Skip to content

Commit ef78e9e

Browse files
erwan-jolyclaude
andauthored
feat: add missing direction-pair packet classes (#452)
Validator flagged headers as "Wrong tag" when they were captured in a direction the library only knew about from the opposite side. Add the missing counterparts so those captures deserialise correctly and give the server a schema to serialise through when it emits them. - ServerPackets.Families.GidxPacket + GidxFamilySubPacket — server emits `gidx 1 <visualId> <serverId>.<familyId> <familyName> <level> <icons>` (or `-1` family-id when the character has none). - ServerPackets.Npcs.NpcReqPacket — mirrors the client packet shape. - ServerPackets.Player.RsfiPacket — mirrors the client packet shape. - ClientPackets.UI.MallPacket — mirrors the server packet shape. - ClientPackets.Player.NpInfoPacket — mirrors the server packet shape. Deserializer dedup keeps "client wins" on duplicate headers, so runtime behaviour for single-deserializer consumers (NosCore's in-game packet handling) is unchanged. The validator uses two separate deserializers so now sees each side's schema in the right dict. Deferred to a follow-up: bpm/bpt server — complex list payloads that need per-field RE work rather than a safe mirror. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7de65f9 commit ef78e9e

8 files changed

Lines changed: 184 additions & 1 deletion

File tree

documentation/DocumentationTest.PacketsDocumentation.verified.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
- [bpt](../src/NosCore.Packets/ClientPackets/Player/BptPacket.cs) *InGame*
168168
- [compl](../src/NosCore.Packets/ClientPackets/Player/ComplPacket.cs) *InGame*
169169
- [eqinfo](../src/NosCore.Packets/ClientPackets/Player/EquipmentInfoPacket.cs) *InGame*
170+
- [npinfo](../src/NosCore.Packets/ClientPackets/Player/NpInfoPacket.cs) *InGame*
170171
- [rsfi](../src/NosCore.Packets/ClientPackets/Player/RsfiPacket.cs) *InGame*
171172
- [snap](../src/NosCore.Packets/ClientPackets/Player/SnapPacket.cs) *InTrade | InGame*
172173
- [tit_eq](../src/NosCore.Packets/ClientPackets/Player/TitEqPacket.cs) *InTrade | InGame*
@@ -205,6 +206,7 @@
205206
### UI
206207
- [gop](../src/NosCore.Packets/ClientPackets/UI/GopPacket.cs) *InGame*
207208
- [guri](../src/NosCore.Packets/ClientPackets/UI/GuriPacket.cs) *InGame*
209+
- [mall](../src/NosCore.Packets/ClientPackets/UI/MallPacket.cs) *InGame*
208210

209211
### Warehouse
210212
- [deposit](../src/NosCore.Packets/ClientPackets/Warehouse/DepositPacket.cs) *InTrade | InGame*
@@ -310,6 +312,7 @@
310312
### Families
311313
- [fc](../src/NosCore.Packets/ServerPackets/Families/FcPacket.cs) *InGame*
312314
- [fslog_stc](../src/NosCore.Packets/ServerPackets/Families/FslogStcPacket.cs) *InGame*
315+
- [gidx](../src/NosCore.Packets/ServerPackets/Families/GidxPacket.cs) *InTrade | InGame*
313316
- [ginfo](../src/NosCore.Packets/ServerPackets/Families/GInfoPacket.cs) *InGame*
314317

315318
### Groups
@@ -383,6 +386,9 @@
383386
### Movement
384387
- [dir](../src/NosCore.Packets/ServerPackets/Movement/DirPacket.cs) *InGame*
385388

389+
### Npcs
390+
- [npc_req](../src/NosCore.Packets/ServerPackets/Npcs/NpcReqPacket.cs) *InGame*
391+
386392
### Parcel
387393
- [parcel](../src/NosCore.Packets/ServerPackets/Parcel/ParcelPacket.cs) *InGame*
388394
- [post](../src/NosCore.Packets/ServerPackets/Parcel/PostPacket.cs) *InGame*
@@ -405,6 +411,7 @@
405411
- [npinfo](../src/NosCore.Packets/ServerPackets/Player/NpInfoPacket.cs) *InGame*
406412
- [p_sex](../src/NosCore.Packets/ServerPackets/Player/PSexPacket.cs) *InGame*
407413
- [rage](../src/NosCore.Packets/ServerPackets/Player/RagePacket.cs) *InGame*
414+
- [rsfi](../src/NosCore.Packets/ServerPackets/Player/RsfiPacket.cs) *InGame*
408415
- [sc](../src/NosCore.Packets/ServerPackets/Player/ScPacket.cs) *InGame*
409416
- [scr](../src/NosCore.Packets/ServerPackets/Player/ScrPacket.cs) *InGame*
410417
- [ski](../src/NosCore.Packets/ServerPackets/Player/SkiPacket.cs) *InGame*
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
using NosCore.Packets.Attributes;
8+
using NosCore.Packets.Enumerations;
9+
10+
namespace NosCore.Packets.ClientPackets.Player
11+
{
12+
/// <summary>
13+
/// Client-side request for the "new player info" page, e.g. <c>npinfo 0</c>.
14+
/// Mirrors the server-side <see cref="NosCore.Packets.ServerPackets.Player.NpInfoPacket"/>.
15+
/// </summary>
16+
[PacketHeader("npinfo", Scope.InGame)]
17+
public class NpInfoPacket : PacketBase
18+
{
19+
[PacketIndex(0)]
20+
public byte Page { get; set; }
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
using NosCore.Packets.Attributes;
8+
using NosCore.Packets.Enumerations;
9+
10+
namespace NosCore.Packets.ClientPackets.UI
11+
{
12+
/// <summary>
13+
/// Client-side request to open the in-game mall UI, e.g. <c>mall 50</c>.
14+
/// Mirrors the server-side <see cref="NosCore.Packets.ServerPackets.UI.MallPacket"/>.
15+
/// </summary>
16+
[PacketHeader("mall", Scope.InGame)]
17+
public class MallPacket : PacketBase
18+
{
19+
[PacketIndex(0)]
20+
public byte State { get; set; }
21+
}
22+
}

src/NosCore.Packets/NosCore.Packets.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<RepositoryUrl>https://github.com/NosCoreIO/NosCore.Packets.git</RepositoryUrl>
1313
<PackageIconUrl></PackageIconUrl>
1414
<PackageTags>nostale, noscore, chickenapi, nostale private server source, nostale emulator</PackageTags>
15-
<Version>17.3.0</Version>
15+
<Version>17.4.0</Version>
1616
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
1717
<Description>NosCore's Packets (Nostale packets) defined over classes</Description>
1818
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
using NosCore.Packets.Attributes;
8+
9+
namespace NosCore.Packets.ServerPackets.Families
10+
{
11+
/// <summary>
12+
/// Server-side family identifier sub-packet used by <see cref="GidxPacket"/>:
13+
/// <c>&lt;serverId&gt;.&lt;familyId&gt;</c>, e.g. <c>103.918</c>.
14+
/// When the character has no family the whole field collapses to <c>-1</c>
15+
/// on the wire, leaving <see cref="FamilyId"/> at its default value.
16+
/// </summary>
17+
public class GidxFamilySubPacket : PacketBase
18+
{
19+
[PacketIndex(0)]
20+
public int ServerId { get; set; }
21+
22+
[PacketIndex(1)]
23+
public long FamilyId { get; set; }
24+
}
25+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
using System.Collections.Generic;
8+
using NosCore.Packets.Attributes;
9+
using NosCore.Packets.Enumerations;
10+
using NosCore.Shared.Enumerations;
11+
12+
namespace NosCore.Packets.ServerPackets.Families
13+
{
14+
/// <summary>
15+
/// Server-side family indicator packet, observed as e.g.
16+
/// <c>gidx 1 5739 103.918 LastDemons 9 0|0|0</c> or
17+
/// <c>gidx 1 14293841 -1 - 0 0|0|0</c> when there is no family.
18+
/// </summary>
19+
[PacketHeader("gidx", Scope.InGame | Scope.InTrade)]
20+
public class GidxPacket : PacketBase
21+
{
22+
[PacketIndex(0)]
23+
public VisualType VisualType { get; set; }
24+
25+
[PacketIndex(1)]
26+
public long VisualId { get; set; }
27+
28+
[PacketIndex(2, SpecialSeparator = ".")]
29+
public GidxFamilySubPacket? FamilyIdentifier { get; set; }
30+
31+
[PacketIndex(3)]
32+
public string? FamilyName { get; set; }
33+
34+
[PacketIndex(4)]
35+
public byte FamilyLevel { get; set; }
36+
37+
[PacketListIndex(5, ListSeparator = "|")]
38+
public List<bool> FamilyIcons { get; set; } = new();
39+
}
40+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
using NosCore.Packets.Attributes;
8+
using NosCore.Packets.Enumerations;
9+
using NosCore.Shared.Enumerations;
10+
11+
namespace NosCore.Packets.ServerPackets.Npcs
12+
{
13+
/// <summary>
14+
/// Server-side NPC request packet, observed as e.g. <c>npc_req 2 5140 16</c>.
15+
/// Mirrors the client-side <see cref="NosCore.Packets.ClientPackets.Npcs.RequestNpcPacket"/>.
16+
/// </summary>
17+
[PacketHeader("npc_req", Scope.InGame)]
18+
public class NpcReqPacket : PacketBase
19+
{
20+
[PacketIndex(0)]
21+
public VisualType Type { get; set; }
22+
23+
[PacketIndex(1)]
24+
public long TargetId { get; set; }
25+
26+
[PacketIndex(2)]
27+
public long? Data { get; set; }
28+
}
29+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
using NosCore.Packets.Attributes;
8+
using NosCore.Packets.Enumerations;
9+
10+
namespace NosCore.Packets.ServerPackets.Player
11+
{
12+
/// <summary>
13+
/// Server-side timespace progression packet, observed as e.g.
14+
/// <c>rsfi 3 3 0 1 0 1</c>. Mirrors the client-side
15+
/// <see cref="NosCore.Packets.ClientPackets.Player.RsfiPacket"/>.
16+
/// </summary>
17+
[PacketHeader("rsfi", Scope.InGame)]
18+
public class RsfiPacket : PacketBase
19+
{
20+
[PacketIndex(0)]
21+
public byte Act { get; set; }
22+
23+
[PacketIndex(1)]
24+
public byte ActPart { get; set; }
25+
26+
[PacketIndex(2)]
27+
public byte Unknown1 { get; set; }
28+
29+
[PacketIndex(3)]
30+
public byte Unknown2 { get; set; }
31+
32+
[PacketIndex(4)]
33+
public byte Ts { get; set; }
34+
35+
[PacketIndex(5)]
36+
public byte TsMax { get; set; }
37+
}
38+
}

0 commit comments

Comments
 (0)