feat(net): #13 strict inventory+equipped reader (no GAMEPLAY_OPTIONS)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-10 08:49:10 +02:00
parent 98eebef740
commit d9a5e40203
2 changed files with 88 additions and 0 deletions

View file

@ -401,6 +401,12 @@ public static class PlayerDescriptionParser
if (optionFlags.HasFlag(CharacterOptionDataFlag.CharacterOptions2))
options2 = ReadU32(payload, ref pos);
if (!optionFlags.HasFlag(CharacterOptionDataFlag.GameplayOptions))
{
// Strict path: inventory + equipped follow directly.
TryUnpackInventoryStrict(payload, ref pos, inventory, equipped);
}
}
}
catch (FormatException ex)
@ -711,6 +717,49 @@ public static class PlayerDescriptionParser
bucket);
}
/// <summary>Strict inventory + equipped block reader. Returns true if
/// the bytes from <paramref name="pos"/> parse cleanly per holtburger
/// events.rs:143-193 (<c>unpack_inventory_and_equipped_strict</c>).
/// Counts capped at 10,000; inventory ContainerType must be 0..2
/// (NonContainer / Container / Foci).</summary>
private static bool TryUnpackInventoryStrict(
ReadOnlySpan<byte> src, ref int pos,
List<InventoryEntry> inventory, List<EquippedEntry> equipped)
{
inventory.Clear();
equipped.Clear();
if (pos + 4 > src.Length) return false;
uint invCount = BinaryPrimitives.ReadUInt32LittleEndian(src.Slice(pos));
pos += 4;
if (invCount > 10_000) return false;
for (uint i = 0; i < invCount; i++)
{
if (pos + 8 > src.Length) return false;
uint guid = BinaryPrimitives.ReadUInt32LittleEndian(src.Slice(pos));
uint wtype = BinaryPrimitives.ReadUInt32LittleEndian(src.Slice(pos + 4));
pos += 8;
if (wtype > 2) return false;
inventory.Add(new InventoryEntry(guid, wtype));
}
if (pos + 4 > src.Length) return false;
uint eqCount = BinaryPrimitives.ReadUInt32LittleEndian(src.Slice(pos));
pos += 4;
if (eqCount > 10_000) return false;
for (uint i = 0; i < eqCount; i++)
{
if (pos + 12 > src.Length) return false;
uint guid = BinaryPrimitives.ReadUInt32LittleEndian(src.Slice(pos));
uint loc = BinaryPrimitives.ReadUInt32LittleEndian(src.Slice(pos + 4));
uint prio = BinaryPrimitives.ReadUInt32LittleEndian(src.Slice(pos + 8));
pos += 12;
equipped.Add(new EquippedEntry(guid, loc, prio));
}
return true;
}
private static ushort ReadU16(ReadOnlySpan<byte> src, ref int pos)
{
if (src.Length - pos < 2) throw new FormatException("truncated u16");