diff --git a/src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs b/src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs index 2e040b0..a6206f2 100644 --- a/src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs +++ b/src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs @@ -393,6 +393,11 @@ public static class PlayerDescriptionParser desiredComps.Add((id, amt)); } } + + // holtburger events.rs:576-582 — spellbook_filters is optional; defaults + // to 0 if EOF. + if (payload.Length - pos >= 4) + spellbookFilters = 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 418c586..0fd852e 100644 --- a/tests/AcDream.Core.Net.Tests/PlayerDescriptionParserTests.cs +++ b/tests/AcDream.Core.Net.Tests/PlayerDescriptionParserTests.cs @@ -566,4 +566,31 @@ public sealed class PlayerDescriptionParserTests Assert.Equal((0xAAu, 50u), parsed.Value.DesiredComps[0]); Assert.Equal((0xBBu, 75u), parsed.Value.DesiredComps[1]); } + + [Fact] + public void TryParse_TrailerSpellbookFilters_ReadOptionalU32() + { + 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 + + writer.Write(0u); // option_flags = None + writer.Write(0u); // options1 + + // Legacy hotbar list: count=0 + writer.Write(0u); + + // spellbook_filters sentinel. + writer.Write(0xF00DBA42u); + + var parsed = PlayerDescriptionParser.TryParse(sb.ToArray()); + + Assert.NotNull(parsed); + Assert.Equal(0xF00DBA42u, parsed!.Value.SpellbookFilters); + } }