diff --git a/src/AcDream.Core/Items/ClientObjectTable.cs b/src/AcDream.Core/Items/ClientObjectTable.cs index 5ed850a8..b789c11c 100644 --- a/src/AcDream.Core/Items/ClientObjectTable.cs +++ b/src/AcDream.Core/Items/ClientObjectTable.cs @@ -205,6 +205,20 @@ public sealed class ClientObjectTable return true; } + /// + /// Apply a SetStackSize (0x0197) update: set the object's StackSize + Value and + /// fire ObjectUpdated so bound widgets refresh the quantity overlay. False if the + /// object is unknown. Retail: ACCWeenieObject::ServerSaysSetStackSize (0x0058...). + /// + public bool UpdateStackSize(uint guid, int stackSize, int value) + { + if (!_objects.TryGetValue(guid, out var item)) return false; + item.StackSize = stackSize; + item.Value = value; + ObjectUpdated?.Invoke(item); + return true; + } + /// /// Canonical CreateObject ingestion: create-if-absent, else patch the /// wire-carried fields in place (retail SetWeenieDesc). Preserves the diff --git a/tests/AcDream.Core.Tests/Items/ClientObjectTableUpdateTests.cs b/tests/AcDream.Core.Tests/Items/ClientObjectTableUpdateTests.cs index b5ec1c78..e2bab4ea 100644 --- a/tests/AcDream.Core.Tests/Items/ClientObjectTableUpdateTests.cs +++ b/tests/AcDream.Core.Tests/Items/ClientObjectTableUpdateTests.cs @@ -38,4 +38,24 @@ public sealed class ClientObjectTableUpdateTests Assert.Equal(99, t.Get(0x50000001u)!.Properties.Ints[5]); Assert.True(updated); } + + [Fact] + public void UpdateStackSize_knownObject_setsFieldsAndFiresUpdated() + { + var t = new ClientObjectTable(); + t.AddOrUpdate(new ClientObject { ObjectId = 0x600u, StackSize = 1, Value = 5 }); + bool updated = false; + t.ObjectUpdated += _ => updated = true; + + bool ok = t.UpdateStackSize(0x600u, stackSize: 25, value: 125); + + Assert.True(ok); + Assert.Equal(25, t.Get(0x600u)!.StackSize); + Assert.Equal(125, t.Get(0x600u)!.Value); + Assert.True(updated); + } + + [Fact] + public void UpdateStackSize_unknownObject_returnsFalse() + => Assert.False(new ClientObjectTable().UpdateStackSize(0xDEADu, 1, 1)); }