~ruther/NosSmooth

c4efc653bada65fb7ac81baadc33004dd4898842 — František Boháček 3 years ago 342f05b
feat: add in packet with all dependencies
A Core/NosSmooth.Packets/Converters/Packets/UpgradeRareSubPacketConverter.cs => Core/NosSmooth.Packets/Converters/Packets/UpgradeRareSubPacketConverter.cs +60 -0
@@ 0,0 1,60 @@
//
//  UpgradeRareSubPacketConverter.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Packets.Errors;
using NosSmooth.Packets.Packets.Server.Weapons;
using Remora.Results;

namespace NosSmooth.Packets.Converters.Packets;

/// <summary>
/// Converter for <see cref="UpgradeRareSubPacket"/>.
/// </summary>
public class UpgradeRareSubPacketConverter : BaseTypeConverter<UpgradeRareSubPacket>
{
    /// <inheritdoc />
    public override Result Serialize(UpgradeRareSubPacket? obj, PacketStringBuilder builder)
    {
        if (obj is null)
        {
            builder.Append("-");
            return Result.FromSuccess();
        }
        builder.Append($"{obj.Upgrade}{obj.Rare}");
        return Result.FromSuccess();
    }

    /// <inheritdoc />
    public override Result<UpgradeRareSubPacket?> Deserialize(PacketStringEnumerator stringEnumerator)
    {
        var tokenResult = stringEnumerator.GetNextToken();
        if (!tokenResult.IsSuccess)
        {
            return Result<UpgradeRareSubPacket?>.FromError(tokenResult);
        }

        var token = tokenResult.Entity.Token;
        if (token.Length != 2)
        {
            return new CouldNotConvertError(this, token, "The string is not two characters long.");
        }

        var upgradeString = token[0].ToString();
        var rareString = token[1].ToString();

        if (!byte.TryParse(upgradeString, out var upgrade))
        {
            return new CouldNotConvertError(this, upgradeString, "Could not parse as byte");
        }

        if (!sbyte.TryParse(rareString, out var rare))
        {
            return new CouldNotConvertError(this, rareString, "Could not parse as byte");
        }

        return new UpgradeRareSubPacket(upgrade, rare);
    }
}
\ No newline at end of file

A Core/NosSmooth.Packets/Enums/Element.cs => Core/NosSmooth.Packets/Enums/Element.cs +38 -0
@@ 0,0 1,38 @@
//
//  Element.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace NosSmooth.Packets.Enums;

/// <summary>
/// Element type.
/// </summary>
public enum Element
{
    /// <summary>
    /// No element type.
    /// </summary>
    Neutral,

    /// <summary>
    /// Fire element.
    /// </summary>
    Fire,

    /// <summary>
    /// Water element.
    /// </summary>
    Water,

    /// <summary>
    /// Light element.
    /// </summary>
    Light,

    /// <summary>
    /// Dark element.
    /// </summary>
    Dark
}
\ No newline at end of file

A Core/NosSmooth.Packets/Enums/Entities/EntityType.cs => Core/NosSmooth.Packets/Enums/Entities/EntityType.cs +38 -0
@@ 0,0 1,38 @@
//
//  EntityType.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace NosSmooth.Packets.Enums;

/// <summary>
/// Type of the entity.
/// </summary>
public enum EntityType
{
    /// <summary>
    /// Unknown.
    /// </summary>
    Map = 0,

    /// <summary>
    /// The entity is a player.
    /// </summary>
    Player = 1,

    /// <summary>
    /// The entity is an npc. (can be pets and partners as well).
    /// </summary>
    Npc = 2,

    /// <summary>
    /// The entity is a monster.
    /// </summary>
    Monster = 3,

    /// <summary>
    /// The entity is an object, ie. gold or dropped item.
    /// </summary>
    Object = 9
}
\ No newline at end of file

R Core/NosSmooth.Packets/Enums/FactionType.cs => Core/NosSmooth.Packets/Enums/Entities/FactionType.cs +0 -0
A Core/NosSmooth.Packets/Enums/Entities/SpawnEffect.cs => Core/NosSmooth.Packets/Enums/Entities/SpawnEffect.cs +28 -0
@@ 0,0 1,28 @@
//
//  SpawnEffect.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace NosSmooth.Packets.Enums.Entities;

