diff --git a/src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs b/src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs index a6206f2..be31e33 100644 --- a/src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs +++ b/src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs @@ -398,6 +398,9 @@ public static class PlayerDescriptionParser // to 0 if EOF. if (payload.Length - pos >= 4) spellbookFilters = ReadU32(payload, ref pos); + + if (optionFlags.HasFlag(CharacterOptionDataFlag.CharacterOptions2)) + options2 = ReadU32(payload, ref pos); } } catch (FormatException ex) diff --git a/tests/AcDream.Core.Net.Tests/PlayerDescriptionParserTests.cs b/tests/AcDream.Core.Net.Tests/PlayerDescriptionParserTests.cs index 0fd852e..91454a7 100644 --- a/tests/AcDream.Core.Net.Tests/PlayerDescriptionParserTests.cs +++ b/tests/AcDream.Core.Net.Tests/PlayerDescriptionParserTests.cs @@ -593,4 +593,35 @@ public sealed class PlayerDescriptionParserTests Assert.NotNull(parsed); Assert.Equal(0xF00DBA42u, parsed!.Value.SpellbookFilters); } + + [Fact] + public void TryParse_TrailerOptions2_GatedOnCharacterOptions2Bit() + { + var sb = new MemoryStream(); + using var writer = new BinaryWriter(sb); + writer.Write(0u); // propertyFlags + writer.Write(0x52u); // weenieType + writer.Write(0x201u); // ATTRIBUTE | ENCHANTMENT + writer.Write(1u); // has_health + writer.Write(0u); // empty attribute_flags + writer.Write(0u); // empty enchantment mask + + // option_flags = CHARACTER_OPTIONS2 (0x40) + writer.Write(0x40u); + writer.Write(0u); // options1 + + // Legacy hotbar list: count=0. + writer.Write(0u); + + // spellbook_filters + writer.Write(0u); + + // options2 sentinel + writer.Write(0xC0FFEE01u); + + var parsed = PlayerDescriptionParser.TryParse(sb.ToArray()); + + Assert.NotNull(parsed); + Assert.Equal(0xC0FFEE01u, parsed!.Value.Options2); + } }