using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using StardewModdingAPI.Framework.StateTracking.Comparers;
using StardewModdingAPI.Framework.StateTracking.FieldWatchers;
using StardewValley;
using StardewValley.Objects;
namespace StardewModdingAPI.Framework.StateTracking
{
/// Tracks changes to a chest's items.
internal class ChestTracker : IDisposable
{
/*********
** Fields
*********/
/// The item stack sizes as of the last update.
private readonly IDictionary- StackSizes;
/// Items added since the last update.
private readonly HashSet
- Added = new(new ObjectReferenceComparer
- ());
/// Items removed since the last update.
private readonly HashSet
- Removed = new(new ObjectReferenceComparer
- ());
/// The underlying inventory watcher.
private readonly ICollectionWatcher
- InventoryWatcher;
/*********
** Accessors
*********/
/// The chest being tracked.
public Chest Chest { get; }
/*********
** Public methods
*********/
/// Construct an instance.
/// A name which identifies what the watcher is watching, used for troubleshooting.
/// The chest being tracked.
public ChestTracker(string name, Chest chest)
{
this.Chest = chest;
this.InventoryWatcher = WatcherFactory.ForNetList($"{name}.{nameof(chest.items)}", chest.items);
this.StackSizes = this.Chest.items
.Where(n => n != null)
.Distinct()
.ToDictionary(n => n, n => n.Stack);
}
/// Update the current values if needed.
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);
}
/// Reset all trackers so their current values are the baseline.
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();
}
/// Get the inventory changes since the last update, if anything changed.
/// The inventory changes, or null if nothing changed.
/// Returns whether anything changed.
public bool TryGetInventoryChanges([NotNullWhen(true)] out SnapshotItemListDiff? changes)
{
return SnapshotItemListDiff.TryGetChanges(added: this.Added, removed: this.Removed, stackSizes: this.StackSizes, out changes);
}
/// Release watchers and resources.
public void Dispose()
{
this.StackSizes.Clear();
this.Added.Clear();
this.Removed.Clear();
this.InventoryWatcher.Dispose();
}
}
}