/// <summary>
/// Effect that is shown on the entity spawning.
/// </summary>
public enum SpawnEffect
{
    /// <summary>
    /// Unknown.
    /// </summary>
    Summon = 0,

    /// <summary>
    /// Unknown.
    /// </summary>
    NoEffect = 1,

    /// <summary>
    /// Unknown.
    /// </summary>
    FallingFromSky = 2
}
\ No newline at end of file

A Core/NosSmooth.Packets/Enums/Players/AuthorityType.cs => Core/NosSmooth.Packets/Enums/Players/AuthorityType.cs +47 -0
@@ 0,0 1,47 @@
//
//  AuthorityType.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace NosSmooth.Packets.Enums;

/// <summary>
/// Authority of a player.
/// </summary>
public enum AuthorityType
{
    /// <summary>
    /// The player is a regular user.
    /// </summary>
    User = 0,

    /// <summary>
    /// The player is a moderator.
    /// </summary>
    Moderator = 1,

    /// <summary>
    /// The player is a game master.
    /// </summary>
    /// <remarks>
    /// Has GM in front of the name.
    /// </remarks>
    GameMaster = 2,

    /// <summary>
    /// The player is an administrator.
    /// </summary>
    /// <remarks>
    /// Has GM in front of the name.
    /// </remarks>
    Administrator = 3,

    /// <summary>
    /// The player is a root.
    /// </summary>
    /// <remarks>
    /// Has GM in front of the name.
    /// </remarks>
    Root = 4
}
\ No newline at end of file

A Core/NosSmooth.Packets/Enums/Players/HairColor.cs => Core/NosSmooth.Packets/Enums/Players/HairColor.cs +145 -0
@@ 0,0 1,145 @@
//
//  HairColor.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

#pragma warning disable CS1591
namespace NosSmooth.Packets.Enums.Players;
#pragma warning disable SA1602

/// <summary>
/// Hair color of a player.
/// </summary>
public enum HairColor
{
    DarkPurple = 0,
    Yellow = 1,
    Blue = 2,
    Purple = 3,
    Orange = 4,
    Brown = 5,
    Green = 6,
    DarkGrey = 7,
    LightBlue = 8,
    PinkRed = 9,
    LightYellow = 10,
    LightPink = 11,
    LightGreen = 12,
    LightGrey = 13,
    SkyBlue = 14,
    Black = 15,
    DarkOrange = 16,
    DarkOrangeVariant2 = 17,
    DarkOrangeVariant3 = 18,
    DarkOrangeVariant4 = 19,
    DarkOrangeVariant5 = 20,
    DarkOrangeVariant6 = 21,
    LightOrange = 22,
    LightLightOrange = 23,
    LightLightLightOrange = 24,
    LightLightLightLightOrange = 25,
    SuperLightOrange = 26,
    DarkYellow = 27,
    LightLightYellow = 28,
    KakiYellow = 29,
    SuperLightYellow = 30,
    SuperLightYellow2 = 31,
    SuperLightYellow3 = 32,
    LittleDarkYellow = 33,
    YellowVariant = 34,
    YellowVariant1 = 35,
    YellowVariant2 = 36,
    YellowVariant3 = 37,
    YellowVariant4 = 38,
    YellowVariant5 = 39,
    YellowVariant6 = 40,
    YellowVariant7 = 41,
    YellowVariant8 = 42,
    YellowVariant9 = 43,
    GreenVariant = 44,
    GreenVariant1 = 45,
    DarkGreenVariant = 46,
    GreenMoreDarkVariant = 47,
    GreenVariant2 = 48,
    GreenVariant3 = 49,
    GreenVariant4 = 50,
    GreenVariant5 = 51,
    GreenVariant6 = 52,
    GreenVariant7 = 53,
    GreenVariant8 = 54,
    GreenVariant9 = 55,
    GreenVariant10 = 56,
    GreenVariant11 = 57,
    GreenVariant12 = 58,
    GreenVariant13 = 59,
    GreenVariant14 = 60,
    GreenVariant15 = 61,
    GreenVariant16 = 62,
    GreenVariant17 = 63,
    GreenVariant18 = 64,
    GreenVariant19 = 65,
    GreenVariant20 = 66,
    LightBlueVariant1 = 67,
    LightBlueVariant2 = 68,
    LightBlueVariant3 = 69,
    LightBlueVariant4 = 70,
    LightBlueVariant5 = 71,
    LightBlueVariant6 = 72,
    LightBlueVariant7 = 73,
    LightBlueVariant8 = 74,
    LightBlueVariant9 = 75,
    LightBlueVariant10 = 76,
    LightBlueVariant11 = 77,
    LightBlueVariant12 = 78,
    LightBlueVariant13 = 79,
    DarkBlack = 80,
    LightBlueVariant14 = 81,
    LightBlueVariant15 = 82,
    LightBlueVariant16 = 83,
    LightBlueVariant17 = 84,
    BlueVariant = 85,
    BlueVariantDark = 86,
    BlueVariantDarkDark = 87,
    BlueVariantDarkDark2 = 88,
    FlashBlue = 89,
    FlashBlueDark = 90,
    FlashBlueDark2 = 91,
    FlashBlueDark3 = 92,
    FlashBlueDark4 = 93,
    FlashBlueDark5 = 94,
    FlashBlueDark6 = 95,
    FlashBlueDark7 = 96,
    FlashBlueDark8 = 97,
    FlashBlueDark9 = 98,
    White = 99,
    FlashBlueDark10 = 100,
    FlashBlue1 = 101,
    FlashBlue2 = 102,
    FlashBlue3 = 103,
    FlashBlue4 = 104,
    FlashBlue5 = 105,
    FlashPurple = 106,
    FlashLightPurple = 107,
    FlashLightPurple2 = 108,
    FlashLightPurple3 = 109,
    FlashLightPurple4 = 110,
    FlashLightPurple5 = 111,
    LightPurple = 112,
    PurpleVariant1 = 113,
    PurpleVariant2 = 114,
    PurpleVariant3 = 115,
    PurpleVariant4 = 116,
    PurpleVariant5 = 117,
    PurpleVariant6 = 118,
    PurpleVariant7 = 119,
    PurpleVariant8 = 120,
    PurpleVariant9 = 121,
    PurpleVariant10 = 122,
    PurpleVariant11 = 123,
    PurpleVariant12 = 124,
    PurpleVariant13 = 125,
    PurpleVariant14 = 126,
    PurpleVariant15 = 127
}
#pragma warning restore SA1602
\ No newline at end of file

