feat(net): D.2b-B B-Wire — PlayerDescription delivers player properties to ClientObject

Add optional Func<uint>? playerGuid parameter (last in WireAll signature so all
existing callers compile unchanged). When provided, the PD handler calls
items.UpsertProperties(playerGuid(), p.Value.Properties) immediately after the
null-guard, landing EncumbranceVal (PropertyInt 5) and other player stats into the
player ClientObject. Upsert (create-if-absent) handles PD arriving before the
player's CreateObject. Retires AP-48/AP-49 divergence rows (wired in Task 16).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-21 19:00:59 +02:00
parent de8baa1aa1
commit d97d84d7ca
2 changed files with 50 additions and 1 deletions

View file

@ -496,4 +496,43 @@ public sealed class GameEventWiringTests
Assert.Equal(0x5001u, got![0].ObjectGuid);
}
[Fact]
public void WireAll_PlayerDescription_UpsertsPlayerPropertiesIntoClientObject()
{
// PD with a PropertyInt32 table carrying EncumbranceVal(5)=1500. The handler
// must land it in the player ClientObject so the burden bar reads the wire value.
const uint playerGuid = 0x50000001u;
var dispatcher = new GameEventDispatcher();
var items = new ClientObjectTable();
GameEventWiring.WireAll(dispatcher, items, new CombatState(), new Spellbook(),
new ChatLog(), playerGuid: () => playerGuid);
var sb = new MemoryStream();
using var w = new BinaryWriter(sb);
w.Write(0x00000001u); // propertyFlags = PropertyInt32
w.Write(0x52u); // weenieType
// int table: u16 count, u16 buckets, then key/val pairs
w.Write((ushort)1); // count
w.Write((ushort)8); // buckets (ignored)
w.Write(5u); // key = EncumbranceVal
w.Write(1500u); // val
// vector + has_health (no vector blocks)
w.Write(0u); // vectorFlags = None
w.Write(0u); // has_health
// strict trailer
w.Write(0u); // option_flags = None
w.Write(0u); // options1
w.Write(0u); // legacy hotbar count
w.Write(0u); // spellbook_filters
w.Write(0u); // inventory count
w.Write(0u); // equipped count
var env = GameEventEnvelope.TryParse(WrapEnvelope(GameEventType.PlayerDescription, sb.ToArray()));
dispatcher.Dispatch(env!.Value);
var player = items.Get(playerGuid);
Assert.NotNull(player);
Assert.Equal(1500, player!.Properties.Ints[5]);
}
}