diff options
Diffstat (limited to 'src/SMAPI/Framework/StateTracking/ChestTracker.cs')
-rw-r--r-- | src/SMAPI/Framework/StateTracking/ChestTracker.cs | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/SMAPI/Framework/StateTracking/ChestTracker.cs b/src/SMAPI/Framework/StateTracking/ChestTracker.cs new file mode 100644 index 00000000..65f58ee7 --- /dev/null +++ b/src/SMAPI/Framework/StateTracking/ChestTracker.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewModdingAPI.Framework.StateTracking.Comparers; +using StardewModdingAPI.Framework.StateTracking.FieldWatchers; +using StardewValley; +using StardewValley.Objects; + +namespace StardewModdingAPI.Framework.StateTracking +{ + /// <summary>Tracks changes to a chest's items.</summary> + internal class ChestTracker : IDisposable + { + /********* + ** Fields + *********/ + /// <summary>The item stack sizes as of the last update.</summary> + private readonly IDictionary<Item, int> StackSizes; + + /// <summary>Items added since the last update.</summary> + private readonly HashSet<Item> Added = new HashSet<Item>(new ObjectReferenceComparer<Item>()); + + /// <summary>Items removed since the last update.</summary> + private readonly HashSet<Item> Removed = new HashSet<Item>(new ObjectReferenceComparer<Item>()); + + /// <summary>The underlying inventory watcher.</summary> + private readonly ICollectionWatcher<Item> InventoryWatcher; + + + /********* + ** Accessors + *********/ + /// <summary>The chest being tracked.</summary> + public Chest Chest { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="chest">The chest being tracked.</param> + public ChestTracker(Chest chest) + { + this.Chest = chest; + this.InventoryWatcher = WatcherFactory.ForNetList(chest.items); + + this.StackSizes = this.Chest.items + .Where(n => n != null) + .Distinct() + .ToDictionary(n => n, n => n.Stack); + } + + /// <summary>Update the current values if needed.</summary> + public void Update() + { + // update watcher + this.InventoryWatcher.Update(); + foreach (Item item in this.InventoryWatcher.Added) + this.Added.Add(item); + foreach (Item item in this.InventoryWatcher.Removed) + { + if (!this.Added.Remove(item)) // item didn't change if it was both added and removed, so remove it from both lists + this.Removed.Add(item); + } + + // stop tracking removed stacks + foreach (Item item in this.Removed) + this.StackSizes.Remove(item); + } + + /// <summary>Reset all trackers so their current values are the baseline.</summary> + public void Reset() + { + // update stack sizes + foreach (Item item in this.StackSizes.Keys.ToArray().Concat(this.Added)) + this.StackSizes[item] = item.Stack; + + // update watcher + this.InventoryWatcher.Reset(); + this.Added.Clear(); + this.Removed.Clear(); + } + + /// <summary>Get the inventory changes since the last update, if anything changed.</summary> + /// <param name="changes">The inventory changes, or <c>null</c> if nothing changed.</param> + /// <returns>Returns whether anything changed.</returns> + public bool TryGetInventoryChanges(out SnapshotItemListDiff changes) + { + return SnapshotItemListDiff.TryGetChanges(added: this.Added, removed: this.Removed, stackSizes: this.StackSizes, out changes); + } + + /// <summary>Release watchers and resources.</summary> + public void Dispose() + { + this.StackSizes.Clear(); + this.Added.Clear(); + this.Removed.Clear(); + this.InventoryWatcher.Dispose(); + } + } +} |