A Core/NosSmooth.Packets/Enums/Players/HairStyle.cs => Core/NosSmooth.Packets/Enums/Players/HairStyle.cs +38 -0
@@ 0,0 1,38 @@
//
//  HairStyle.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace NosSmooth.Packets.Enums.Players;

/// <summary>
/// Hair style of a player.
/// </summary>
public enum HairStyle
{
    /// <summary>
    /// Unknown TODO.
    /// </summary>
    HairStyleA = 0,

    /// <summary>
    /// Unknown TODO.
    /// </summary>
    HairStyleB = 1,

    /// <summary>
    /// Unknown TODO.
    /// </summary>
    HairStyleC = 2,

    /// <summary>
    /// Unknown TODO.
    /// </summary>
    HairStyleD = 3,

    /// <summary>
    /// The player has no hair.
    /// </summary>
    NoHair = 4
}
\ No newline at end of file

A Core/NosSmooth.Packets/Enums/Players/PlayerClass.cs => Core/NosSmooth.Packets/Enums/Players/PlayerClass.cs +57 -0
@@ 0,0 1,57 @@
//
//  PlayerClass.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace NosSmooth.Packets.Enums.Players;

/// <summary>
/// The class of the player.
/// </summary>
public enum PlayerClass
{
    /// <summary>
    /// Adventurer class.
    /// </summary>
    /// <remarks>
    /// After creating a character, this is the first class.
    /// The player can change the class at level 15, job level 20.
    /// </remarks>
    Adventurer = 0,

    /// <summary>
    /// Swordsman class.
    /// </summary>
    /// <remarks>
    /// Primary weapon is a sword, secondary weapon is a crossbow.
    /// </remarks>
    Swordsman = 1,

    /// <summary>
    /// Archer class.
    /// </summary>
    /// <remarks>
    /// Primary weapon is a bow,
    /// secondary weapon is a dagger.
    /// </remarks>
    Archer = 2,

