feat(D.5.4): PlayerDescription = membership manifest; drop WeenieClassId=ContainerType misuse
The old seeding block set WeenieClassId = inv.ContainerType (a 0/1/2 container-kind discriminator, not a weenie class id) and used MoveItem for the equipped block. Replace both loops with RecordMembership calls: inventory guids get a bare stub (WeenieClassId stays 0); equipped guids get the equip slot set directly. Weenie data arrives via CreateObject / ObjectTableWiring, not PlayerDescription. New test PlayerDescription_SeedsMembership_NotWeenieClassIdMisuse proves: (a) inv guid is registered, (b) WeenieClassId==0 not ContainerType, and (c) equipped guid CurrentlyEquippedLocation is set to MeleeWeapon. No existing tests pinned the old behavior; all 15 GameEventWiringTests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
82f5968316
commit
cbbfe4cd49
2 changed files with 59 additions and 32 deletions
|
|
@ -375,6 +375,58 @@ public sealed class GameEventWiringTests
|
|||
Assert.NotNull(items.Get(0x50000A02u));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlayerDescription_SeedsMembership_NotWeenieClassIdMisuse()
|
||||
{
|
||||
// D.5.4: PlayerDescription is a membership MANIFEST, not the data
|
||||
// source. The old code set WeenieClassId = inv.ContainerType (a
|
||||
// 0/1/2 discriminator), which is a misuse. After the fix, the
|
||||
// registered stub has WeenieClassId == 0 and the equipped item's
|
||||
// CurrentlyEquippedLocation is set to MeleeWeapon (0x1).
|
||||
// Uses the SAME wire fixture as PlayerDescription_RegistersInventoryEntries_InClientObjectTable.
|
||||
var dispatcher = new GameEventDispatcher();
|
||||
var items = new ClientObjectTable();
|
||||
var combat = new CombatState();
|
||||
var spellbook = new Spellbook();
|
||||
var chat = new ChatLog();
|
||||
GameEventWiring.WireAll(dispatcher, items, combat, spellbook, chat);
|
||||
|
||||
var sb = new MemoryStream();
|
||||
using var w = new BinaryWriter(sb);
|
||||
w.Write(0u); // propertyFlags = 0
|
||||
w.Write(0x52u); // weenieType
|
||||
w.Write(0x201u); // vectorFlags = ATTRIBUTE | ENCHANTMENT
|
||||
w.Write(1u); // has_health
|
||||
w.Write(0u); // attribute_flags = 0 (no attrs)
|
||||
w.Write(0u); // enchantment_mask = 0
|
||||
|
||||
w.Write(0u); // option_flags = None (no GAMEPLAY_OPTIONS → strict inv path)
|
||||
w.Write(0u); // options1
|
||||
w.Write(0u); // legacy hotbar list count = 0
|
||||
w.Write(0u); // spellbook_filters
|
||||
|
||||
// Inventory: 1 entry with ContainerType=1 (the OLD code would have
|
||||
// set WeenieClassId=1; the new code must leave WeenieClassId==0).
|
||||
w.Write(1u);
|
||||
w.Write(0x700u); w.Write(1u); // guid=0x700, ContainerType=1
|
||||
|
||||
// Equipped: 1 entry with EquipLocation = MeleeWeapon (0x1).
|
||||
// Wire format: guid(4) + loc(4) + priority(4) = 12 bytes per entry.
|
||||
w.Write(1u);
|
||||
w.Write(0x701u); w.Write((uint)EquipMask.MeleeWeapon); w.Write(0u); // guid=0x701, slot=MeleeWeapon, prio=0
|
||||
|
||||
var env = GameEventEnvelope.TryParse(WrapEnvelope(GameEventType.PlayerDescription, sb.ToArray()));
|
||||
dispatcher.Dispatch(env!.Value);
|
||||
|
||||
// (a) inventory guid is registered
|
||||
Assert.NotNull(items.Get(0x700u));
|
||||
// (b) WeenieClassId must be 0, NOT the ContainerType discriminator (1) — misuse gone
|
||||
Assert.Equal(0u, items.Get(0x700u)!.WeenieClassId);
|
||||
// (c) equipped guid has its equip slot set
|
||||
Assert.NotNull(items.Get(0x701u));
|
||||
Assert.Equal(EquipMask.MeleeWeapon, items.Get(0x701u)!.CurrentlyEquippedLocation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WireAll_PlayerDescription_invokesOnShortcuts()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue