From 29fba4b7cbd857855c9590b92033e95e97fa33f9 Mon Sep 17 00:00:00 2001 From: erik Date: Sun, 11 May 2025 15:48:48 +0200 Subject: [PATCH] test of inventory --- MosswartMassacre/Inventory.cs | 157 +++++++++++++++++++++++ MosswartMassacre/MosswartMassacre.csproj | 1 + MosswartMassacre/PluginCore.cs | 3 + 3 files changed, 161 insertions(+) create mode 100644 MosswartMassacre/Inventory.cs diff --git a/MosswartMassacre/Inventory.cs b/MosswartMassacre/Inventory.cs new file mode 100644 index 0000000..21c8b91 --- /dev/null +++ b/MosswartMassacre/Inventory.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Decal.Adapter; +using Decal.Adapter.Wrappers; +using Newtonsoft.Json; + +namespace MosswartMassacre +{ + public sealed class InventoryMonitor : IDisposable + { + private const string Schema = "mm-inv/1.1"; + private readonly string _filePath; + private Dictionary _cache = new Dictionary(); + private readonly WorldFilter _wf; + private readonly CharacterFilter _cf; + private bool _suppress; + + public InventoryMonitor() + { + _cf = CoreManager.Current.CharacterFilter; + _wf = CoreManager.Current.WorldFilter; + _filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{_cf.Name}-inventory.json"); + + _cf.LoginComplete += (_, __) => SnapshotAndSaveAll(); + _wf.CreateObject += OnWorldFilterEvent; + _wf.ChangeObject += OnWorldFilterEvent; + _wf.MoveObject += OnWorldFilterEvent; + _wf.ReleaseObject += OnWorldFilterEvent; + + if (_cf.LoginStatus == 3) + SnapshotAndSaveAll(); + } + + public void Dispose() + { + _cf.LoginComplete -= (_, __) => SnapshotAndSaveAll(); + _wf.CreateObject -= OnWorldFilterEvent; + _wf.ChangeObject -= OnWorldFilterEvent; + _wf.MoveObject -= OnWorldFilterEvent; + _wf.ReleaseObject -= OnWorldFilterEvent; + } + + private void SnapshotAndSaveAll() + { + var snapshot = _wf.GetInventory() + .Select(o => new ItemRecord(o)) + .ToDictionary(r => r.Id, r => r); + + SaveToDisk(new SnapshotFile + { + schema = Schema, + items = snapshot.Values.ToList() + }); + + _cache = snapshot; + } + + private void OnWorldFilterEvent(object s, EventArgs e) + { + if (_suppress) return; + _suppress = true; + try { DiffAndSave(); } + finally { _suppress = false; } + } + + private void DiffAndSave() + { + var latest = _wf.GetInventory() + .Select(o => new ItemRecord(o)) + .ToDictionary(r => r.Id, r => r); + + var adds = latest.Keys.Except(_cache.Keys) + .Select(id => latest[id]); + var removes = _cache.Keys.Except(latest.Keys); + var updates = latest.Values + .Where(r => _cache.TryGetValue(r.Id, out var old) && !r.Equals(old)); + + if (!adds.Any() && !removes.Any() && !updates.Any()) + return; + + var patch = new PatchFile + { + schema = Schema, + type = "events", + adds = adds.ToList(), + removes = removes.ToList(), + updates = updates.ToList() + }; + SaveToDisk(patch); + + _cache = latest; + } + + private void SaveToDisk(object doc) + { + var json = JsonConvert.SerializeObject(doc, Formatting.Indented); + File.WriteAllText(_filePath, json, Encoding.UTF8); + } + + // Data classes + private class SnapshotFile + { + public string Schema => schema; + public string schema; + public List items; + } + + private class PatchFile + { + public string schema; + public string type; + public List adds; + public List removes; + public List updates; + } + } + + public class ItemRecord : IEquatable + { + public int Id { get; set; } + public string Name { get; set; } + public int Container { get; set; } + public int Icon { get; set; } + public int Count { get; set; } + public bool Equipped { get; set; } + public bool HasIdData { get; set; } + public int ObjectClass { get; set; } + + public ItemRecord() { } + + public ItemRecord(WorldObject wo) + { + Id = wo.Id; + Name = wo.Name; + Container = wo.Container; + Icon = wo.Icon; + Count = (int)wo.Values(LongValueKey.StackCount, 1); + Equipped = wo.Values(LongValueKey.EquippedSlots, 0) > 0; + HasIdData = wo.HasIdData; + ObjectClass = (int)wo.ObjectClass; + } + + public bool Equals(ItemRecord other) + { + if (other == null) return false; + return Container == other.Container + && Count == other.Count + && Equipped == other.Equipped + && HasIdData == other.HasIdData; + } + + public override int GetHashCode() => Id; + } +} diff --git a/MosswartMassacre/MosswartMassacre.csproj b/MosswartMassacre/MosswartMassacre.csproj index 33a1c87..63d5676 100644 --- a/MosswartMassacre/MosswartMassacre.csproj +++ b/MosswartMassacre/MosswartMassacre.csproj @@ -74,6 +74,7 @@ + diff --git a/MosswartMassacre/PluginCore.cs b/MosswartMassacre/PluginCore.cs index 9fe72b8..d705358 100644 --- a/MosswartMassacre/PluginCore.cs +++ b/MosswartMassacre/PluginCore.cs @@ -32,6 +32,7 @@ namespace MosswartMassacre private static Queue rareMessageQueue = new Queue(); private static DateTime _lastSent = DateTime.MinValue; private static readonly Queue _chatQueue = new Queue(); + private InventoryMonitor _inv; protected override void Startup() { @@ -63,6 +64,7 @@ namespace MosswartMassacre vTank.Enable(); //lyssna på commands WebSocket.OnServerCommand += HandleServerCommand; + _inv = new InventoryMonitor(); } catch (Exception ex) { @@ -101,6 +103,7 @@ namespace MosswartMassacre // sluta lyssna på commands WebSocket.OnServerCommand -= HandleServerCommand; WebSocket.Stop(); + _inv?.Dispose(); MyHost = null; }