diff --git a/src/AcDream.Core.Net/ObjectTableWiring.cs b/src/AcDream.Core.Net/ObjectTableWiring.cs index 463d7d9e..c94c343d 100644 --- a/src/AcDream.Core.Net/ObjectTableWiring.cs +++ b/src/AcDream.Core.Net/ObjectTableWiring.cs @@ -5,7 +5,9 @@ namespace AcDream.Core.Net; /// /// Wires WorldSession GameMessage-level object events into the client object /// table: CreateObject (0xF745) = canonical merge-upsert, DeleteObject (0xF747) -/// = evict, PublicUpdatePropertyInt (0x02CE) UiEffects = live icon re-composite. +/// = evict, PublicUpdatePropertyInt (0x02CE) = live int apply, PrivateUpdatePropertyInt +/// (0x02CD) = player int (burden), SetStackSize (0x0197) = stack count, InventoryRemoveObject +/// (0x0024) = inventory-view removal. /// Keeps object ingestion in Core.Net (pure data, no GL) and off GameWindow. /// Retail: ACCObjectMaint::CreateObject / DeleteObject (the weenie_object_table side). /// @@ -16,18 +18,35 @@ public static class ObjectTableWiring /// on . Call this BEFORE the render handler subscribes /// to EntitySpawned so the table is populated before the render path runs. /// - public static void Wire(WorldSession session, ClientObjectTable table) + public static void Wire(WorldSession session, ClientObjectTable table, Func? playerGuid = null) { ArgumentNullException.ThrowIfNull(session); ArgumentNullException.ThrowIfNull(table); session.EntitySpawned += s => table.Ingest(ToWeenieData(s)); session.EntityDeleted += d => table.Remove(d.Guid); + + // B-Wire: apply EVERY PropertyInt update on a visible object (0x02CE), not just + // UiEffects — the server is the authority on object properties. UpdateIntProperty + // stores it in the bundle and still mirrors UiEffects → the typed Effects field. session.ObjectIntPropertyUpdated += u => + table.UpdateIntProperty(u.Guid, u.Property, u.Value); + + // B-Wire: PrivateUpdatePropertyInt (0x02CD) carries no guid — it targets the + // local player. Route it to the player object so live EncumbranceVal updates the + // burden bar. (No-op if the player guid isn't wired yet.) + session.PlayerIntPropertyUpdated += u => { - if (u.Property == ClientObjectTable.UiEffectsPropertyId) - table.UpdateIntProperty(u.Guid, u.Property, u.Value); + if (playerGuid is not null) + table.UpdateIntProperty(playerGuid(), u.Property, u.Value); }; + + // B-Wire: SetStackSize (0x0197) — update the object's stack count + value. + session.StackSizeUpdated += u => table.UpdateStackSize(u.Guid, u.StackSize, u.Value); + + // B-Wire: InventoryRemoveObject (0x0024) — the object left the player's inventory + // view; drop it from the table (retail ClientUISystem removes it from maintenance). + session.InventoryObjectRemoved += guid => table.Remove(guid); } /// Translate the wire spawn into the table's merge patch.