    /// <summary>
    /// Mage class.
    /// </summary>
    /// <remarks>
    /// Primary weapon is a wand,
    /// secondary weapon is magical gun.
    /// </remarks>
    Mage = 3,

    /// <summary>
    /// Martial artist class.
    /// </summary>
    /// <remarks>
    /// Can be created after reaching level 80 on any of the characters.
    /// Then character with that class can be created on the same account.
    /// </remarks>
    MartialArtist = 4
}
\ No newline at end of file

A Core/NosSmooth.Packets/Enums/Players/SexType.cs => Core/NosSmooth.Packets/Enums/Players/SexType.cs +23 -0
@@ 0,0 1,23 @@
//
//  SexType.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace NosSmooth.Packets.Enums.Players;

/// <summary>
/// The sex of a player.
/// </summary>
public enum SexType
{
    /// <summary>
    /// The character is male..
    /// </summary>
    Male = 0,

    /// <summary>
    /// The character is female.
    /// </summary>
    Female = 1
}
\ No newline at end of file

A Core/NosSmooth.Packets/Packets/Server/Entities/InEquipmentSubPacket.cs => Core/NosSmooth.Packets/Packets/Server/Entities/InEquipmentSubPacket.cs +49 -0
@@ 0,0 1,49 @@
//
//  InEquipmentSubPacket.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Packets.Attributes;

namespace NosSmooth.Packets.Packets.Server.Entities;

/// <summary>
/// Sub packet of <see cref="InPacket"/> present if the in packet
/// is for a player. Contains information about the player's
/// weapon.
/// /// </summary>
/// <param name="HatVNum">The VNum of the hat.</param>
/// <param name="ArmorVNum">The VNum of the armor.</param>
/// <param name="MainWeaponVNum">The VNum of the main weapon.</param>
/// <param name="SecondaryWeaponVNum">The VNum of the secondary weapon.</param>
/// <param name="MaskVNum">The VNum of the mask.</param>
/// <param name="Fairy">Unknown TODO.</param>
/// <param name="CostumeSuitVNum">The VNum of the costume suit.</param>
/// <param name="CostumeHatVNum">The VNum of the costume hat.</param>
/// <param name="WeaponSkin">The skin of the weapon.</param>
/// <param name="WingSkin">The skin of the wings.</param>
[GenerateSerializer]
public record InEquipmentSubPacket
(
    [PacketIndex(0)]
    long HatVNum,
    [PacketIndex(1)]
    long ArmorVNum,
    [PacketIndex(2)]
    long MainWeaponVNum,
    [PacketIndex(3)]
    long SecondaryWeaponVNum,
    [PacketIndex(4)]
    long MaskVNum,
    [PacketIndex(5)]
    long Fairy,
    [PacketIndex(6)]
    long CostumeSuitVNum,
    [PacketIndex(7)]
    long CostumeHatVNum,
    [PacketIndex(8)]
    short WeaponSkin,
    [PacketIndex(9)]
    short WingSkin
) : IPacket;
\ No newline at end of file

A Core/NosSmooth.Packets/Packets/Server/Entities/InItemSubPacket.cs => Core/NosSmooth.Packets/Packets/Server/Entities/InItemSubPacket.cs +28 -0
@@ 0,0 1,28 @@
//
//  InItemSubPacket.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Packets.Attributes;

namespace NosSmooth.Packets.Packets.Server.Entities;

/// <summary>
/// Sub packet of <see cref="InPacket"/> present if the in packet
/// is for an object.
/// </summary>
/// <param name="Amount">The amount of the gold or drop etc.</param>
/// <param name="IsQuestRelative">Whether the item is needed for a quest.</param>
/// <param name="OwnerId">The id of the owner of the item.</param>
[PacketHeader(null, PacketSource.Server)]
[GenerateSerializer]
public record InItemSubPacket
(
    [PacketIndex(0)]
    long Amount,
    [PacketIndex(1)]
    bool IsQuestRelative,
    [PacketIndex(2)]
    long OwnerId
) : IPacket;
\ No newline at end of file

A Core/NosSmooth.Packets/Packets/Server/Entities/InNonPlayerSubPacket.cs => Core/NosSmooth.Packets/Packets/Server/Entities/InNonPlayerSubPacket.cs +88 -0
@@ 0,0 1,88 @@
//
//  InNonPlayerSubPacket.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Packets.Attributes;
using NosSmooth.Packets.Common;
using NosSmooth.Packets.Enums;
using NosSmooth.Packets.Enums.Entities;

