using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework;
using StardewModdingAPI.Framework.Input;
using StardewModdingAPI.Framework.StateTracking;
using StardewModdingAPI.Framework.StateTracking.FieldWatchers;
using StardewValley;
using StardewValley.Locations;
using StardewValley.Menus;
namespace StardewModdingAPI.Framework
{
/// Monitors the entire game state for changes, virally spreading watchers into any new entities that get created.
internal class WatcherCore
{
/*********
** Fields
*********/
/// The underlying watchers for convenience. These are accessible individually as separate properties.
private readonly List Watchers = new();
/*********
** Accessors
*********/
/// Tracks changes to the window size.
public readonly IValueWatcher WindowSizeWatcher;
/// Tracks changes to the current player.
public PlayerTracker? CurrentPlayerTracker;
/// Tracks changes to the time of day (in 24-hour military format).
public readonly IValueWatcher TimeWatcher;
/// Tracks changes to the save ID.
public readonly IValueWatcher SaveIdWatcher;
/// Tracks changes to the game's locations.
public readonly WorldLocationsTracker LocationsWatcher;
/// Tracks changes to .
public readonly IValueWatcher ActiveMenuWatcher;
/// Tracks changes to the cursor position.
public readonly IValueWatcher CursorWatcher;
/// Tracks changes to the mouse wheel scroll.
public readonly IValueWatcher MouseWheelScrollWatcher;
/// Tracks changes to the content locale.
public readonly IValueWatcher LocaleWatcher;
/*********
** Public methods
*********/
/// Construct an instance.
/// Manages input visible to the game.
/// The observable list of game locations.
public WatcherCore(SInputState inputState, ObservableCollection gameLocations)
{
// init watchers
this.CursorWatcher = WatcherFactory.ForEquatable(nameof(inputState.CursorPosition), () => inputState.CursorPosition);
this.MouseWheelScrollWatcher = WatcherFactory.ForEquatable(nameof(inputState.MouseState.ScrollWheelValue), () => inputState.MouseState.ScrollWheelValue);
this.SaveIdWatcher = WatcherFactory.ForEquatable(nameof(Game1.uniqueIDForThisGame), () => Game1.hasLoadedGame ? Game1.uniqueIDForThisGame : 0);
this.WindowSizeWatcher = WatcherFactory.ForEquatable(nameof(Game1.viewport), () => new Point(Game1.viewport.Width, Game1.viewport.Height));
this.TimeWatcher = WatcherFactory.ForEquatable(nameof(Game1.timeOfDay), () => Game1.timeOfDay);
this.ActiveMenuWatcher = WatcherFactory.ForReference(nameof(Game1.activeClickableMenu), () => Game1.activeClickableMenu);
this.LocationsWatcher = new WorldLocationsTracker(gameLocations, MineShaft.activeMines, VolcanoDungeon.activeLevels);
this.LocaleWatcher = WatcherFactory.ForGenericEquality(nameof(LocalizedContentManager.CurrentLanguageCode), () => LocalizedContentManager.CurrentLanguageCode);
this.Watchers.AddRange(new IWatcher[]
{
this.CursorWatcher,
this.MouseWheelScrollWatcher,
this.SaveIdWatcher,
this.WindowSizeWatcher,
this.TimeWatcher,
this.ActiveMenuWatcher,
this.LocationsWatcher,
this.LocaleWatcher
});
}
/// Update the watchers and adjust for added or removed entities.
public void Update()
{
// reset player
if (Context.IsWorldReady)
{
if (this.CurrentPlayerTracker == null || this.CurrentPlayerTracker.Player != Game1.player)
{
this.CurrentPlayerTracker?.Dispose();
this.CurrentPlayerTracker = new PlayerTracker(Game1.player);
}
}
else
{
if (this.CurrentPlayerTracker != null)
{
this.CurrentPlayerTracker.Dispose();
this.CurrentPlayerTracker = null;
}
}
// update values
foreach (IWatcher watcher in this.Watchers)
watcher.Update();
this.CurrentPlayerTracker?.Update();
this.LocationsWatcher.Update();
}
/// Reset the current values as the baseline.
public void Reset()
{
foreach (IWatcher watcher in this.Watchers)
watcher.Reset();
this.CurrentPlayerTracker?.Reset();
this.LocationsWatcher.Reset();
}
}
}