using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using StardewModdingAPI.Framework.StateTracking.FieldWatchers;
using StardewValley;
using StardewValley.Buildings;
using StardewValley.Locations;
using StardewValley.TerrainFeatures;
using Object = StardewValley.Object;
using Chest = StardewValley.Objects.Chest;
namespace StardewModdingAPI.Framework.StateTracking
{
/// Tracks changes to a location's data.
internal class LocationTracker : IWatcher
{
/*********
** Fields
*********/
/// The underlying watchers.
private readonly List Watchers = new List();
/*********
** Accessors
*********/
/// Whether the value changed since the last reset.
public bool IsChanged => this.Watchers.Any(p => p.IsChanged);
/// The tracked location.
public GameLocation Location { get; }
/// Tracks added or removed buildings.
public ICollectionWatcher BuildingsWatcher { get; }
/// Tracks added or removed debris.
public ICollectionWatcher DebrisWatcher { get; }
/// Tracks added or removed large terrain features.
public ICollectionWatcher LargeTerrainFeaturesWatcher { get; }
/// Tracks added or removed NPCs.
public ICollectionWatcher NpcsWatcher { get; }
/// Tracks added or removed objects.
public IDictionaryWatcher ObjectsWatcher { get; }
/// Tracks added or removed terrain features.
public IDictionaryWatcher TerrainFeaturesWatcher { get; }
public Dictionary> activeChestWatchers = new Dictionary>();
/*********
** Public methods
*********/
/// Construct an instance.
/// The location to track.
public LocationTracker(GameLocation location)
{
this.Location = location;
// init watchers
this.BuildingsWatcher = location is BuildableGameLocation buildableLocation ? WatcherFactory.ForNetCollection(buildableLocation.buildings) : WatcherFactory.ForImmutableCollection();
this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris);
this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection(location.largeTerrainFeatures);
this.NpcsWatcher = WatcherFactory.ForNetCollection(location.characters);
this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects);
this.TerrainFeaturesWatcher = WatcherFactory.ForNetDictionary(location.terrainFeatures);
this.Watchers.AddRange(new IWatcher[]
{
this.BuildingsWatcher,
this.DebrisWatcher,
this.LargeTerrainFeaturesWatcher,
this.NpcsWatcher,
this.ObjectsWatcher,
this.TerrainFeaturesWatcher
});
}
/// Stop watching the player fields and release all references.
public void Dispose()
{
foreach (IWatcher watcher in this.Watchers)
watcher.Dispose();
}
/// Update the current value if needed.
public void Update()
{
foreach (IWatcher watcher in this.Watchers)
watcher.Update();
foreach (KeyValuePair obj in this.ObjectsWatcher.Added.Where(p => p.Value is Chest))
{
if (!this.activeChestWatchers.ContainsKey(obj.Key))
{
//create a new watcher for chests items
Chest temp = obj.Value as Chest;
NetListWatcher tempItemWatcher = new NetListWatcher(temp.items, obj.Key);
this.Watchers.Add(tempItemWatcher);
this.activeChestWatchers.Add(obj.Key, tempItemWatcher);
}
}
foreach (KeyValuePair obj in this.ObjectsWatcher.Removed)
{
this.activeChestWatchers.TryGetValue(obj.Key, out NetListWatcher tempItemWatcher);
this.Watchers.Remove(tempItemWatcher);
this.activeChestWatchers.Remove(obj.Key);
}
}
/// Set the current value as the baseline.
public void Reset()
{
foreach (IWatcher watcher in this.Watchers)
watcher.Reset();
}
}
}