namespace NosSmooth.Packets.Packets.Server.Entities;

/// <summary>
/// Sub packet of <see cref="InPacket"/> present if the in packet
/// is for a monster or npc.
/// </summary>
/// <param name="HpPercentage">The hp percentage of the entity.</param>
/// <param name="MpPercentage">The mp percentage of the entity.</param>
/// <param name="Dialog">Unknown TODO</param>
/// <param name="Faction">The faction of the entity.</param>
/// <param name="GroupEffect">Unknown TODO</param>
/// <param name="OwnerId">The id of the owner entity.</param>
/// <param name="SpawnEffect">The effect the entity does on spawning.</param>
/// <param name="IsSitting">Whether the entity is sitting.</param>
/// <param name="Morph">The id of the morph (for special cards an such).</param>
/// <param name="Name">The name of the entity, if any.</param>
/// <param name="Unknown">Unknown.</param>
/// <param name="Unknown2">Unknown.</param>
/// <param name="Unknown3">Unknown.</param>
/// <param name="Skill1">The first skill VNum of the entity.</param>
/// <param name="Skill2">The second skill VNum of the entity.</param>
/// <param name="Skill3">The third skill VNum of the entity.</param>
/// <param name="SkillRank1">The rank of the first skill.</param>
/// <param name="SkillRank2">The rank of the second skill.</param>
/// <param name="SkillRank3">The rank of the third skill.</param>
/// <param name="IsInvisible">Whether the entity is invisible.</param>
/// <param name="Unknown4">Unknown.</param>
/// <param name="Unknown5">Unknown.</param>
[PacketHeader(null, PacketSource.Server)]
[GenerateSerializer]
public record InNonPlayerSubPacket
(
    [PacketIndex(0)]
    byte HpPercentage,
    [PacketIndex(1)]
    byte MpPercentage,
    [PacketIndex(2)]
    short Dialog,
    [PacketIndex(3)]
    FactionType Faction,
    [PacketIndex(4)]
    short GroupEffect,
    [PacketIndex(5)]
    long OwnerId,
    [PacketIndex(6)]
    SpawnEffect SpawnEffect,
    [PacketIndex(7)]
    bool IsSitting,
    [PacketIndex(8)]
    long Morph,
    [PacketIndex(9)]
    NameString? Name,
    [PacketIndex(10)]
    string? Unknown,
    [PacketIndex(11)]
    string? Unknown2,
    [PacketIndex(12)]
    string? Unknown3,
    [PacketIndex(13)]
    short Skill1,
    [PacketIndex(14)]
    short Skill2,
    [PacketIndex(15)]
    short Skill3,
    [PacketIndex(16)]
    short SkillRank1,
    [PacketIndex(17)]
    short SkillRank2,
    [PacketIndex(18)]
    short SkillRank3,
    [PacketIndex(19)]
    bool IsInvisible,
    [PacketIndex(20)]
    string? Unknown4,
    [PacketIndex(21)]
    string? Unknown5
) : IPacket;
\ No newline at end of file

A Core/NosSmooth.Packets/Packets/Server/Entities/InPacket.cs => Core/NosSmooth.Packets/Packets/Server/Entities/InPacket.cs +53 -0
@@ 0,0 1,53 @@
//
//  InPacket.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Packets.Attributes;
using NosSmooth.Packets.Common;
using NosSmooth.Packets.Enums;

namespace NosSmooth.Packets.Packets.Server.Entities;

