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:
parent
98eebef740
commit
d9a5e40203
2 changed files with 88 additions and 0 deletions
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue