From c1e8a2cf186a755afe9344d1c6b6356e9c3e2e5e Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 25 Sep 2026 12:41:00 +0200 Subject: [PATCH] Inventory: stamp an appraisal when it arrives The original's appraisal time was the wall clock at the moment the appraisal came in. The reader stamped it when it first built the record, which for a coalesced update can be minutes later; the appraisal event now stamps it. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../Inventory/InventoryFeature.cs | 3 +++ .../Inventory/InventoryReader.cs | 10 ++++++++++ .../Inventory/InventoryFeatureTests.cs | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/src/OpenAC.MosswartMassacre/Inventory/InventoryFeature.cs b/src/OpenAC.MosswartMassacre/Inventory/InventoryFeature.cs index f30b222..d5dd032 100644 --- a/src/OpenAC.MosswartMassacre/Inventory/InventoryFeature.cs +++ b/src/OpenAC.MosswartMassacre/Inventory/InventoryFeature.cs @@ -424,7 +424,10 @@ internal sealed class InventoryFeature : IMmFeature try { if (change.Kind == PluginObjectChangeKind.IdentReceived) + { + _reader.NoteAppraisal(change.ObjectId); _identify.OnIdentReceived(change.ObjectId); + } PluginWorldObject? current = change.Current; if (change.Kind == PluginObjectChangeKind.Released diff --git a/src/OpenAC.MosswartMassacre/Inventory/InventoryReader.cs b/src/OpenAC.MosswartMassacre/Inventory/InventoryReader.cs index 032c573..c5712bb 100644 --- a/src/OpenAC.MosswartMassacre/Inventory/InventoryReader.cs +++ b/src/OpenAC.MosswartMassacre/Inventory/InventoryReader.cs @@ -57,6 +57,16 @@ internal sealed class InventoryReader && world.HasAppraisalData && world.LastIdTime != 0; + /// + /// Stamps an appraisal as it arrives, so the record carries the time it + /// came in rather than the time the record was first built. + /// + public void NoteAppraisal(uint objectId) + { + if (_context.Automation.Objects.TryGet(objectId, out PluginWorldObject world) && world.LastIdTime != 0) + Stamp(objectId, world.LastIdTime); + } + /// The item record for one owned item, as it stands now. public MyWorldObject Build(in PluginInventoryItem item) { diff --git a/tests/OpenAC.MosswartMassacre.Tests/Inventory/InventoryFeatureTests.cs b/tests/OpenAC.MosswartMassacre.Tests/Inventory/InventoryFeatureTests.cs index e283ed5..a659950 100644 --- a/tests/OpenAC.MosswartMassacre.Tests/Inventory/InventoryFeatureTests.cs +++ b/tests/OpenAC.MosswartMassacre.Tests/Inventory/InventoryFeatureTests.cs @@ -252,4 +252,22 @@ public sealed class InventoryFeatureTests Assert.Empty(harness.FramesOfTypeRaw("full_inventory")); } + + [Fact] + public void The_appraisal_time_is_the_wall_clock_when_the_appraisal_arrived() + { + using var harness = new PluginHarness("Mossy"); + InventoryFeature feature = LoginAndSettle(harness); + Own(harness.Host, Tachi(appraised: false)); + Raise(harness.Host, 0x80000202u, PluginObjectChangeKind.Created); + + Own(harness.Host, Tachi(appraised: true), TachiProps(), hostIdTime: 5000); + Raise(harness.Host, 0x80000202u, PluginObjectChangeKind.IdentReceived); + harness.Clock.Advance(TimeSpan.FromMinutes(3)); + harness.Frames.Clear(); + feature.FlushDirtyItems(); + + JObject update = JObject.Parse(harness.FramesOfTypeRaw("inventory_delta").Single()); + Assert.Equal(1790325015, (int)update["item"]!["LastIdTime"]!); + } }