/// <summary>
/// There is a new entity on the map present.
/// </summary>
/// <param name="EntityType">The type of the entity.</param>
/// <param name="Name">The name of the entity, present only for players.</param>
/// <param name="VNum">The vnum of the entity, present only for non players.</param>
/// <param name="Unknown">Unknown value present only for players. It's always "-".</param>
/// <param name="EntityId">The id of the entity.</param>
/// <param name="PositionX">The x coordinate the entity is at.</param>
/// <param name="PositionY">The y coordinate the entity is at.</param>
/// <param name="Direction">The direction the entity is looking, present only for non-objects.</param>
/// <param name="PlayerSubPacket">The player data sub packet present only for players.</param>
/// <param name="ItemSubPacket">The item data sub packet present only for objects.</param>
/// <param name="NonPlayerSubPacket">The non player data sub packet present only for npcs and monsters.</param>
[PacketHeader("in", PacketSource.Server)]
[GenerateSerializer]
public record InPacket
(
    [PacketIndex(0)]
    EntityType EntityType,
    [PacketConditionalIndex(1, "EntityType", false,  EntityType.Player)]
    NameString? Name,
    [PacketConditionalIndex(2, "EntityType", true, EntityType.Player)]
    long? VNum,
    [PacketConditionalIndex(3, "EntityType", false, EntityType.Player)]
    string? Unknown,
    [PacketIndex(4)]
    long EntityId,
    [PacketIndex(5)]
    short PositionX,
    [PacketIndex(6)]
    short PositionY,
    [PacketConditionalIndex(7, "EntityType", true, EntityType.Object)]
    byte Direction,
    [PacketConditionalIndex(8, "EntityType", false, EntityType.Player, InnerSeparator = ' ')]
    InPlayerSubPacket? PlayerSubPacket,
    [PacketConditionalIndex(9, "EntityType", false, EntityType.Object, InnerSeparator = ' ')]
    InItemSubPacket? ItemSubPacket,
    [PacketConditionalIndex(10, "EntityType", true, EntityType.Player, EntityType.Object, InnerSeparator = ' ')]
    InNonPlayerSubPacket? NonPlayerSubPacket
) : IPacket;
\ No newline at end of file

A Core/NosSmooth.Packets/Packets/Server/Entities/InPlayerSubPacket.cs => Core/NosSmooth.Packets/Packets/Server/Entities/InPlayerSubPacket.cs +84 -0
@@ 0,0 1,84 @@
//
//  InPlayerSubPacket.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using NosSmooth.Packets.Attributes;
using NosSmooth.Packets.Enums;
using NosSmooth.Packets.Enums.Players;
using NosSmooth.Packets.Packets.Server.Players;
using NosSmooth.Packets.Packets.Server.Weapons;

namespace NosSmooth.Packets.Packets.Server.Entities;

[PacketHeader(null, PacketSource.Server)]
[GenerateSerializer]
public record InPlayerSubPacket
(
    [PacketIndex(0)]
    AuthorityType Authority,
    [PacketIndex(1)]
    SexType Sex,
    [PacketIndex(2)]
    HairStyle HairStyle,
    [PacketIndex(3)]
    HairColor HairColor,
    [PacketIndex(4)]
    PlayerClass Class,
    [PacketIndex(5, InnerSeparator = '.')]
    InEquipmentSubPacket Equipment,
    [PacketIndex(6)]
    short HpPercentage,
    [PacketIndex(7)]
    short MpPercentage,
    [PacketIndex(8)]
    bool IsSitting,
    [PacketIndex(9)]
    long? GroupId,
    [PacketIndex(10)]
    short Fairy,
    [PacketIndex(11)]
    Element FairyElement,
    [PacketIndex(12)]
    byte Unknown,
    [PacketIndex(13)]
    long Morph,
    [PacketIndex(14)]
    byte Unknown2,
    [PacketIndex(15)]
    byte Unknown3,
    [PacketIndex(16)]
    UpgradeRareSubPacket WeaponUpgradeRareSubPacket,
    [PacketIndex(17)]
    UpgradeRareSubPacket ArmorUpgradeRareSubPacket,
    [PacketIndex(18)]
    FamilySubPacket FamilySubPacket,
    [PacketIndex(19)]
    string ReputationIcon,
    [PacketIndex(20)]
    bool IsInvisible,
    [PacketIndex(21)]
    byte MorphUpgrade,
    [PacketIndex(22)]
    FactionType Faction,
    [PacketIndex(23)]
    byte MorphUpgrade2,
    [PacketIndex(24)]
    byte Level,
    [PacketIndex(25)]
    byte FamilyLevel,
    [PacketListIndex(26, ListSeparator = '|')]
    IReadOnlyList<bool> FamilyIcons,
    [PacketIndex(27)]
    bool ArenaWinner,
    [PacketIndex(28)]
    short Compliment,
    [PacketIndex(29)]
    byte Size,
    [PacketIndex(30)]
    byte HeroLevel,
    [PacketIndex(31)]
    short Title
) : IPacket;
\ No newline at end of file

