feat(net): #13 read OptionFlags + Options1 after enchantments

First step of the PD trailer walk. Wraps trailer reads in their own
try/catch so a malformed trailer does not null out the upstream
attribute/skill/spell/enchantment data we already extracted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-10 08:18:38 +02:00
parent 65870349a8
commit becbde60a4
2 changed files with 59 additions and 14 deletions

View file

@ -309,26 +309,42 @@ public static class PlayerDescriptionParser
ReadSpellTable(payload, ref pos, spells);
// ── Enchantments (Issue #7 / #12) ───────────────────────────────
// Outer EnchantmentMask + per-bucket count + N×Enchantment(60-64 B).
// Holtburger events.rs:462-501. After this block come options /
// shortcuts / hotbars / inventory / equipped — those need a
// heuristic walker for the variable-length gameplay_options blob.
// Filed as ISSUES.md #13 for follow-up; stop here cleanly so
// partial parses still populate enchantments.
if (vectorFlags.HasFlag(DescriptionVectorFlag.Enchantment))
ReadEnchantmentBlock(payload, ref pos, enchantments);
// ── Trailer (Issue #13): options + shortcuts + hotbars + inventory ──
// Wrapped in its own try/catch — a malformed trailer must not destroy
// the attribute / skill / spell / enchantment data we already extracted.
CharacterOptionDataFlag optionFlags = CharacterOptionDataFlag.None;
uint options1 = 0;
uint options2 = 0;
uint spellbookFilters = 0;
List<ShortcutEntry> shortcuts = new();
List<IReadOnlyList<uint>> hotbarSpells = new();
List<(uint, uint)> desiredComps = new();
ReadOnlyMemory<byte> gameplayOptions = ReadOnlyMemory<byte>.Empty;
List<InventoryEntry> inventory = new();
List<EquippedEntry> equipped = new();
try
{
if (payload.Length - pos >= 8)
{
optionFlags = (CharacterOptionDataFlag)ReadU32(payload, ref pos);
options1 = ReadU32(payload, ref pos);
}
}
catch (FormatException)
{
// Trailer corrupted — keep what we have and return.
}
return new Parsed(
weenieType, propertyFlags, vectorFlags, hasHealth,
bundle, positions, attributes, skills, spells, enchantments,
CharacterOptionDataFlag.None, 0u, 0u,
System.Array.Empty<ShortcutEntry>(),
System.Array.Empty<IReadOnlyList<uint>>(),
System.Array.Empty<(uint, uint)>(),
0u,
ReadOnlyMemory<byte>.Empty,
System.Array.Empty<InventoryEntry>(),
System.Array.Empty<EquippedEntry>());
optionFlags, options1, options2,
shortcuts, hotbarSpells, desiredComps, spellbookFilters,
gameplayOptions, inventory, equipped);
}
catch (FormatException ex)
{