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.