M Core/NosSmooth.Packets/Packets/Server/Entities/MovePacket.cs => Core/NosSmooth.Packets/Packets/Server/Entities/MovePacket.cs +2 -2
@@ 4,8 4,8 @@
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosCore.Shared.Enumerations;
using NosSmooth.Packets.Attributes;
using NosSmooth.Packets.Enums;

namespace NosSmooth.Packets.Packets.Server.Entities;



@@ 22,7 22,7 @@ namespace NosSmooth.Packets.Packets.Server.Entities;
public record MovePacket
(
    [PacketIndex(0)]
    VisualType EntityType,
    EntityType EntityType,
    [PacketIndex(1)]
    long EntityId,
    [PacketIndex(2)]

M Core/NosSmooth.Packets/Packets/Server/Groups/PinitPacket.cs => Core/NosSmooth.Packets/Packets/Server/Groups/PinitPacket.cs +2 -2
@@ 15,8 15,8 @@ namespace NosSmooth.Packets.Packets.Server.Groups;
/// <remarks>
/// Contains pet and group information.
/// </remarks>
/// <param name="GroupSize"></param>
/// <param name="PinitSubPackets"></param>
/// <param name="GroupSize">The size of the group.</param>
/// <param name="PinitSubPackets">The members of the group. (including pet and partner, if any)</param>
[GenerateSerializer]
[PacketHeader("pinit", PacketSource.Server)]
public record PinitPacket

M Core/NosSmooth.Packets/Packets/Server/Groups/PinitSubPacket.cs => Core/NosSmooth.Packets/Packets/Server/Groups/PinitSubPacket.cs +5 -5
@@ 4,9 4,9 @@
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosCore.Shared.Enumerations;
using NosSmooth.Packets.Attributes;
using NosSmooth.Packets.Common;
using NosSmooth.Packets.Enums;

namespace NosSmooth.Packets.Packets.Server.Groups;



@@ 29,7 29,7 @@ namespace NosSmooth.Packets.Packets.Server.Groups;
public record PinitSubPacket
(
    [PacketIndex(0)]
    VisualType EntityType,
    EntityType EntityType,
    [PacketIndex(1)]
    long EntityId,
    [PacketIndex(2)]


@@ 46,10 46,10 @@ public record PinitSubPacket
    short Race,
    [PacketIndex(8)]
    short Morph,
    [PacketConditionalIndex(9, "EntityType", false, VisualType.Player)]
    [PacketConditionalIndex(9, "EntityType", false, EntityType.Player)]
    byte? HeroLevel,
    [PacketConditionalIndex(10, "EntityType", false, VisualType.Player)]
    [PacketConditionalIndex(10, "EntityType", false, EntityType.Player)]
    int? Unknown1,
    [PacketConditionalIndex(11, "EntityType", false, VisualType.Player)]
    [PacketConditionalIndex(11, "EntityType", false, EntityType.Player)]
    int? Unknown2
) : IPacket;
\ No newline at end of file

A Core/NosSmooth.Packets/Packets/Server/Players/FamilySubPacket.cs => Core/NosSmooth.Packets/Packets/Server/Players/FamilySubPacket.cs +26 -0
@@ 0,0 1,26 @@
//
//  FamilySubPacket.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Packets.Attributes;

namespace NosSmooth.Packets.Packets.Server.Players;

/// <summary>
/// Sub packet with family information.
/// </summary>
/// <param name="FamilyId">The id of the family.</param>
/// <param name="Title">The title of the family.</param>
/// <param name="FamilyName">The name of the family.</param>
[GenerateSerializer]
public record FamilySubPacket
(
    [PacketIndex(0, AfterSeparator = '.')]
    string FamilyId,
    [PacketIndex(1)]
    short Title,
    [PacketIndex(2)]
    string FamilyName
) : IPacket;
\ No newline at end of file

A Core/NosSmooth.Packets/Packets/Server/Weapons/UpgradeRareSubPacket.cs => Core/NosSmooth.Packets/Packets/Server/Weapons/UpgradeRareSubPacket.cs +21 -0
@@ 0,0 1,21 @@
//
//  UpgradeRareSubPacket.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Packets.Attributes;

namespace NosSmooth.Packets.Packets.Server.Weapons;

/// <summary>
/// Upgrade and rare of a weapon or an armor.
/// </summary>
/// <param name="Upgrade">The upgrade of the weapon.</param>
/// <param name="Rare">The rare .</param>
[PacketHeader(null, PacketSource.Server)]
public record UpgradeRareSubPacket
(
    byte Upgrade,
    sbyte Rare
) : IPacket;
\ No newline at end of file

M Tests/NosSmooth.Packets.Tests/Converters/Packets/MovePacketConverterTests.cs => Tests/NosSmooth.Packets.Tests/Converters/Packets/MovePacketConverterTests.cs +3 -3
@@ 5,9 5,9 @@
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Extensions.DependencyInjection;
using NosCore.Shared.Enumerations;
using NosSmooth.Packets.Attributes;
using NosSmooth.Packets.Converters;
using NosSmooth.Packets.Enums;
using NosSmooth.Packets.Extensions;
using NosSmooth.Packets.Packets.Server.Entities;
using Xunit;


@@ 40,7 40,7 @@ public class MovePacketConverterTests
    [Fact]
    public void Converter_Serialization_SerializesCorrectly()
    {
        MovePacket packet = new MovePacket(VisualType.Monster, 122, 15, 20, 10);
        MovePacket packet = new MovePacket(EntityType.Monster, 122, 15, 20, 10);
        var result = _packetSerializer.Serialize(packet);
        Assert.True(result.IsSuccess);



@@ 57,7 57,7 @@ public class MovePacketConverterTests
        var result = _packetSerializer.Deserialize(packetString, PacketSource.Server);
        Assert.True(result.IsSuccess);

        MovePacket actualPacket = new MovePacket(VisualType.Monster, 122, 15, 20, 10);
        MovePacket actualPacket = new MovePacket(EntityType.Monster, 122, 15, 20, 10);
        Assert.Equal(result.Entity, actualPacket);
    }
}
\ No newline at end of file

