diff options
| author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2018-05-05 01:31:06 -0400 |
|---|---|---|
| committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2018-05-05 01:31:06 -0400 |
| commit | b8fd3aedfe884741bdda8c68398427f875585456 (patch) | |
| tree | 12b6395923c930fa3155d4be2f38b1aa6e660217 /src/SMAPI | |
| parent | a65a49a62201cc897e73c265a0a808ef0baad002 (diff) | |
| download | SMAPI-b8fd3aedfe884741bdda8c68398427f875585456.tar.gz SMAPI-b8fd3aedfe884741bdda8c68398427f875585456.tar.bz2 SMAPI-b8fd3aedfe884741bdda8c68398427f875585456.zip | |
rewrite location events for multiplayer
Diffstat (limited to 'src/SMAPI')
16 files changed, 532 insertions, 193 deletions
diff --git a/src/SMAPI/Events/EventArgsGameLocationsChanged.cs b/src/SMAPI/Events/EventArgsGameLocationsChanged.cs deleted file mode 100644 index 78ba38fa..00000000 --- a/src/SMAPI/Events/EventArgsGameLocationsChanged.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using StardewValley; - -namespace StardewModdingAPI.Events -{ - /// <summary>Event arguments for a <see cref="LocationEvents.LocationsChanged"/> event.</summary> - public class EventArgsGameLocationsChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// <summary>The current list of game locations.</summary> - public IList<GameLocation> NewLocations { get; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - /// <param name="newLocations">The current list of game locations.</param> - public EventArgsGameLocationsChanged(IList<GameLocation> newLocations) - { - this.NewLocations = newLocations; - } - } -} diff --git a/src/SMAPI/Events/EventArgsIntChanged.cs b/src/SMAPI/Events/EventArgsIntChanged.cs index 0c742d12..a018695c 100644 --- a/src/SMAPI/Events/EventArgsIntChanged.cs +++ b/src/SMAPI/Events/EventArgsIntChanged.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace StardewModdingAPI.Events { @@ -14,6 +14,7 @@ namespace StardewModdingAPI.Events /// <summary>The current value.</summary> public int NewInt { get; } + /********* ** Public methods *********/ diff --git a/src/SMAPI/Events/EventArgsLocationBuildingsChanged.cs b/src/SMAPI/Events/EventArgsLocationBuildingsChanged.cs new file mode 100644 index 00000000..e8184ebe --- /dev/null +++ b/src/SMAPI/Events/EventArgsLocationBuildingsChanged.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; +using StardewValley.Buildings; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="LocationEvents.BuildingsChanged"/> event.</summary> + public class EventArgsLocationBuildingsChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The location which changed.</summary> + public GameLocation Location { get; } + + /// <summary>The buildings added to the location.</summary> + public IEnumerable<Building> Added { get; } + + /// <summary>The buildings removed from the location.</summary> + public IEnumerable<Building> Removed { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="location">The location which changed.</param> + /// <param name="added">The buildings added to the location.</param> + /// <param name="removed">The buildings removed from the location.</param> + public EventArgsLocationBuildingsChanged(GameLocation location, IEnumerable<Building> added, IEnumerable<Building> removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs index a6138ddb..410ef6e6 100644 --- a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs +++ b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs @@ -8,7 +8,7 @@ using SObject = StardewValley.Object; namespace StardewModdingAPI.Events { - /// <summary>Event arguments for a <see cref="LocationEvents.LocationObjectsChanged"/> or <see cref="LocationEvents.ObjectsChanged"/> event.</summary> + /// <summary>Event arguments for a <see cref="LocationEvents.ObjectsChanged"/> event.</summary> public class EventArgsLocationObjectsChanged : EventArgs { /********* @@ -17,31 +17,25 @@ namespace StardewModdingAPI.Events /// <summary>The location which changed.</summary> public GameLocation Location { get; } - /// <summary>The objects added to the list.</summary> + /// <summary>The objects added to the location.</summary> public IEnumerable<KeyValuePair<Vector2, SObject>> Added { get; } - /// <summary>The objects removed from the list.</summary> + /// <summary>The objects removed from the location.</summary> public IEnumerable<KeyValuePair<Vector2, SObject>> Removed { get; } - /// <summary>The current list of objects in the current location.</summary> - [Obsolete("Use " + nameof(EventArgsLocationObjectsChanged.Added))] - public IDictionary<Vector2, NetRef<SObject>> NewObjects { get; } - /********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="location">The location which changed.</param> - /// <param name="added">The objects added to the list.</param> - /// <param name="removed">The objects removed from the list.</param> - /// <param name="newObjects">The current list of objects in the current location.</param> - public EventArgsLocationObjectsChanged(GameLocation location, IEnumerable<KeyValuePair<Vector2, SObject>> added, IEnumerable<KeyValuePair<Vector2, SObject>> removed, IDictionary<Vector2, NetRef<SObject>> newObjects) + /// <param name="added">The objects added to the location.</param> + /// <param name="removed">The objects removed from the location.</param> + public EventArgsLocationObjectsChanged(GameLocation location, IEnumerable<KeyValuePair<Vector2, SObject>> added, IEnumerable<KeyValuePair<Vector2, SObject>> removed) { this.Location = location; this.Added = added.ToArray(); this.Removed = removed.ToArray(); - this.NewObjects = newObjects; } } } diff --git a/src/SMAPI/Events/EventArgsLocationsChanged.cs b/src/SMAPI/Events/EventArgsLocationsChanged.cs new file mode 100644 index 00000000..20984f45 --- /dev/null +++ b/src/SMAPI/Events/EventArgsLocationsChanged.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="LocationEvents.LocationsChanged"/> event.</summary> + public class EventArgsLocationsChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The added locations.</summary> + public IEnumerable<GameLocation> Added { get; } + + /// <summary>The removed locations.</summary> + public IEnumerable<GameLocation> Removed { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="added">The added locations.</param> + /// <param name="removed">The removed locations.</param> + public EventArgsLocationsChanged(IEnumerable<GameLocation> added, IEnumerable<GameLocation> removed) + { + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/EventArgsCurrentLocationChanged.cs b/src/SMAPI/Events/EventArgsPlayerWarped.cs index 25d3ebf3..93026aea 100644 --- a/src/SMAPI/Events/EventArgsCurrentLocationChanged.cs +++ b/src/SMAPI/Events/EventArgsPlayerWarped.cs @@ -1,19 +1,20 @@ -using System; +using System; using StardewValley; namespace StardewModdingAPI.Events { - /// <summary>Event arguments for a <see cref="LocationEvents.CurrentLocationChanged"/> event.</summary> - public class EventArgsCurrentLocationChanged : EventArgs + /// <summary>Event arguments for a <see cref="PlayerEvents.Warped"/> event.</summary> + public class EventArgsPlayerWarped : EventArgs { /********* ** Accessors *********/ + /// <summary>The player's previous location.</summary> + public GameLocation PriorLocation { get; } + /// <summary>The player's current location.</summary> public GameLocation NewLocation { get; } - /// <summary>The player's previous location.</summary> - public GameLocation PriorLocation { get; } /********* @@ -22,7 +23,7 @@ namespace StardewModdingAPI.Events /// <summary>Construct an instance.</summary> /// <param name="priorLocation">The player's previous location.</param> /// <param name="newLocation">The player's current location.</param> - public EventArgsCurrentLocationChanged(GameLocation priorLocation, GameLocation newLocation) + public EventArgsPlayerWarped(GameLocation priorLocation, GameLocation newLocation) { this.NewLocation = newLocation; this.PriorLocation = priorLocation; diff --git a/src/SMAPI/Events/LocationEvents.cs b/src/SMAPI/Events/LocationEvents.cs index 3ed09136..ff75c619 100644 --- a/src/SMAPI/Events/LocationEvents.cs +++ b/src/SMAPI/Events/LocationEvents.cs @@ -16,29 +16,21 @@ namespace StardewModdingAPI.Events /********* ** Events *********/ - /// <summary>Raised after the player warps to a new location.</summary> - public static event EventHandler<EventArgsCurrentLocationChanged> CurrentLocationChanged - { - add => LocationEvents.EventManager.Location_CurrentLocationChanged.Add(value); - remove => LocationEvents.EventManager.Location_CurrentLocationChanged.Remove(value); - } - /// <summary>Raised after a game location is added or removed.</summary> - public static event EventHandler<EventArgsGameLocationsChanged> LocationsChanged + public static event EventHandler<EventArgsLocationsChanged> LocationsChanged { add => LocationEvents.EventManager.Location_LocationsChanged.Add(value); remove => LocationEvents.EventManager.Location_LocationsChanged.Remove(value); } - /// <summary>Raised after the list of objects in the current location changes (e.g. an object is added or removed).</summary> - [Obsolete("Use " + nameof(LocationEvents) + "." + nameof(LocationEvents.ObjectsChanged) + " instead")] - public static event EventHandler<EventArgsLocationObjectsChanged> LocationObjectsChanged + /// <summary>Raised after buildings are added or removed in a location.</summary> + public static event EventHandler<EventArgsLocationBuildingsChanged> BuildingsChanged { - add => LocationEvents.EventManager.Location_LocationObjectsChanged.Add(value); - remove => LocationEvents.EventManager.Location_LocationObjectsChanged.Remove(value); + add => LocationEvents.EventManager.Location_BuildingsChanged.Add(value); + remove => LocationEvents.EventManager.Location_BuildingsChanged.Remove(value); } - /// <summary>Raised after the list of objects in a location changes (e.g. an object is added or removed).</summary> + /// <summary>Raised after objects are added or removed in a location.</summary> public static event EventHandler<EventArgsLocationObjectsChanged> ObjectsChanged { add => LocationEvents.EventManager.Location_ObjectsChanged.Add(value); diff --git a/src/SMAPI/Events/PlayerEvents.cs b/src/SMAPI/Events/PlayerEvents.cs index 84a7ff63..6e7050e3 100644 --- a/src/SMAPI/Events/PlayerEvents.cs +++ b/src/SMAPI/Events/PlayerEvents.cs @@ -23,13 +23,21 @@ namespace StardewModdingAPI.Events remove => PlayerEvents.EventManager.Player_InventoryChanged.Remove(value); } - /// <summary> Raised after the player levels up a skill. This happens as soon as they level up, not when the game notifies the player after their character goes to bed.</summary> + /// <summary>Raised after the player levels up a skill. This happens as soon as they level up, not when the game notifies the player after their character goes to bed.</summary> public static event EventHandler<EventArgsLevelUp> LeveledUp { add => PlayerEvents.EventManager.Player_LeveledUp.Add(value); remove => PlayerEvents.EventManager.Player_LeveledUp.Remove(value); } + /// <summary>Raised after the player warps to a new location.</summary> + public static event EventHandler<EventArgsPlayerWarped> Warped + { + add => PlayerEvents.EventManager.Player_Warped.Add(value); + remove => PlayerEvents.EventManager.Player_Warped.Remove(value); + } + + /********* ** Public methods diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 9030ba97..84036127 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -108,17 +108,13 @@ namespace StardewModdingAPI.Framework.Events /**** ** LocationEvents ****/ - /// <summary>Raised after the player warps to a new location.</summary> - public readonly ManagedEvent<EventArgsCurrentLocationChanged> Location_CurrentLocationChanged; - /// <summary>Raised after a game location is added or removed.</summary> - public readonly ManagedEvent<EventArgsGameLocationsChanged> Location_LocationsChanged; + public readonly ManagedEvent<EventArgsLocationsChanged> Location_LocationsChanged; - /// <summary>Raised after the list of objects in the current location changes (e.g. an object is added or removed).</summary> - [Obsolete] - public readonly ManagedEvent<EventArgsLocationObjectsChanged> Location_LocationObjectsChanged; + /// <summary>Raised after buildings are added or removed in a location.</summary> + public readonly ManagedEvent<EventArgsLocationBuildingsChanged> Location_BuildingsChanged; - /// <summary>Raised after the list of objects in a location changes (e.g. an object is added or removed).</summary> + /// <summary>Raised after objects are added or removed in a location.</summary> public readonly ManagedEvent<EventArgsLocationObjectsChanged> Location_ObjectsChanged; /**** @@ -160,6 +156,10 @@ namespace StardewModdingAPI.Framework.Events /// <summary> Raised after the player levels up a skill. This happens as soon as they level up, not when the game notifies the player after their character goes to bed.</summary> public readonly ManagedEvent<EventArgsLevelUp> Player_LeveledUp; + /// <summary>Raised after the player warps to a new location.</summary> + public readonly ManagedEvent<EventArgsPlayerWarped> Player_Warped; + + /**** ** SaveEvents ****/ @@ -241,9 +241,8 @@ namespace StardewModdingAPI.Framework.Events this.Input_ButtonPressed = ManageEventOf<EventArgsInput>(nameof(InputEvents), nameof(InputEvents.ButtonPressed)); this.Input_ButtonReleased = ManageEventOf<EventArgsInput>(nameof(InputEvents), nameof(InputEvents.ButtonReleased)); - this.Location_CurrentLocationChanged = ManageEventOf<EventArgsCurrentLocationChanged>(nameof(LocationEvents), nameof(LocationEvents.CurrentLocationChanged)); - this.Location_LocationsChanged = ManageEventOf<EventArgsGameLocationsChanged>(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); - this.Location_LocationObjectsChanged = ManageEventOf<EventArgsLocationObjectsChanged>(nameof(LocationEvents), nameof(LocationEvents.LocationObjectsChanged)); + this.Location_LocationsChanged = ManageEventOf<EventArgsLocationsChanged>(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); + this.Location_BuildingsChanged = ManageEventOf<EventArgsLocationBuildingsChanged>(nameof(LocationEvents), nameof(LocationEvents.BuildingsChanged)); this.Location_ObjectsChanged = ManageEventOf<EventArgsLocationObjectsChanged>(nameof(LocationEvents), nameof(LocationEvents.ObjectsChanged)); this.Menu_Changed = ManageEventOf<EventArgsClickableMenuChanged>(nameof(MenuEvents), nameof(MenuEvents.MenuChanged)); @@ -258,6 +257,7 @@ namespace StardewModdingAPI.Framework.Events this.Player_InventoryChanged = ManageEventOf<EventArgsInventoryChanged>(nameof(PlayerEvents), nameof(PlayerEvents.InventoryChanged)); this.Player_LeveledUp = ManageEventOf<EventArgsLevelUp>(nameof(PlayerEvents), nameof(PlayerEvents.LeveledUp)); + this.Player_Warped = ManageEventOf<EventArgsPlayerWarped>(nameof(PlayerEvents), nameof(PlayerEvents.Warped)); this.Save_BeforeCreate = ManageEvent(nameof(SaveEvents), nameof(SaveEvents.BeforeCreate)); this.Save_AfterCreate = ManageEvent(nameof(SaveEvents), nameof(SaveEvents.AfterCreate)); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index d2ba85f8..c8c30834 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -23,7 +23,6 @@ using StardewValley.Menus; using StardewValley.Tools; using xTile.Dimensions; using xTile.Layers; -using SObject = StardewValley.Object; namespace StardewModdingAPI.Framework { @@ -92,11 +91,8 @@ namespace StardewModdingAPI.Framework /// <summary>Tracks changes to the save ID.</summary> private readonly IValueWatcher<ulong> SaveIdWatcher; - /// <summary>Tracks changes to the location list.</summary> - private readonly ICollectionWatcher<GameLocation> LocationListWatcher; - - /// <summary>Tracks changes to each location.</summary> - private readonly IDictionary<GameLocation, LocationTracker> LocationWatchers = new Dictionary<GameLocation, LocationTracker>(); + /// <summary>Tracks changes to the game's locations.</summary> + private readonly WorldLocationsTracker LocationsWatcher; /// <summary>Tracks changes to <see cref="Game1.activeClickableMenu"/>.</summary> private readonly IValueWatcher<IClickableMenu> ActiveMenuWatcher; @@ -165,14 +161,14 @@ namespace StardewModdingAPI.Framework this.WindowSizeWatcher = WatcherFactory.ForEquatable(() => new Point(Game1.viewport.Width, Game1.viewport.Height)); this.TimeWatcher = WatcherFactory.ForEquatable(() => Game1.timeOfDay); this.ActiveMenuWatcher = WatcherFactory.ForReference(() => Game1.activeClickableMenu); - this.LocationListWatcher = WatcherFactory.ForObservableCollection((ObservableCollection<GameLocation>)Game1.locations); + this.LocationsWatcher = new WorldLocationsTracker((ObservableCollection<GameLocation>)Game1.locations); this.Watchers.AddRange(new IWatcher[] { this.SaveIdWatcher, this.WindowSizeWatcher, this.TimeWatcher, this.ActiveMenuWatcher, - this.LocationListWatcher + this.LocationsWatcher }); } @@ -351,22 +347,7 @@ namespace StardewModdingAPI.Framework foreach (IWatcher watcher in this.Watchers) watcher.Update(); this.CurrentPlayerTracker?.Update(); - - // update location watchers - if (this.LocationListWatcher.IsChanged) - { - foreach (GameLocation location in this.LocationListWatcher.Removed.Union(this.LocationListWatcher.Added)) - { - if (this.LocationWatchers.TryGetValue(location, out LocationTracker watcher)) - { - this.Watchers.Remove(watcher); - this.LocationWatchers.Remove(location); - watcher.Dispose(); - } - } - foreach (GameLocation location in this.LocationListWatcher.Added) - this.LocationWatchers[location] = new LocationTracker(location); - } + this.LocationsWatcher.Update(); /********* ** Locale changed events @@ -516,45 +497,86 @@ namespace StardewModdingAPI.Framework *********/ if (Context.IsWorldReady) { - // update player info - PlayerTracker curPlayer = this.CurrentPlayerTracker; + bool raiseWorldEvents = !this.SaveIdWatcher.IsChanged; // don't report changes from unloaded => loaded - // raise current location changed - if (curPlayer.TryGetNewLocation(out GameLocation newLocation)) + // raise location changes + if (this.LocationsWatcher.IsChanged) { - if (this.VerboseLogging) - this.Monitor.Log($"Context: set location to {newLocation.Name}.", LogLevel.Trace); - this.Events.Location_CurrentLocationChanged.Raise(new EventArgsCurrentLocationChanged(curPlayer.LocationWatcher.PreviousValue, newLocation)); + // location list changes + if (this.LocationsWatcher.IsLocationListChanged) + { + GameLocation[] added = this.LocationsWatcher.Added.ToArray(); + GameLocation[] removed = this.LocationsWatcher.Removed.ToArray(); + this.LocationsWatcher.ResetLocationList(); + + if (this.VerboseLogging) + { + string addedText = this.LocationsWatcher.Added.Any() ? string.Join(", ", added.Select(p => p.Name)) : "none"; + string removedText = this.LocationsWatcher.Removed.Any() ? string.Join(", ", removed.Select(p => p.Name)) : "none"; + this.Monitor.Log($"Context: location list changed (added {addedText}; removed {removedText}).", LogLevel.Trace); + } + + this.Events.Location_LocationsChanged.Raise(new EventArgsLocationsChanged(added, removed)); + } + + // raise location contents changed + if (raiseWorldEvents) + { + foreach (LocationTracker watcher in this.LocationsWatcher.Locations) + { + // objects changed + if (watcher.ObjectsWatcher.IsChanged) + { + GameLocation location = watcher.Location; + var added = watcher.ObjectsWatcher.Added; + var removed = watcher.ObjectsWatcher.Removed; + watcher.ObjectsWatcher.Reset(); + + this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); + } + + // buildings changed + if (watcher.BuildingsWatcher.IsChanged) + { + GameLocation location = watcher.Location; + var added = watcher.BuildingsWatcher.Added; + var removed = watcher.BuildingsWatcher.Removed; + watcher.BuildingsWatcher.Reset(); + + this.Events.Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); + } + } + } + else + this.LocationsWatcher.Reset(); } - // raise location list changed - if (this.LocationListWatcher.IsChanged) + // raise time changed + if (raiseWorldEvents && this.TimeWatcher.IsChanged) { + int was = this.TimeWatcher.PreviousValue; + int now = this.TimeWatcher.CurrentValue; + this.TimeWatcher.Reset(); + if (this.VerboseLogging) - { - string added = this.LocationListWatcher.Added.Any() ? string.Join(", ", this.LocationListWatcher.Added.Select(p => p.Name)) : "none"; - string removed = this.LocationListWatcher.Removed.Any() ? string.Join(", ", this.LocationListWatcher.Removed.Select(p => p.Name)) : "none"; - this.Monitor.Log($"Context: location list changed (added {added}; removed {removed}).", LogLevel.Trace); - } + this.Monitor.Log($"Context: time changed from {was} to {now}.", LogLevel.Trace); - this.Events.Location_LocationsChanged.Raise(new EventArgsGameLocationsChanged(Game1.locations)); + this.Events.Time_TimeOfDayChanged.Raise(new EventArgsIntChanged(was, now)); } + else + this.TimeWatcher.Reset(); - // raise events that shouldn't be triggered on initial load - if (!this.SaveIdWatcher.IsChanged) + // raise player events + if (raiseWorldEvents) { - // raise location objects changed - foreach (LocationTracker watcher in this.LocationWatchers.Values) - { - if (watcher.LocationObjectsWatcher.IsChanged) - { - GameLocation location = watcher.Location; - var added = watcher.LocationObjectsWatcher.Added; - var removed = watcher.LocationObjectsWatcher.Removed; - watcher.Reset(); + PlayerTracker curPlayer = this.CurrentPlayerTracker; - this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed, watcher.Location.netObjects.FieldDict)); - } + // raise current location changed + if (curPlayer.TryGetNewLocation(out GameLocation newLocation)) + { + if (this.VerboseLogging) + this.Monitor.Log($"Context: set location to {newLocation.Name}.", LogLevel.Trace); + this.Events.Player_Warped.Raise(new EventArgsPlayerWarped(curPlayer.LocationWatcher.PreviousValue, newLocation)); } // raise player leveled up a skill @@ -574,27 +596,6 @@ namespace StardewModdingAPI.Framework this.Events.Player_InventoryChanged.Raise(new EventArgsInventoryChanged(Game1.player.Items, changedItems.ToList())); } - // raise current location's object list changed - { - if (curPlayer.TryGetLocationChanges(out IDictionaryWatcher<Vector2, SObject> watcher)) - { - if (this.VerboseLogging) - this.Monitor.Log("Context: current location objects changed.", LogLevel.Trace); - - GameLocation location = curPlayer.GetCurrentLocation(); - - this.Events.Location_LocationObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, watcher.Added, watcher.Removed, location.netObjects.FieldDict)); - } - } - - // raise time changed - if (this.TimeWatcher.IsChanged) - { - if (this.VerboseLogging) - this.Monitor.Log($"Context: time changed from {this.TimeWatcher.PreviousValue} to {this.TimeWatcher.CurrentValue}.", LogLevel.Trace); - this.Events.Time_TimeOfDayChanged.Raise(new EventArgsIntChanged(this.TimeWatcher.PreviousValue, this.TimeWatcher.CurrentValue)); - } - // raise mine level changed if (curPlayer.TryGetNewMineLevel(out int mineLevel)) { @@ -603,18 +604,11 @@ namespace StardewModdingAPI.Framework this.Events.Mine_LevelChanged.Raise(new EventArgsMineLevelChanged(curPlayer.MineLevelWatcher.PreviousValue, mineLevel)); } } + this.CurrentPlayerTracker?.Reset(); } - // update state - this.CurrentPlayerTracker?.Reset(); - this.LocationListWatcher.Reset(); + // update save ID watcher this.SaveIdWatcher.Reset(); - this.TimeWatcher.Reset(); - if (!Context.IsWorldReady) - { - foreach (LocationTracker watcher in this.LocationWatchers.Values) - watcher.Reset(); - } /********* ** Game update diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs new file mode 100644 index 00000000..f92edb90 --- /dev/null +++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using Netcode; + +namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers +{ + /// <summary>A watcher which detects changes to a Netcode collection.</summary> + internal class NetCollectionWatcher<TValue> : BaseDisposableWatcher, ICollectionWatcher<TValue> + where TValue : INetObject<INetSerializable> + { + /********* + ** Properties + *********/ + /// <summary>The field being watched.</summary> + private readonly NetCollection<TValue> Field; + + /// <summary>The pairs added since the last reset.</summary> + private readonly List<TValue> AddedImpl = new List<TValue>(); + + /// <summary>The pairs demoved since the last reset.</summary> + private readonly List<TValue> RemovedImpl = new List<TValue>(); + + + /********* + ** Accessors + *********/ + /// <summary>Whether the collection changed since the last reset.</summary> + public bool IsChanged => this.AddedImpl.Count > 0 || this.RemovedImpl.Count > 0; + + /// <summary>The values added since the last reset.</summary> + public IEnumerable<TValue> Added => this.AddedImpl; + + /// <summary>The values removed since the last reset.</summary> + public IEnumerable<TValue> Removed => this.RemovedImpl; + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="field">The field to watch.</param> + public NetCollectionWatcher(NetCollection<TValue> field) + { + this.Field = field; + field.OnValueAdded += this.OnValueAdded; + field.OnValueRemoved += this.OnValueRemoved; + } + + /// <summary>Update the current value if needed.</summary> + public void Update() + { + this.AssertNotDisposed(); + } + + /// <summary>Set the current value as the baseline.</summary> + public void Reset() + { + this.AssertNotDisposed(); + + this.AddedImpl.Clear(); + this.RemovedImpl.Clear(); + } + + /// <summary>Stop watching the field and release all references.</summary> + public override void Dispose() + { + if (!this.IsDisposed) + { + this.Field.OnValueAdded -= this.OnValueAdded; + this.Field.OnValueRemoved -= this.OnValueRemoved; + } + + base.Dispose(); + } + + + /********* + ** Private methods + *********/ + /// <summary>A callback invoked when an entry is added to the collection.</summary> + /// <param name="value">The added value.</param> + private void OnValueAdded(TValue value) + { + this.AddedImpl.Add(value); + } + + /// <summary>A callback invoked when an entry is removed from the collection.</summary> + /// <param name="value">The added value.</param> + private void OnValueRemoved(TValue value) + { + this.RemovedImpl.Add(value); + } + } +} |