M Tests/NosSmooth.Packets.Tests/Converters/Packets/PinitPacketConverterTest.cs => Tests/NosSmooth.Packets.Tests/Converters/Packets/PinitPacketConverterTest.cs +5 -6
@@ 4,11 4,10 @@
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using NosCore.Shared.Enumerations;
using NosSmooth.Packets.Attributes;
using NosSmooth.Packets.Converters;
using NosSmooth.Packets.Enums;
using NosSmooth.Packets.Extensions;
using NosSmooth.Packets.Packets.Server.Groups;
using Xunit;


@@ 43,8 42,8 @@ public class PinitPacketConverterTest
    {
        var packet = new PinitPacket(2, new[]
        {
            new PinitSubPacket(VisualType.Npc, 345377, 0, 83, "Kliff", -1, 319, 1, 0, null, null, null),
            new PinitSubPacket(VisualType.Npc, 345384, 1, 83, "@", -1, 2105, 0, 0, null, null, null)
            new PinitSubPacket(EntityType.Npc, 345377, 0, 83, "Kliff", -1, 319, 1, 0, null, null, null),
            new PinitSubPacket(EntityType.Npc, 345384, 1, 83, "@", -1, 2105, 0, 0, null, null, null)
        });
        var result = _packetSerializer.Serialize(packet);
        Assert.True(result.IsSuccess);


@@ 66,7 65,7 @@ public class PinitPacketConverterTest

        Assert.Equal(2, actualPacket.GroupSize);
        Assert.Equal(2, actualPacket.PinitSubPackets.Count);
        Assert.StrictEqual(new PinitSubPacket(VisualType.Npc, 345377, 0, 83, "Kliff", -1, 319, 1, 0, null, null, null), actualPacket.PinitSubPackets[0]);
        Assert.StrictEqual(new PinitSubPacket(VisualType.Npc, 345384, 1, 83, "@", -1, 2105, 0, 0, null, null, null), actualPacket.PinitSubPackets[1]);
        Assert.StrictEqual(new PinitSubPacket(EntityType.Npc, 345377, 0, 83, "Kliff", -1, 319, 1, 0, null, null, null), actualPacket.PinitSubPackets[0]);
        Assert.StrictEqual(new PinitSubPacket(EntityType.Npc, 345384, 1, 83, "@", -1, 2105, 0, 0, null, null, null), actualPacket.PinitSubPackets[1]);
    }
}
\ No newline at end of file