From adda9611c73163270cbfcd34d6617560f81d54b0 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 27 Apr 2018 18:49:13 -0400 Subject: add multiplayer sync events (#479) --- src/SMAPI/Framework/Events/EventManager.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index d7c89a76..87ff760f 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -125,6 +125,21 @@ namespace StardewModdingAPI.Framework.Events /// Raised after a game menu is closed. public readonly ManagedEvent Menu_Closed; + /**** + ** MultiplayerEvents + ****/ + /// Raised before the game syncs changes from other players. + public readonly ManagedEvent Multiplayer_BeforeMainSync; + + /// Raised after the game syncs changes from other players. + public readonly ManagedEvent Multiplayer_AfterMainSync; + + /// Raised before the game broadcasts changes to other players. + public readonly ManagedEvent Multiplayer_BeforeMainBroadcast; + + /// Raised after the game broadcasts changes to other players. + public readonly ManagedEvent Multiplayer_AfterMainBroadcast; + /**** ** MineEvents ****/ @@ -228,6 +243,11 @@ namespace StardewModdingAPI.Framework.Events this.Menu_Changed = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuChanged)); this.Menu_Closed = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuClosed)); + this.Multiplayer_BeforeMainBroadcast = ManageEvent(nameof(MultiplayerEvents), nameof(MultiplayerEvents.BeforeMainBroadcast)); + this.Multiplayer_AfterMainBroadcast = ManageEvent(nameof(MultiplayerEvents), nameof(MultiplayerEvents.AfterMainBroadcast)); + this.Multiplayer_BeforeMainSync = ManageEvent(nameof(MultiplayerEvents), nameof(MultiplayerEvents.BeforeMainSync)); + this.Multiplayer_AfterMainSync = ManageEvent(nameof(MultiplayerEvents), nameof(MultiplayerEvents.AfterMainSync)); + this.Mine_LevelChanged = ManageEventOf(nameof(MineEvents), nameof(MineEvents.MineLevelChanged)); this.Player_InventoryChanged = ManageEventOf(nameof(PlayerEvents), nameof(PlayerEvents.InventoryChanged)); -- cgit From 8051862c7bd2fe498657eef4bb102b5ca33390a6 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 4 May 2018 20:44:20 -0400 Subject: add LocationEvents.ObjectsChanged event --- docs/release-notes.md | 1 + .../Events/EventArgsLocationObjectsChanged.cs | 26 ++++++-- src/SMAPI/Events/LocationEvents.cs | 8 +++ src/SMAPI/Framework/Events/EventManager.cs | 6 ++ src/SMAPI/Framework/SGame.cs | 64 +++++++++++++++---- .../Framework/StateTracking/LocationTracker.cs | 71 ++++++++++++++++++++++ src/SMAPI/StardewModdingAPI.csproj | 1 + 7 files changed, 162 insertions(+), 15 deletions(-) create mode 100644 src/SMAPI/Framework/StateTracking/LocationTracker.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 85776a06..558ed004 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -11,6 +11,7 @@ * For modders: * Added code analysis to mod build config package to flag common issues as warnings. + * Added `LocationEvents.ObjectsChanged`, raised when an object is added/removed in any location. * Added `Context.IsMultiplayer` and `Context.IsMainPlayer` flags. * Added `Constants.TargetPlatform` which says whether the game is running on Linux, Mac, or Windows. * Added `semanticVersion.IsPrerelease()` method. diff --git a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs index de6bd365..a6138ddb 100644 --- a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs +++ b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs @@ -1,28 +1,46 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.Xna.Framework; using Netcode; -using Object = StardewValley.Object; +using StardewValley; +using SObject = StardewValley.Object; namespace StardewModdingAPI.Events { - /// Event arguments for a event. + /// Event arguments for a or event. public class EventArgsLocationObjectsChanged : EventArgs { /********* ** Accessors *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The objects added to the list. + public IEnumerable> Added { get; } + + /// The objects removed from the list. + public IEnumerable> Removed { get; } + /// The current list of objects in the current location. - public IDictionary> NewObjects { get; } + [Obsolete("Use " + nameof(EventArgsLocationObjectsChanged.Added))] + public IDictionary> NewObjects { get; } /********* ** Public methods *********/ /// Construct an instance. + /// The location which changed. + /// The objects added to the list. + /// The objects removed from the list. /// The current list of objects in the current location. - public EventArgsLocationObjectsChanged(IDictionary> newObjects) + public EventArgsLocationObjectsChanged(GameLocation location, IEnumerable> added, IEnumerable> removed, IDictionary> newObjects) { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); this.NewObjects = newObjects; } } diff --git a/src/SMAPI/Events/LocationEvents.cs b/src/SMAPI/Events/LocationEvents.cs index 81d13e9f..3ed09136 100644 --- a/src/SMAPI/Events/LocationEvents.cs +++ b/src/SMAPI/Events/LocationEvents.cs @@ -31,12 +31,20 @@ namespace StardewModdingAPI.Events } /// Raised after the list of objects in the current location changes (e.g. an object is added or removed). + [Obsolete("Use " + nameof(LocationEvents) + "." + nameof(LocationEvents.ObjectsChanged) + " instead")] public static event EventHandler LocationObjectsChanged { add => LocationEvents.EventManager.Location_LocationObjectsChanged.Add(value); remove => LocationEvents.EventManager.Location_LocationObjectsChanged.Remove(value); } + /// Raised after the list of objects in a location changes (e.g. an object is added or removed). + public static event EventHandler ObjectsChanged + { + add => LocationEvents.EventManager.Location_ObjectsChanged.Add(value); + remove => LocationEvents.EventManager.Location_ObjectsChanged.Remove(value); + } + /********* ** Public methods diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 87ff760f..9030ba97 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -1,3 +1,4 @@ +using System; using System.Diagnostics.CodeAnalysis; using Microsoft.Xna.Framework.Input; using StardewModdingAPI.Events; @@ -114,8 +115,12 @@ namespace StardewModdingAPI.Framework.Events public readonly ManagedEvent Location_LocationsChanged; /// Raised after the list of objects in the current location changes (e.g. an object is added or removed). + [Obsolete] public readonly ManagedEvent Location_LocationObjectsChanged; + /// Raised after the list of objects in a location changes (e.g. an object is added or removed). + public readonly ManagedEvent Location_ObjectsChanged; + /**** ** MenuEvents ****/ @@ -239,6 +244,7 @@ namespace StardewModdingAPI.Framework.Events this.Location_CurrentLocationChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.CurrentLocationChanged)); this.Location_LocationsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); this.Location_LocationObjectsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationObjectsChanged)); + this.Location_ObjectsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.ObjectsChanged)); this.Menu_Changed = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuChanged)); this.Menu_Closed = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuClosed)); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 78d07fbf..d2ba85f8 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -93,7 +93,10 @@ namespace StardewModdingAPI.Framework private readonly IValueWatcher SaveIdWatcher; /// Tracks changes to the location list. - private readonly ICollectionWatcher LocationsWatcher; + private readonly ICollectionWatcher LocationListWatcher; + + /// Tracks changes to each location. + private readonly IDictionary LocationWatchers = new Dictionary(); /// Tracks changes to . private readonly IValueWatcher ActiveMenuWatcher; @@ -162,14 +165,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.LocationsWatcher = WatcherFactory.ForObservableCollection((ObservableCollection)Game1.locations); + this.LocationListWatcher = WatcherFactory.ForObservableCollection((ObservableCollection)Game1.locations); this.Watchers.AddRange(new IWatcher[] { this.SaveIdWatcher, this.WindowSizeWatcher, this.TimeWatcher, this.ActiveMenuWatcher, - this.LocationsWatcher + this.LocationListWatcher }); } @@ -349,6 +352,22 @@ namespace StardewModdingAPI.Framework 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); + } + /********* ** Locale changed events *********/ @@ -509,12 +528,12 @@ namespace StardewModdingAPI.Framework } // raise location list changed - if (this.LocationsWatcher.IsChanged) + if (this.LocationListWatcher.IsChanged) { if (this.VerboseLogging) { - string added = this.LocationsWatcher.Added.Any() ? string.Join(", ", this.LocationsWatcher.Added.Select(p => p.Name)) : "none"; - string removed = this.LocationsWatcher.Removed.Any() ? string.Join(", ", this.LocationsWatcher.Removed.Select(p => p.Name)) : "none"; + 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); } @@ -524,6 +543,20 @@ namespace StardewModdingAPI.Framework // raise events that shouldn't be triggered on initial load if (!this.SaveIdWatcher.IsChanged) { + // 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(); + + this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed, watcher.Location.netObjects.FieldDict)); + } + } + // raise player leveled up a skill foreach (KeyValuePair> pair in curPlayer.GetChangedSkills()) { @@ -542,12 +575,16 @@ namespace StardewModdingAPI.Framework } // raise current location's object list changed - if (curPlayer.TryGetLocationChanges(out IDictionaryWatcher _)) { - if (this.VerboseLogging) - this.Monitor.Log("Context: current location objects changed.", LogLevel.Trace); + if (curPlayer.TryGetLocationChanges(out IDictionaryWatcher 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(curPlayer.GetCurrentLocation().netObjects.FieldDict)); + this.Events.Location_LocationObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, watcher.Added, watcher.Removed, location.netObjects.FieldDict)); + } } // raise time changed @@ -570,9 +607,14 @@ namespace StardewModdingAPI.Framework // update state this.CurrentPlayerTracker?.Reset(); - this.LocationsWatcher.Reset(); + this.LocationListWatcher.Reset(); 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/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs new file mode 100644 index 00000000..8cf4e7a2 --- /dev/null +++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using StardewModdingAPI.Framework.StateTracking.FieldWatchers; +using StardewValley; +using Object = StardewValley.Object; + +namespace StardewModdingAPI.Framework.StateTracking +{ + /// Tracks changes to a location's data. + internal class LocationTracker : IWatcher + { + /********* + ** Properties + *********/ + /// 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 changes to the current location's objects. + public IDictionaryWatcher LocationObjectsWatcher { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location to track. + public LocationTracker(GameLocation location) + { + this.Location = location; + + // init watchers + this.LocationObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects); + this.Watchers.AddRange(new[] + { + this.LocationObjectsWatcher + }); + } + + /// 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(); + } + + /// Set the current value as the baseline. + public void Reset() + { + foreach (IWatcher watcher in this.Watchers) + watcher.Reset(); + } + } +} diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 1822b134..9f04887c 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -148,6 +148,7 @@ + -- cgit From b8fd3aedfe884741bdda8c68398427f875585456 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 5 May 2018 01:31:06 -0400 Subject: rewrite location events for multiplayer --- docs/release-notes.md | 12 +- .../Events/EventArgsCurrentLocationChanged.cs | 31 --- src/SMAPI/Events/EventArgsGameLocationsChanged.cs | 27 --- src/SMAPI/Events/EventArgsIntChanged.cs | 3 +- .../Events/EventArgsLocationBuildingsChanged.cs | 39 ++++ .../Events/EventArgsLocationObjectsChanged.cs | 18 +- src/SMAPI/Events/EventArgsLocationsChanged.cs | 33 +++ src/SMAPI/Events/EventArgsPlayerWarped.cs | 32 +++ src/SMAPI/Events/LocationEvents.cs | 20 +- src/SMAPI/Events/PlayerEvents.cs | 10 +- src/SMAPI/Framework/Events/EventManager.cs | 22 +- src/SMAPI/Framework/SGame.cs | 158 +++++++-------- .../FieldWatchers/NetCollectionWatcher.cs | 93 +++++++++ .../StateTracking/FieldWatchers/WatcherFactory.cs | 8 + .../Framework/StateTracking/LocationTracker.cs | 21 +- src/SMAPI/Framework/StateTracking/PlayerTracker.cs | 32 --- .../StateTracking/WorldLocationsTracker.cs | 221 +++++++++++++++++++++ src/SMAPI/StardewModdingAPI.csproj | 7 +- 18 files changed, 566 insertions(+), 221 deletions(-) delete mode 100644 src/SMAPI/Events/EventArgsCurrentLocationChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsGameLocationsChanged.cs create mode 100644 src/SMAPI/Events/EventArgsLocationBuildingsChanged.cs create mode 100644 src/SMAPI/Events/EventArgsLocationsChanged.cs create mode 100644 src/SMAPI/Events/EventArgsPlayerWarped.cs create mode 100644 src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs create mode 100644 src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 00ed6e9c..ece388c7 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,7 +12,11 @@ * For modders: * Added code analysis to mod build config package to flag common issues as warnings. - * Added `LocationEvents.ObjectsChanged`, raised when an object is added/removed in any location. + * Replaced `LocationEvents` with a more powerful set of events for multiplayer: + * now raised for all locations; + * now includes added/removed building interiors; + * each event now provides a list of added/removed values; + * added buildings-changed event. * Added `Context.IsMultiplayer` and `Context.IsMainPlayer` flags. * Added `Constants.TargetPlatform` which says whether the game is running on Linux, Mac, or Windows. * Added `semanticVersion.IsPrerelease()` method. @@ -21,8 +25,10 @@ * Fixed assets not reloaded consistently when the player switches language. * Fixed console command input not saved to the log. * Fixed `helper.ModRegistry.GetApi` interface validation errors not mentioning which interface caused the issue. - * **Breaking change**: dropped some deprecated APIs. - * **Breaking change**: mods can't intercept chatbox input, including the game's hotkeys to toggle the chatbox (default `T` and `?`). + * **Breaking changes** (see [migration guide](https://stardewvalleywiki.com/Modding:Migrate_to_Stardew_Valley_1.3)): + * dropped some deprecated APIs; + * `LocationEvents` have been rewritten (see above); + * mods can't intercept chatbox input, including the game's hotkeys to toggle the chatbox (default `T` and `?`). * In console commands: * Added `player_add name`, which lets you add items to your inventory by name instead of ID. diff --git a/src/SMAPI/Events/EventArgsCurrentLocationChanged.cs b/src/SMAPI/Events/EventArgsCurrentLocationChanged.cs deleted file mode 100644 index 25d3ebf3..00000000 --- a/src/SMAPI/Events/EventArgsCurrentLocationChanged.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using StardewValley; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsCurrentLocationChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The player's current location. - public GameLocation NewLocation { get; } - - /// The player's previous location. - public GameLocation PriorLocation { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The player's previous location. - /// The player's current location. - public EventArgsCurrentLocationChanged(GameLocation priorLocation, GameLocation newLocation) - { - this.NewLocation = newLocation; - this.PriorLocation = priorLocation; - } - } -} 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 -{ - /// Event arguments for a event. - public class EventArgsGameLocationsChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The current list of game locations. - public IList NewLocations { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The current list of game locations. - public EventArgsGameLocationsChanged(IList 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 /// The current value. 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 +{ + /// Event arguments for a event. + public class EventArgsLocationBuildingsChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The buildings added to the location. + public IEnumerable Added { get; } + + /// The buildings removed from the location. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The buildings added to the location. + /// The buildings removed from the location. + public EventArgsLocationBuildingsChanged(GameLocation location, IEnumerable added, IEnumerable 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 { - /// Event arguments for a or event. + /// Event arguments for a event. public class EventArgsLocationObjectsChanged : EventArgs { /********* @@ -17,31 +17,25 @@ namespace StardewModdingAPI.Events /// The location which changed. public GameLocation Location { get; } - /// The objects added to the list. + /// The objects added to the location. public IEnumerable> Added { get; } - /// The objects removed from the list. + /// The objects removed from the location. public IEnumerable> Removed { get; } - /// The current list of objects in the current location. - [Obsolete("Use " + nameof(EventArgsLocationObjectsChanged.Added))] - public IDictionary> NewObjects { get; } - /********* ** Public methods *********/ /// Construct an instance. /// The location which changed. - /// The objects added to the list. - /// The objects removed from the list. - /// The current list of objects in the current location. - public EventArgsLocationObjectsChanged(GameLocation location, IEnumerable> added, IEnumerable> removed, IDictionary> newObjects) + /// The objects added to the location. + /// The objects removed from the location. + public EventArgsLocationObjectsChanged(GameLocation location, IEnumerable> added, IEnumerable> 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 +{ + /// Event arguments for a event. + public class EventArgsLocationsChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// The added locations. + public IEnumerable Added { get; } + + /// The removed locations. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The added locations. + /// The removed locations. + public EventArgsLocationsChanged(IEnumerable added, IEnumerable removed) + { + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/EventArgsPlayerWarped.cs b/src/SMAPI/Events/EventArgsPlayerWarped.cs new file mode 100644 index 00000000..93026aea --- /dev/null +++ b/src/SMAPI/Events/EventArgsPlayerWarped.cs @@ -0,0 +1,32 @@ +using System; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class EventArgsPlayerWarped : EventArgs + { + /********* + ** Accessors + *********/ + /// The player's previous location. + public GameLocation PriorLocation { get; } + + /// The player's current location. + public GameLocation NewLocation { get; } + + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The player's previous location. + /// The player's current location. + 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 *********/ - /// Raised after the player warps to a new location. - public static event EventHandler CurrentLocationChanged - { - add => LocationEvents.EventManager.Location_CurrentLocationChanged.Add(value); - remove => LocationEvents.EventManager.Location_CurrentLocationChanged.Remove(value); - } - /// Raised after a game location is added or removed. - public static event EventHandler LocationsChanged + public static event EventHandler LocationsChanged { add => LocationEvents.EventManager.Location_LocationsChanged.Add(value); remove => LocationEvents.EventManager.Location_LocationsChanged.Remove(value); } - /// Raised after the list of objects in the current location changes (e.g. an object is added or removed). - [Obsolete("Use " + nameof(LocationEvents) + "." + nameof(LocationEvents.ObjectsChanged) + " instead")] - public static event EventHandler LocationObjectsChanged + /// Raised after buildings are added or removed in a location. + public static event EventHandler 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); } - /// Raised after the list of objects in a location changes (e.g. an object is added or removed). + /// Raised after objects are added or removed in a location. public static event EventHandler 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); } - /// 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. + /// 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. public static event EventHandler LeveledUp { add => PlayerEvents.EventManager.Player_LeveledUp.Add(value); remove => PlayerEvents.EventManager.Player_LeveledUp.Remove(value); } + /// Raised after the player warps to a new location. + public static event EventHandler 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 ****/ - /// Raised after the player warps to a new location. - public readonly ManagedEvent Location_CurrentLocationChanged; - /// Raised after a game location is added or removed. - public readonly ManagedEvent Location_LocationsChanged; + public readonly ManagedEvent Location_LocationsChanged; - /// Raised after the list of objects in the current location changes (e.g. an object is added or removed). - [Obsolete] - public readonly ManagedEvent Location_LocationObjectsChanged; + /// Raised after buildings are added or removed in a location. + public readonly ManagedEvent Location_BuildingsChanged; - /// Raised after the list of objects in a location changes (e.g. an object is added or removed). + /// Raised after objects are added or removed in a location. public readonly ManagedEvent Location_ObjectsChanged; /**** @@ -160,6 +156,10 @@ namespace StardewModdingAPI.Framework.Events /// 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. public readonly ManagedEvent Player_LeveledUp; + /// Raised after the player warps to a new location. + public readonly ManagedEvent Player_Warped; + + /**** ** SaveEvents ****/ @@ -241,9 +241,8 @@ namespace StardewModdingAPI.Framework.Events this.Input_ButtonPressed = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonPressed)); this.Input_ButtonReleased = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonReleased)); - this.Location_CurrentLocationChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.CurrentLocationChanged)); - this.Location_LocationsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); - this.Location_LocationObjectsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationObjectsChanged)); + this.Location_LocationsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); + this.Location_BuildingsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.BuildingsChanged)); this.Location_ObjectsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.ObjectsChanged)); this.Menu_Changed = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuChanged)); @@ -258,6 +257,7 @@ namespace StardewModdingAPI.Framework.Events this.Player_InventoryChanged = ManageEventOf(nameof(PlayerEvents), nameof(PlayerEvents.InventoryChanged)); this.Player_LeveledUp = ManageEventOf(nameof(PlayerEvents), nameof(PlayerEvents.LeveledUp)); + this.Player_Warped = ManageEventOf(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 /// Tracks changes to the save ID. private readonly IValueWatcher SaveIdWatcher; - /// Tracks changes to the location list. - private readonly ICollectionWatcher LocationListWatcher; - - /// Tracks changes to each location. - private readonly IDictionary LocationWatchers = new Dictionary(); + /// Tracks changes to the game's locations. + private readonly WorldLocationsTracker LocationsWatcher; /// Tracks changes to . private readonly IValueWatcher 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)Game1.locations); + this.LocationsWatcher = new WorldLocationsTracker((ObservableCollection)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 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 +{ + /// A watcher which detects changes to a Netcode collection. + internal class NetCollectionWatcher : BaseDisposableWatcher, ICollectionWatcher + where TValue : INetObject + { + /********* + ** Properties + *********/ + /// The field being watched. + private readonly NetCollection Field; + + /// The pairs added since the last reset. + private readonly List AddedImpl = new List(); + + /// The pairs demoved since the last reset. + private readonly List RemovedImpl = new List(); + + + /********* + ** Accessors + *********/ + /// Whether the collection changed since the last reset. + public bool IsChanged => this.AddedImpl.Count > 0 || this.RemovedImpl.Count > 0; + + /// The values added since the last reset. + public IEnumerable Added => this.AddedImpl; + + /// The values removed since the last reset. + public IEnumerable Removed => this.RemovedImpl; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The field to watch. + public NetCollectionWatcher(NetCollection field) + { + this.Field = field; + field.OnValueAdded += this.OnValueAdded; + field.OnValueRemoved += this.OnValueRemoved; + } + + /// Update the current value if needed. + public void Update() + { + this.AssertNotDisposed(); + } + + /// Set the current value as the baseline. + public void Reset() + { + this.AssertNotDisposed(); + + this.AddedImpl.Clear(); + this.RemovedImpl.Clear(); + } + + /// Stop watching the field and release all references. + public override void Dispose() + { + if (!this.IsDisposed) + { + this.Field.OnValueAdded -= this.OnValueAdded; + this.Field.OnValueRemoved -= this.OnValueRemoved; + } + + base.Dispose(); + } + + + /********* + ** Private methods + *********/ + /// A callback invoked when an entry is added to the collection. + /// The added value. + private void OnValueAdded(TValue value) + { + this.AddedImpl.Add(value); + } + + /// A callback invoked when an entry is removed from the collection. + /// The added value. + private void OnValueRemoved(TValue value) + { + this.RemovedImpl.Add(value); + } + } +} diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs index bf261bb5..a4982faa 100644 --- a/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs +++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs @@ -36,6 +36,14 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers return new ObservableCollectionWatcher(collection); } + /// Get a watcher for a net collection. + /// The value type. + /// The net collection. + public static NetCollectionWatcher ForNetCollection(NetCollection collection) where T : INetObject + { + return new NetCollectionWatcher(collection); + } + /// Get a watcher for a net dictionary. /// The dictionary key type. /// The dictionary value type. diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs index 8cf4e7a2..07570401 100644 --- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs +++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs @@ -1,8 +1,11 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using Microsoft.Xna.Framework; using StardewModdingAPI.Framework.StateTracking.FieldWatchers; using StardewValley; +using StardewValley.Buildings; +using StardewValley.Locations; using Object = StardewValley.Object; namespace StardewModdingAPI.Framework.StateTracking @@ -26,8 +29,11 @@ namespace StardewModdingAPI.Framework.StateTracking /// The tracked location. public GameLocation Location { get; } - /// Tracks changes to the current location's objects. - public IDictionaryWatcher LocationObjectsWatcher { get; } + /// Tracks changes to the location's buildings. + public ICollectionWatcher BuildingsWatcher { get; } + + /// Tracks changes to the location's objects. + public IDictionaryWatcher ObjectsWatcher { get; } /********* @@ -40,10 +46,15 @@ namespace StardewModdingAPI.Framework.StateTracking this.Location = location; // init watchers - this.LocationObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects); - this.Watchers.AddRange(new[] + this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects); + this.BuildingsWatcher = location is BuildableGameLocation buildableLocation + ? WatcherFactory.ForNetCollection(buildableLocation.buildings) + : (ICollectionWatcher)WatcherFactory.ForObservableCollection(new ObservableCollection()); + + this.Watchers.AddRange(new IWatcher[] { - this.LocationObjectsWatcher + this.BuildingsWatcher, + this.ObjectsWatcher }); } diff --git a/src/SMAPI/Framework/StateTracking/PlayerTracker.cs b/src/SMAPI/Framework/StateTracking/PlayerTracker.cs index 032705b7..dea2e30d 100644 --- a/src/SMAPI/Framework/StateTracking/PlayerTracker.cs +++ b/src/SMAPI/Framework/StateTracking/PlayerTracker.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Xna.Framework; using StardewModdingAPI.Events; using StardewModdingAPI.Framework.StateTracking.FieldWatchers; using StardewValley; using StardewValley.Locations; -using SObject = StardewValley.Object; namespace StardewModdingAPI.Framework.StateTracking { @@ -38,9 +36,6 @@ namespace StardewModdingAPI.Framework.StateTracking /// The player's current location. public IValueWatcher LocationWatcher { get; } - /// Tracks changes to the player's current location's objects. - public IDictionaryWatcher LocationObjectsWatcher { get; private set; } - /// The player's current mine level. public IValueWatcher MineLevelWatcher { get; } @@ -61,7 +56,6 @@ namespace StardewModdingAPI.Framework.StateTracking // init trackers this.LocationWatcher = WatcherFactory.ForReference(this.GetCurrentLocation); - this.LocationObjectsWatcher = WatcherFactory.ForNetDictionary(this.GetCurrentLocation().netObjects); this.MineLevelWatcher = WatcherFactory.ForEquatable(() => this.LastValidLocation is MineShaft mine ? mine.mineLevel : 0); this.SkillWatchers = new Dictionary> { @@ -77,7 +71,6 @@ namespace StardewModdingAPI.Framework.StateTracking this.Watchers.AddRange(new IWatcher[] { this.LocationWatcher, - this.LocationObjectsWatcher, this.MineLevelWatcher }); this.Watchers.AddRange(this.SkillWatchers.Values); @@ -93,16 +86,6 @@ namespace StardewModdingAPI.Framework.StateTracking foreach (IWatcher watcher in this.Watchers) watcher.Update(); - // replace location objects watcher - if (this.LocationWatcher.IsChanged) - { - this.Watchers.Remove(this.LocationObjectsWatcher); - this.LocationObjectsWatcher.Dispose(); - - this.LocationObjectsWatcher = WatcherFactory.ForNetDictionary(this.GetCurrentLocation().netObjects); - this.Watchers.Add(this.LocationObjectsWatcher); - } - // update inventory this.CurrentInventory = this.GetInventory(); } @@ -154,21 +137,6 @@ namespace StardewModdingAPI.Framework.StateTracking return this.LocationWatcher.IsChanged; } - /// Get object changes to the player's current location if they there as of the last reset. - /// The object change watcher. - /// Returns whether it changed. - public bool TryGetLocationChanges(out IDictionaryWatcher watcher) - { - if (this.LocationWatcher.IsChanged) - { - watcher = null; - return false; - } - - watcher = this.LocationObjectsWatcher; - return watcher.IsChanged; - } - /// Get the player's new mine level if it changed. /// The player's current mine level. /// Returns whether it changed. diff --git a/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs b/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs new file mode 100644 index 00000000..d9090c08 --- /dev/null +++ b/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs @@ -0,0 +1,221 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using StardewModdingAPI.Framework.StateTracking.FieldWatchers; +using StardewValley; +using StardewValley.Buildings; +using StardewValley.Locations; + +namespace StardewModdingAPI.Framework.StateTracking +{ + /// Detects changes to the game's locations. + internal class WorldLocationsTracker : IWatcher + { + /********* + ** Properties + *********/ + /// Tracks changes to the location list. + private readonly ICollectionWatcher LocationListWatcher; + + /// A lookup of the tracked locations. + private IDictionary LocationDict { get; } = new Dictionary(); + + /// A lookup of registered buildings and their indoor location. + private readonly IDictionary BuildingIndoors = new Dictionary(); + + + /********* + ** Accessors + *********/ + /// Whether locations were added or removed since the last reset. + public bool IsLocationListChanged => this.Added.Any() || this.Removed.Any(); + + /// Whether any tracked location data changed since the last reset. + public bool IsChanged => this.IsLocationListChanged || this.Locations.Any(p => p.IsChanged); + + /// The tracked locations. + public IEnumerable Locations => this.LocationDict.Values; + + /// The locations removed since the last update. + public ICollection Added { get; } = new HashSet(); + + /// The locations added since the last update. + public ICollection Removed { get; } = new HashSet(); + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The game's list of locations. + public WorldLocationsTracker(ObservableCollection locations) + { + this.LocationListWatcher = WatcherFactory.ForObservableCollection(locations); + } + + /// Update the current value if needed. + public void Update() + { + // detect location changes + if (this.LocationListWatcher.IsChanged) + { + this.Remove(this.LocationListWatcher.Removed); + this.Add(this.LocationListWatcher.Added); + } + + // detect building changes + foreach (LocationTracker watcher in this.Locations.ToArray()) + { + if (watcher.BuildingsWatcher.IsChanged) + { + this.Remove(watcher.BuildingsWatcher.Removed); + this.Add(watcher.BuildingsWatcher.Added); + } + } + + // detect building interior changed (e.g. construction completed) + foreach (KeyValuePair pair in this.BuildingIndoors.Where(p => !object.Equals(p.Key.indoors.Value, p.Value))) + { + GameLocation oldIndoors = pair.Value; + GameLocation newIndoors = pair.Key.indoors.Value; + + if (oldIndoors != null) + this.Added.Add(oldIndoors); + if (newIndoors != null) + this.Removed.Add(newIndoors); + } + + // update watchers + foreach (IWatcher watcher in this.Locations) + watcher.Update(); + } + + /// Set the current location list as the baseline. + public void ResetLocationList() + { + this.Removed.Clear(); + this.Added.Clear(); + this.LocationListWatcher.Reset(); + } + + /// Set the current value as the baseline. + public void Reset() + { + this.ResetLocationList(); + foreach (IWatcher watcher in this.Locations) + watcher.Reset(); + } + + /// Stop watching the player fields and release all references. + public void Dispose() + { + this.LocationListWatcher.Dispose(); + foreach (IWatcher watcher in this.Locations) + watcher.Dispose(); + } + + + /********* + ** Private methods + *********/ + /**** + ** Enumerable wrappers + ****/ + /// Add the given buildings. + /// The buildings to add. + public void Add(IEnumerable buildings) + { + foreach (Building building in buildings) + this.Add(building); + } + + /// Add the given locations. + /// The locations to add. + public void Add(IEnumerable locations) + { + foreach (GameLocation location in locations) + this.Add(location); + } + + /// Remove the given buildings. + /// The buildings to remove. + public void Remove(IEnumerable buildings) + { + foreach (Building building in buildings) + this.Remove(building); + } + + /// Remove the given locations. + /// The locations to remove. + public void Remove(IEnumerable locations) + { + foreach (GameLocation location in locations) + this.Remove(location); + } + + /**** + ** Main add/remove logic + ****/ + /// Add the given building. + /// The building to add. + public void Add(Building building) + { + if (building == null) + return; + + GameLocation indoors = building.indoors.Value; + this.BuildingIndoors[building] = indoors; + this.Add(indoors); + } + + /// Add the given location. + /// The location to add. + public void Add(GameLocation location) + { + if (location == null) + return; + + // remove old location if needed + this.Remove(location); + + // track change + this.Added.Add(location); + + // add + this.LocationDict[location] = new LocationTracker(location); + if (location is BuildableGameLocation buildableLocation) + this.Add(buildableLocation.buildings); + } + + /// Remove the given building. + /// The building to remove. + public void Remove(Building building) + { + if (building == null) + return; + + this.BuildingIndoors.Remove(building); + this.Remove(building.indoors.Value); + } + + /// Remove the given location. + /// The location to remove. + public void Remove(GameLocation location) + { + if (location == null) + return; + + if (this.LocationDict.TryGetValue(location, out LocationTracker watcher)) + { + // track change + this.Removed.Add(location); + + // remove + this.LocationDict.Remove(location); + watcher.Dispose(); + if (location is BuildableGameLocation buildableLocation) + this.Remove(buildableLocation.buildings); + } + } + } +} diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 9f04887c..54fe9385 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -85,6 +85,7 @@ Properties\GlobalAssemblyInfo.cs + @@ -142,12 +143,14 @@ + + @@ -175,8 +178,8 @@ - - + + -- cgit From 558fb8a865b638cf5536856e7dcab44823feeaf3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 31 May 2018 22:47:56 -0400 Subject: move location events into new event system (#310) --- .../Events/EventArgsLocationObjectsChanged.cs | 1 - src/SMAPI/Events/IModEvents.cs | 9 ++++ src/SMAPI/Events/IWorldEvents.cs | 20 ++++++++ src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs | 39 +++++++++++++++ src/SMAPI/Events/WorldLocationsChangedEventArgs.cs | 33 +++++++++++++ src/SMAPI/Events/WorldObjectsChangedEventArgs.cs | 40 ++++++++++++++++ src/SMAPI/Framework/Events/EventManager.cs | 26 ++++++++-- src/SMAPI/Framework/Events/ManagedEvent.cs | 20 +++++++- src/SMAPI/Framework/Events/ManagedEventBase.cs | 9 ++-- src/SMAPI/Framework/Events/ModEvents.cs | 26 ++++++++++ src/SMAPI/Framework/Events/ModWorldEvents.cs | 56 ++++++++++++++++++++++ src/SMAPI/Framework/ModHelpers/ModHelper.cs | 16 +++++-- src/SMAPI/Framework/SGame.cs | 3 ++ src/SMAPI/IModHelper.cs | 5 ++ src/SMAPI/Program.cs | 3 +- src/SMAPI/StardewModdingAPI.csproj | 7 +++ 16 files changed, 297 insertions(+), 16 deletions(-) create mode 100644 src/SMAPI/Events/IModEvents.cs create mode 100644 src/SMAPI/Events/IWorldEvents.cs create mode 100644 src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs create mode 100644 src/SMAPI/Events/WorldLocationsChangedEventArgs.cs create mode 100644 src/SMAPI/Events/WorldObjectsChangedEventArgs.cs create mode 100644 src/SMAPI/Framework/Events/ModEvents.cs create mode 100644 src/SMAPI/Framework/Events/ModWorldEvents.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs index 410ef6e6..3bb387d5 100644 --- a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs +++ b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; -using Netcode; using StardewValley; using SObject = StardewValley.Object; diff --git a/src/SMAPI/Events/IModEvents.cs b/src/SMAPI/Events/IModEvents.cs new file mode 100644 index 00000000..99e5523f --- /dev/null +++ b/src/SMAPI/Events/IModEvents.cs @@ -0,0 +1,9 @@ +namespace StardewModdingAPI.Events +{ + /// Manages access to events raised by SMAPI. + public interface IModEvents + { + /// Events raised when something changes in the world. + IWorldEvents World { get; } + } +} diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs new file mode 100644 index 00000000..5c713250 --- /dev/null +++ b/src/SMAPI/Events/IWorldEvents.cs @@ -0,0 +1,20 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// Provides events raised when something changes in the world. + public interface IWorldEvents + { + /********* + ** Events + *********/ + /// Raised after a game location is added or removed. + event EventHandler LocationsChanged; + + /// Raised after buildings are added or removed in a location. + event EventHandler BuildingsChanged; + + /// Raised after objects are added or removed in a location. + event EventHandler ObjectsChanged; + } +} diff --git a/src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs b/src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs new file mode 100644 index 00000000..1f68fd02 --- /dev/null +++ b/src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; +using StardewValley.Buildings; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldBuildingsChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The buildings added to the location. + public IEnumerable Added { get; } + + /// The buildings removed from the location. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The buildings added to the location. + /// The buildings removed from the location. + public WorldBuildingsChangedEventArgs(GameLocation location, IEnumerable added, IEnumerable removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/WorldLocationsChangedEventArgs.cs b/src/SMAPI/Events/WorldLocationsChangedEventArgs.cs new file mode 100644 index 00000000..5cf77959 --- /dev/null +++ b/src/SMAPI/Events/WorldLocationsChangedEventArgs.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldLocationsChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The added locations. + public IEnumerable Added { get; } + + /// The removed locations. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The added locations. + /// The removed locations. + public WorldLocationsChangedEventArgs(IEnumerable added, IEnumerable removed) + { + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/WorldObjectsChangedEventArgs.cs b/src/SMAPI/Events/WorldObjectsChangedEventArgs.cs new file mode 100644 index 00000000..fb20acd4 --- /dev/null +++ b/src/SMAPI/Events/WorldObjectsChangedEventArgs.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using StardewValley; +using Object = StardewValley.Object; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldObjectsChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The objects added to the location. + public IEnumerable> Added { get; } + + /// The objects removed from the location. + public IEnumerable> Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The objects added to the location. + /// The objects removed from the location. + public WorldObjectsChangedEventArgs(GameLocation location, IEnumerable> added, IEnumerable> removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 84036127..53ea699a 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics.CodeAnalysis; using Microsoft.Xna.Framework.Input; using StardewModdingAPI.Events; @@ -10,7 +9,23 @@ namespace StardewModdingAPI.Framework.Events internal class EventManager { /********* - ** Properties + ** Events (new) + *********/ + /**** + ** World + ****/ + /// Raised after a game location is added or removed. + public readonly ManagedEvent World_LocationsChanged; + + /// Raised after buildings are added or removed in a location. + public readonly ManagedEvent World_BuildingsChanged; + + /// Raised after objects are added or removed in a location. + public readonly ManagedEvent World_ObjectsChanged; + + + /********* + ** Events (old) *********/ /**** ** ContentEvents @@ -209,7 +224,12 @@ namespace StardewModdingAPI.Framework.Events ManagedEvent ManageEventOf(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); ManagedEvent ManageEvent(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); - // init events + // init events (new) + this.World_BuildingsChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationsChanged)); + this.World_LocationsChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.BuildingsChanged)); + this.World_ObjectsChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ObjectsChanged)); + + // init events (old) this.Content_LocaleChanged = ManageEventOf>(nameof(ContentEvents), nameof(ContentEvents.AfterLocaleChanged)); this.Control_ControllerButtonPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerButtonPressed)); diff --git a/src/SMAPI/Framework/Events/ManagedEvent.cs b/src/SMAPI/Framework/Events/ManagedEvent.cs index e54a4fd3..c1ebf6c7 100644 --- a/src/SMAPI/Framework/Events/ManagedEvent.cs +++ b/src/SMAPI/Framework/Events/ManagedEvent.cs @@ -27,9 +27,17 @@ namespace StardewModdingAPI.Framework.Events /// Add an event handler. /// The event handler. public void Add(EventHandler handler) + { + this.Add(handler, this.ModRegistry.GetFromStack()); + } + + /// Add an event handler. + /// The event handler. + /// The mod which added the event handler. + public void Add(EventHandler handler, IModMetadata mod) { this.Event += handler; - this.AddTracking(handler, this.Event?.GetInvocationList().Cast>()); + this.AddTracking(mod, handler, this.Event?.GetInvocationList().Cast>()); } /// Remove an event handler. @@ -84,9 +92,17 @@ namespace StardewModdingAPI.Framework.Events /// Add an event handler. /// The event handler. public void Add(EventHandler handler) + { + this.Add(handler, this.ModRegistry.GetFromStack()); + } + + /// Add an event handler. + /// The event handler. + /// The mod which added the event handler. + public void Add(EventHandler handler, IModMetadata mod) { this.Event += handler; - this.AddTracking(handler, this.Event?.GetInvocationList().Cast()); + this.AddTracking(mod, handler, this.Event?.GetInvocationList().Cast()); } /// Remove an event handler. diff --git a/src/SMAPI/Framework/Events/ManagedEventBase.cs b/src/SMAPI/Framework/Events/ManagedEventBase.cs index 7e42d613..f3a278dc 100644 --- a/src/SMAPI/Framework/Events/ManagedEventBase.cs +++ b/src/SMAPI/Framework/Events/ManagedEventBase.cs @@ -17,7 +17,7 @@ namespace StardewModdingAPI.Framework.Events private readonly IMonitor Monitor; /// The mod registry with which to identify mods. - private readonly ModRegistry ModRegistry; + protected readonly ModRegistry ModRegistry; /// The display names for the mods which added each delegate. private readonly IDictionary SourceMods = new Dictionary(); @@ -50,11 +50,12 @@ namespace StardewModdingAPI.Framework.Events } /// Track an event handler. + /// The mod which added the handler. /// The event handler. /// The updated event invocation list. - protected void AddTracking(TEventHandler handler, IEnumerable invocationList) + protected void AddTracking(IModMetadata mod, TEventHandler handler, IEnumerable invocationList) { - this.SourceMods[handler] = this.ModRegistry.GetFromStack(); + this.SourceMods[handler] = mod; this.CachedInvocationList = invocationList?.ToArray() ?? new TEventHandler[0]; } @@ -64,7 +65,7 @@ namespace StardewModdingAPI.Framework.Events protected void RemoveTracking(TEventHandler handler, IEnumerable invocationList) { this.CachedInvocationList = invocationList?.ToArray() ?? new TEventHandler[0]; - if(!this.CachedInvocationList.Contains(handler)) // don't remove if there's still a reference to the removed handler (e.g. it was added twice and removed once) + if (!this.CachedInvocationList.Contains(handler)) // don't remove if there's still a reference to the removed handler (e.g. it was added twice and removed once) this.SourceMods.Remove(handler); } diff --git a/src/SMAPI/Framework/Events/ModEvents.cs b/src/SMAPI/Framework/Events/ModEvents.cs new file mode 100644 index 00000000..cc4cf8d7 --- /dev/null +++ b/src/SMAPI/Framework/Events/ModEvents.cs @@ -0,0 +1,26 @@ +using StardewModdingAPI.Events; + +namespace StardewModdingAPI.Framework.Events +{ + /// Manages access to events raised by SMAPI. + internal class ModEvents : IModEvents + { + /********* + ** Accessors + *********/ + /// Events raised when something changes in the world. + public IWorldEvents World { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The mod which uses this instance. + /// The underlying event manager. + public ModEvents(IModMetadata mod, EventManager eventManager) + { + this.World = new ModWorldEvents(mod, eventManager); + } + } +} diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs new file mode 100644 index 00000000..a76a7eb5 --- /dev/null +++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs @@ -0,0 +1,56 @@ +using System; +using StardewModdingAPI.Events; + +namespace StardewModdingAPI.Framework.Events +{ + /// Events raised when something changes in the world. + public class ModWorldEvents : IWorldEvents + { + /********* + ** Properties + *********/ + /// The underlying event manager. + private readonly EventManager EventManager; + + /// The mod which uses this instance. + private readonly IModMetadata Mod; + + + /********* + ** Accessors + *********/ + /// Raised after a game location is added or removed. + public event EventHandler LocationsChanged + { + add => this.EventManager.World_LocationsChanged.Add(value, this.Mod); + remove => this.EventManager.World_LocationsChanged.Remove(value); + } + + /// Raised after buildings are added or removed in a location. + public event EventHandler BuildingsChanged + { + add => this.EventManager.World_BuildingsChanged.Add(value, this.Mod); + remove => this.EventManager.World_BuildingsChanged.Remove(value); + } + + /// Raised after objects are added or removed in a location. + public event EventHandler ObjectsChanged + { + add => this.EventManager.World_ObjectsChanged.Add(value); + remove => this.EventManager.World_ObjectsChanged.Remove(value); + } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The mod which uses this instance. + /// The underlying event manager. + internal ModWorldEvents(IModMetadata mod, EventManager eventManager) + { + this.Mod = mod; + this.EventManager = eventManager; + } + } +} diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs index 26fe7198..92cb9d94 100644 --- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using StardewModdingAPI.Events; using StardewModdingAPI.Framework.Models; using StardewModdingAPI.Framework.Serialisation; using StardewModdingAPI.Framework.Utilities; @@ -33,6 +34,9 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The full path to the mod's folder. public string DirectoryPath { get; } + /// Manages access to events raised by SMAPI, which let your mod react when something happens in the game. + public IModEvents Events { get; } + /// An API for loading content assets. public IContentHelper Content { get; } @@ -59,6 +63,7 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The mod's unique ID. /// The full path to the mod's folder. /// Encapsulate SMAPI's JSON parsing. + /// Manages access to events raised by SMAPI. /// An API for loading content assets. /// An API for managing console commands. /// an API for fetching metadata about loaded mods. @@ -70,7 +75,7 @@ namespace StardewModdingAPI.Framework.ModHelpers /// Manages deprecation warnings. /// An argument is null or empty. /// The path does not exist on disk. - public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, IContentHelper contentHelper, ICommandHelper commandHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper, IEnumerable contentPacks, Func createContentPack, DeprecationManager deprecationManager) + public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, IModEvents events, IContentHelper contentHelper, ICommandHelper commandHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper, IEnumerable contentPacks, Func createContentPack, DeprecationManager deprecationManager) : base(modID) { // validate directory @@ -91,6 +96,7 @@ namespace StardewModdingAPI.Framework.ModHelpers this.ContentPacks = contentPacks.ToArray(); this.CreateContentPack = createContentPack; this.DeprecationManager = deprecationManager; + this.Events = events; } /**** @@ -157,13 +163,13 @@ namespace StardewModdingAPI.Framework.ModHelpers this.DeprecationManager.Warn($"{nameof(IModHelper)}.{nameof(IModHelper.CreateTransitionalContentPack)}", "2.5", DeprecationLevel.Notice); // validate - if(string.IsNullOrWhiteSpace(directoryPath)) + if (string.IsNullOrWhiteSpace(directoryPath)) throw new ArgumentNullException(nameof(directoryPath)); - if(string.IsNullOrWhiteSpace(id)) + if (string.IsNullOrWhiteSpace(id)) throw new ArgumentNullException(nameof(id)); - if(string.IsNullOrWhiteSpace(name)) + if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name)); - if(!Directory.Exists(directoryPath)) + if (!Directory.Exists(directoryPath)) throw new ArgumentException($"Can't create content pack for directory path '{directoryPath}' because no such directory exists."); // create manifest diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 369f1f40..e7e9f74f 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -543,6 +543,7 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Context: location list changed (added {addedText}; removed {removedText}).", LogLevel.Trace); } + this.Events.World_LocationsChanged.Raise(new WorldLocationsChangedEventArgs(added, removed)); this.Events.Location_LocationsChanged.Raise(new EventArgsLocationsChanged(added, removed)); } @@ -559,6 +560,7 @@ namespace StardewModdingAPI.Framework var removed = watcher.ObjectsWatcher.Removed.ToArray(); watcher.ObjectsWatcher.Reset(); + this.Events.World_ObjectsChanged.Raise(new WorldObjectsChangedEventArgs(location, added, removed)); this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); } @@ -570,6 +572,7 @@ namespace StardewModdingAPI.Framework var removed = watcher.BuildingsWatcher.Removed.ToArray(); watcher.BuildingsWatcher.Reset(); + this.Events.World_BuildingsChanged.Raise(new WorldBuildingsChangedEventArgs(location, added, removed)); this.Events.Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); } } diff --git a/src/SMAPI/IModHelper.cs b/src/SMAPI/IModHelper.cs index 5e39161d..68c2f1c4 100644 --- a/src/SMAPI/IModHelper.cs +++ b/src/SMAPI/IModHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using StardewModdingAPI.Events; namespace StardewModdingAPI { @@ -12,6 +13,10 @@ namespace StardewModdingAPI /// The full path to the mod's folder. string DirectoryPath { get; } + /// Manages access to events raised by SMAPI, which let your mod react when something happens in the game. + [Obsolete("This is an experimental interface which may change at any time. Don't depend on this for released mods.")] + IModEvents Events { get; } + /// An API for loading content assets. IContentHelper Content { get; } diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 844dc5d8..48ad922b 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -840,6 +840,7 @@ namespace StardewModdingAPI IMonitor monitor = this.GetSecondaryMonitor(metadata.DisplayName); IModHelper modHelper; { + IModEvents events = new ModEvents(metadata, this.EventManager); ICommandHelper commandHelper = new CommandHelper(manifest.UniqueID, metadata.DisplayName, this.CommandManager); IContentHelper contentHelper = new ContentHelper(contentCore, metadata.DirectoryPath, manifest.UniqueID, metadata.DisplayName, monitor); IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, metadata.DisplayName, this.Reflection, this.DeprecationManager); @@ -854,7 +855,7 @@ namespace StardewModdingAPI return new ContentPack(packDirPath, packManifest, packContentHelper, this.JsonHelper); } - modHelper = new ModHelper(manifest.UniqueID, metadata.DirectoryPath, jsonHelper, contentHelper, commandHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper, contentPacks, CreateTransitionalContentPack, this.DeprecationManager); + modHelper = new ModHelper(manifest.UniqueID, metadata.DirectoryPath, jsonHelper, events, contentHelper, commandHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper, contentPacks, CreateTransitionalContentPack, this.DeprecationManager); } // init mod diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index e9e0ea54..6a062930 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -86,17 +86,23 @@ Properties\GlobalAssemblyInfo.cs + + + + + + @@ -129,6 +135,7 @@ + -- cgit From cca7bf197079975bf310ca90c03b78d0f77fdf02 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 1 Jun 2018 01:15:26 -0400 Subject: rename new events for clarity (#310) --- src/SMAPI/Events/IWorldEvents.cs | 6 ++-- .../Events/WorldBuildingListChangedEventArgs.cs | 39 +++++++++++++++++++++ src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs | 39 --------------------- .../Events/WorldLocationListChangedEventArgs.cs | 33 ++++++++++++++++++ src/SMAPI/Events/WorldLocationsChangedEventArgs.cs | 33 ------------------ .../Events/WorldObjectListChangedEventArgs.cs | 40 ++++++++++++++++++++++ src/SMAPI/Events/WorldObjectsChangedEventArgs.cs | 40 ---------------------- src/SMAPI/Framework/Events/EventManager.cs | 12 +++---- src/SMAPI/Framework/Events/ModWorldEvents.cs | 18 +++++----- src/SMAPI/Framework/SGame.cs | 6 ++-- src/SMAPI/StardewModdingAPI.csproj | 6 ++-- 11 files changed, 136 insertions(+), 136 deletions(-) create mode 100644 src/SMAPI/Events/WorldBuildingListChangedEventArgs.cs delete mode 100644 src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs create mode 100644 src/SMAPI/Events/WorldLocationListChangedEventArgs.cs delete mode 100644 src/SMAPI/Events/WorldLocationsChangedEventArgs.cs create mode 100644 src/SMAPI/Events/WorldObjectListChangedEventArgs.cs delete mode 100644 src/SMAPI/Events/WorldObjectsChangedEventArgs.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs index 5c713250..a9a5fe6b 100644 --- a/src/SMAPI/Events/IWorldEvents.cs +++ b/src/SMAPI/Events/IWorldEvents.cs @@ -9,12 +9,12 @@ namespace StardewModdingAPI.Events ** Events *********/ /// Raised after a game location is added or removed. - event EventHandler LocationsChanged; + event EventHandler LocationListChanged; /// Raised after buildings are added or removed in a location. - event EventHandler BuildingsChanged; + event EventHandler BuildingListChanged; /// Raised after objects are added or removed in a location. - event EventHandler ObjectsChanged; + event EventHandler ObjectListChanged; } } diff --git a/src/SMAPI/Events/WorldBuildingListChangedEventArgs.cs b/src/SMAPI/Events/WorldBuildingListChangedEventArgs.cs new file mode 100644 index 00000000..e73b9396 --- /dev/null +++ b/src/SMAPI/Events/WorldBuildingListChangedEventArgs.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; +using StardewValley.Buildings; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldBuildingListChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The buildings added to the location. + public IEnumerable Added { get; } + + /// The buildings removed from the location. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The buildings added to the location. + /// The buildings removed from the location. + public WorldBuildingListChangedEventArgs(GameLocation location, IEnumerable added, IEnumerable removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs b/src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs deleted file mode 100644 index 1f68fd02..00000000 --- a/src/SMAPI/Events/WorldBuildingsChangedEventArgs.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using StardewValley; -using StardewValley.Buildings; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class WorldBuildingsChangedEventArgs : EventArgs - { - /********* - ** Accessors - *********/ - /// The location which changed. - public GameLocation Location { get; } - - /// The buildings added to the location. - public IEnumerable Added { get; } - - /// The buildings removed from the location. - public IEnumerable Removed { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The location which changed. - /// The buildings added to the location. - /// The buildings removed from the location. - public WorldBuildingsChangedEventArgs(GameLocation location, IEnumerable added, IEnumerable removed) - { - this.Location = location; - this.Added = added.ToArray(); - this.Removed = removed.ToArray(); - } - } -} diff --git a/src/SMAPI/Events/WorldLocationListChangedEventArgs.cs b/src/SMAPI/Events/WorldLocationListChangedEventArgs.cs new file mode 100644 index 00000000..8bc26a43 --- /dev/null +++ b/src/SMAPI/Events/WorldLocationListChangedEventArgs.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldLocationListChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The added locations. + public IEnumerable Added { get; } + + /// The removed locations. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The added locations. + /// The removed locations. + public WorldLocationListChangedEventArgs(IEnumerable added, IEnumerable removed) + { + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/WorldLocationsChangedEventArgs.cs b/src/SMAPI/Events/WorldLocationsChangedEventArgs.cs deleted file mode 100644 index 5cf77959..00000000 --- a/src/SMAPI/Events/WorldLocationsChangedEventArgs.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using StardewValley; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class WorldLocationsChangedEventArgs : EventArgs - { - /********* - ** Accessors - *********/ - /// The added locations. - public IEnumerable Added { get; } - - /// The removed locations. - public IEnumerable Removed { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The added locations. - /// The removed locations. - public WorldLocationsChangedEventArgs(IEnumerable added, IEnumerable removed) - { - this.Added = added.ToArray(); - this.Removed = removed.ToArray(); - } - } -} diff --git a/src/SMAPI/Events/WorldObjectListChangedEventArgs.cs b/src/SMAPI/Events/WorldObjectListChangedEventArgs.cs new file mode 100644 index 00000000..5623a49b --- /dev/null +++ b/src/SMAPI/Events/WorldObjectListChangedEventArgs.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using StardewValley; +using Object = StardewValley.Object; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldObjectListChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The objects added to the location. + public IEnumerable> Added { get; } + + /// The objects removed from the location. + public IEnumerable> Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The objects added to the location. + /// The objects removed from the location. + public WorldObjectListChangedEventArgs(GameLocation location, IEnumerable> added, IEnumerable> removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/WorldObjectsChangedEventArgs.cs b/src/SMAPI/Events/WorldObjectsChangedEventArgs.cs deleted file mode 100644 index fb20acd4..00000000 --- a/src/SMAPI/Events/WorldObjectsChangedEventArgs.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Xna.Framework; -using StardewValley; -using Object = StardewValley.Object; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class WorldObjectsChangedEventArgs : EventArgs - { - /********* - ** Accessors - *********/ - /// The location which changed. - public GameLocation Location { get; } - - /// The objects added to the location. - public IEnumerable> Added { get; } - - /// The objects removed from the location. - public IEnumerable> Removed { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The location which changed. - /// The objects added to the location. - /// The objects removed from the location. - public WorldObjectsChangedEventArgs(GameLocation location, IEnumerable> added, IEnumerable> removed) - { - this.Location = location; - this.Added = added.ToArray(); - this.Removed = removed.ToArray(); - } - } -} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 53ea699a..0e1e6241 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -15,13 +15,13 @@ namespace StardewModdingAPI.Framework.Events ** World ****/ /// Raised after a game location is added or removed. - public readonly ManagedEvent World_LocationsChanged; + public readonly ManagedEvent World_LocationListChanged; /// Raised after buildings are added or removed in a location. - public readonly ManagedEvent World_BuildingsChanged; + public readonly ManagedEvent World_BuildingListChanged; /// Raised after objects are added or removed in a location. - public readonly ManagedEvent World_ObjectsChanged; + public readonly ManagedEvent World_ObjectListChanged; /********* @@ -225,9 +225,9 @@ namespace StardewModdingAPI.Framework.Events ManagedEvent ManageEvent(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); // init events (new) - this.World_BuildingsChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationsChanged)); - this.World_LocationsChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.BuildingsChanged)); - this.World_ObjectsChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ObjectsChanged)); + this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); + this.World_LocationListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.BuildingListChanged)); + this.World_ObjectListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged)); // init events (old) this.Content_LocaleChanged = ManageEventOf>(nameof(ContentEvents), nameof(ContentEvents.AfterLocaleChanged)); diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs index a76a7eb5..7036b765 100644 --- a/src/SMAPI/Framework/Events/ModWorldEvents.cs +++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs @@ -20,24 +20,24 @@ namespace StardewModdingAPI.Framework.Events ** Accessors *********/ /// Raised after a game location is added or removed. - public event EventHandler LocationsChanged + public event EventHandler LocationListChanged { - add => this.EventManager.World_LocationsChanged.Add(value, this.Mod); - remove => this.EventManager.World_LocationsChanged.Remove(value); + add => this.EventManager.World_LocationListChanged.Add(value, this.Mod); + remove => this.EventManager.World_LocationListChanged.Remove(value); } /// Raised after buildings are added or removed in a location. - public event EventHandler BuildingsChanged + public event EventHandler BuildingListChanged { - add => this.EventManager.World_BuildingsChanged.Add(value, this.Mod); - remove => this.EventManager.World_BuildingsChanged.Remove(value); + add => this.EventManager.World_BuildingListChanged.Add(value, this.Mod); + remove => this.EventManager.World_BuildingListChanged.Remove(value); } /// Raised after objects are added or removed in a location. - public event EventHandler ObjectsChanged + public event EventHandler ObjectListChanged { - add => this.EventManager.World_ObjectsChanged.Add(value); - remove => this.EventManager.World_ObjectsChanged.Remove(value); + add => this.EventManager.World_ObjectListChanged.Add(value); + remove => this.EventManager.World_ObjectListChanged.Remove(value); } diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index e7e9f74f..9442c749 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -543,7 +543,7 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Context: location list changed (added {addedText}; removed {removedText}).", LogLevel.Trace); } - this.Events.World_LocationsChanged.Raise(new WorldLocationsChangedEventArgs(added, removed)); + this.Events.World_LocationListChanged.Raise(new WorldLocationListChangedEventArgs(added, removed)); this.Events.Location_LocationsChanged.Raise(new EventArgsLocationsChanged(added, removed)); } @@ -560,7 +560,7 @@ namespace StardewModdingAPI.Framework var removed = watcher.ObjectsWatcher.Removed.ToArray(); watcher.ObjectsWatcher.Reset(); - this.Events.World_ObjectsChanged.Raise(new WorldObjectsChangedEventArgs(location, added, removed)); + this.Events.World_ObjectListChanged.Raise(new WorldObjectListChangedEventArgs(location, added, removed)); this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); } @@ -572,7 +572,7 @@ namespace StardewModdingAPI.Framework var removed = watcher.BuildingsWatcher.Removed.ToArray(); watcher.BuildingsWatcher.Reset(); - this.Events.World_BuildingsChanged.Raise(new WorldBuildingsChangedEventArgs(location, added, removed)); + this.Events.World_BuildingListChanged.Raise(new WorldBuildingListChangedEventArgs(location, added, removed)); this.Events.Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); } } diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 6a062930..951a9e6b 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -88,9 +88,9 @@ - - - + + + -- cgit From b3f116a8f123387b1f2f9ce1a099d1fd8081708d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 1 Jun 2018 01:58:31 -0400 Subject: add terrain feature list changed event (#310) --- src/SMAPI/Events/IWorldEvents.cs | 3 ++ .../WorldTerrainFeatureListChangedEventArgs.cs | 40 ++++++++++++++++++++++ src/SMAPI/Framework/Events/EventManager.cs | 4 +++ src/SMAPI/Framework/Events/ModWorldEvents.cs | 7 ++++ src/SMAPI/Framework/SGame.cs | 22 +++++++++--- .../Framework/StateTracking/LocationTracker.cs | 12 +++++-- src/SMAPI/StardewModdingAPI.csproj | 1 + 7 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 src/SMAPI/Events/WorldTerrainFeatureListChangedEventArgs.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs index a9a5fe6b..7ec26bae 100644 --- a/src/SMAPI/Events/IWorldEvents.cs +++ b/src/SMAPI/Events/IWorldEvents.cs @@ -16,5 +16,8 @@ namespace StardewModdingAPI.Events /// Raised after objects are added or removed in a location. event EventHandler ObjectListChanged; + + /// Raised after terrain features are added or removed in a location. + event EventHandler TerrainFeatureListChanged; } } diff --git a/src/SMAPI/Events/WorldTerrainFeatureListChangedEventArgs.cs b/src/SMAPI/Events/WorldTerrainFeatureListChangedEventArgs.cs new file mode 100644 index 00000000..cb089811 --- /dev/null +++ b/src/SMAPI/Events/WorldTerrainFeatureListChangedEventArgs.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using StardewValley; +using StardewValley.TerrainFeatures; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldTerrainFeatureListChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The terrain features added to the location. + public IEnumerable> Added { get; } + + /// The terrain features removed from the location. + public IEnumerable> Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The terrain features added to the location. + /// The terrain features removed from the location. + public WorldTerrainFeatureListChangedEventArgs(GameLocation location, IEnumerable> added, IEnumerable> removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 0e1e6241..c909c1bd 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -23,6 +23,9 @@ namespace StardewModdingAPI.Framework.Events /// Raised after objects are added or removed in a location. public readonly ManagedEvent World_ObjectListChanged; + /// Raised after terrain features are added or removed in a location. + public readonly ManagedEvent World_TerrainFeatureListChanged; + /********* ** Events (old) @@ -228,6 +231,7 @@ namespace StardewModdingAPI.Framework.Events this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); this.World_LocationListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.BuildingListChanged)); this.World_ObjectListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged)); + this.World_TerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.TerrainFeatureListChanged)); // init events (old) this.Content_LocaleChanged = ManageEventOf>(nameof(ContentEvents), nameof(ContentEvents.AfterLocaleChanged)); diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs index 7036b765..14646c5d 100644 --- a/src/SMAPI/Framework/Events/ModWorldEvents.cs +++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs @@ -40,6 +40,13 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.World_ObjectListChanged.Remove(value); } + /// Raised after terrain features are added or removed in a location. + public event EventHandler TerrainFeatureListChanged + { + add => this.EventManager.World_TerrainFeatureListChanged.Add(value); + remove => this.EventManager.World_TerrainFeatureListChanged.Remove(value); + } + /********* ** Public methods diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 9442c749..02d6dd2c 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -18,11 +18,14 @@ using StardewModdingAPI.Framework.StateTracking.FieldWatchers; using StardewModdingAPI.Framework.Utilities; using StardewValley; using StardewValley.BellsAndWhistles; +using StardewValley.Buildings; using StardewValley.Locations; using StardewValley.Menus; +using StardewValley.TerrainFeatures; using StardewValley.Tools; using xTile.Dimensions; using xTile.Layers; +using Object = StardewValley.Object; namespace StardewModdingAPI.Framework { @@ -556,8 +559,8 @@ namespace StardewModdingAPI.Framework if (watcher.ObjectsWatcher.IsChanged) { GameLocation location = watcher.Location; - var added = watcher.ObjectsWatcher.Added.ToArray(); - var removed = watcher.ObjectsWatcher.Removed.ToArray(); + KeyValuePair[] added = watcher.ObjectsWatcher.Added.ToArray(); + KeyValuePair[] removed = watcher.ObjectsWatcher.Removed.ToArray(); watcher.ObjectsWatcher.Reset(); this.Events.World_ObjectListChanged.Raise(new WorldObjectListChangedEventArgs(location, added, removed)); @@ -568,13 +571,24 @@ namespace StardewModdingAPI.Framework if (watcher.BuildingsWatcher.IsChanged) { GameLocation location = watcher.Location; - var added = watcher.BuildingsWatcher.Added.ToArray(); - var removed = watcher.BuildingsWatcher.Removed.ToArray(); + Building[] added = watcher.BuildingsWatcher.Added.ToArray(); + Building[] removed = watcher.BuildingsWatcher.Removed.ToArray(); watcher.BuildingsWatcher.Reset(); this.Events.World_BuildingListChanged.Raise(new WorldBuildingListChangedEventArgs(location, added, removed)); this.Events.Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); } + + // terrain features changed + if (watcher.TerrainFeaturesWatcher.IsChanged) + { + GameLocation location = watcher.Location; + KeyValuePair[] added = watcher.TerrainFeaturesWatcher.Added.ToArray(); + KeyValuePair[] removed = watcher.TerrainFeaturesWatcher.Removed.ToArray(); + watcher.TerrainFeaturesWatcher.Reset(); + + this.Events.World_TerrainFeatureListChanged.Raise(new WorldTerrainFeatureListChangedEventArgs(location, added, removed)); + } } } else diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs index 07570401..d31b1128 100644 --- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs +++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs @@ -6,6 +6,7 @@ using StardewModdingAPI.Framework.StateTracking.FieldWatchers; using StardewValley; using StardewValley.Buildings; using StardewValley.Locations; +using StardewValley.TerrainFeatures; using Object = StardewValley.Object; namespace StardewModdingAPI.Framework.StateTracking @@ -29,12 +30,15 @@ namespace StardewModdingAPI.Framework.StateTracking /// The tracked location. public GameLocation Location { get; } - /// Tracks changes to the location's buildings. + /// Tracks added or removed buildings. public ICollectionWatcher BuildingsWatcher { get; } - /// Tracks changes to the location's objects. + /// Tracks added or removed objects. public IDictionaryWatcher ObjectsWatcher { get; } + /// Tracks added or removed terrain features. + public IDictionaryWatcher TerrainFeaturesWatcher { get; } + /********* ** Public methods @@ -50,11 +54,13 @@ namespace StardewModdingAPI.Framework.StateTracking this.BuildingsWatcher = location is BuildableGameLocation buildableLocation ? WatcherFactory.ForNetCollection(buildableLocation.buildings) : (ICollectionWatcher)WatcherFactory.ForObservableCollection(new ObservableCollection()); + this.TerrainFeaturesWatcher = WatcherFactory.ForNetDictionary(location.terrainFeatures); this.Watchers.AddRange(new IWatcher[] { this.BuildingsWatcher, - this.ObjectsWatcher + this.ObjectsWatcher, + this.TerrainFeaturesWatcher }); } diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 951a9e6b..50d8c533 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -88,6 +88,7 @@ + -- cgit From 07bbfea7dd9dac5bbacf8bfc3c35d3f65ec71b75 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 1 Jun 2018 02:14:01 -0400 Subject: add NPC list changed event (#310) --- src/SMAPI/Events/IWorldEvents.cs | 3 ++ src/SMAPI/Events/WorldNpcListChangedEventArgs.cs | 38 ++++++++++++++++++++++ src/SMAPI/Framework/Events/EventManager.cs | 4 +++ src/SMAPI/Framework/Events/ModWorldEvents.cs | 7 ++++ src/SMAPI/Framework/SGame.cs | 35 +++++++++++++------- .../Framework/StateTracking/LocationTracker.cs | 7 +++- src/SMAPI/StardewModdingAPI.csproj | 1 + 7 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 src/SMAPI/Events/WorldNpcListChangedEventArgs.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs index 7ec26bae..ce288ae1 100644 --- a/src/SMAPI/Events/IWorldEvents.cs +++ b/src/SMAPI/Events/IWorldEvents.cs @@ -14,6 +14,9 @@ namespace StardewModdingAPI.Events /// Raised after buildings are added or removed in a location. event EventHandler BuildingListChanged; + /// Raised after NPCs are added or removed in a location. + event EventHandler NpcListChanged; + /// Raised after objects are added or removed in a location. event EventHandler ObjectListChanged; diff --git a/src/SMAPI/Events/WorldNpcListChangedEventArgs.cs b/src/SMAPI/Events/WorldNpcListChangedEventArgs.cs new file mode 100644 index 00000000..e251f894 --- /dev/null +++ b/src/SMAPI/Events/WorldNpcListChangedEventArgs.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldNpcListChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The NPCs added to the location. + public IEnumerable Added { get; } + + /// The NPCs removed from the location. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The NPCs added to the location. + /// The NPCs removed from the location. + public WorldNpcListChangedEventArgs(GameLocation location, IEnumerable added, IEnumerable removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index c909c1bd..cb331e7a 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -20,6 +20,9 @@ namespace StardewModdingAPI.Framework.Events /// Raised after buildings are added or removed in a location. public readonly ManagedEvent World_BuildingListChanged; + /// Raised after NPCs are added or removed in a location. + public readonly ManagedEvent World_NpcListChanged; + /// Raised after objects are added or removed in a location. public readonly ManagedEvent World_ObjectListChanged; @@ -230,6 +233,7 @@ namespace StardewModdingAPI.Framework.Events // init events (new) this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); this.World_LocationListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.BuildingListChanged)); + this.World_NpcListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.NpcListChanged)); this.World_ObjectListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged)); this.World_TerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.TerrainFeatureListChanged)); diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs index 14646c5d..ca851550 100644 --- a/src/SMAPI/Framework/Events/ModWorldEvents.cs +++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs @@ -33,6 +33,13 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.World_BuildingListChanged.Remove(value); } + /// Raised after NPCs are added or removed in a location. + public event EventHandler NpcListChanged + { + add => this.EventManager.World_NpcListChanged.Add(value); + remove => this.EventManager.World_NpcListChanged.Remove(value); + } + /// Raised after objects are added or removed in a location. public event EventHandler ObjectListChanged { diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 02d6dd2c..38f96566 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -555,18 +555,6 @@ namespace StardewModdingAPI.Framework { foreach (LocationTracker watcher in this.LocationsWatcher.Locations) { - // objects changed - if (watcher.ObjectsWatcher.IsChanged) - { - GameLocation location = watcher.Location; - KeyValuePair[] added = watcher.ObjectsWatcher.Added.ToArray(); - KeyValuePair[] removed = watcher.ObjectsWatcher.Removed.ToArray(); - watcher.ObjectsWatcher.Reset(); - - this.Events.World_ObjectListChanged.Raise(new WorldObjectListChangedEventArgs(location, added, removed)); - this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); - } - // buildings changed if (watcher.BuildingsWatcher.IsChanged) { @@ -579,6 +567,29 @@ namespace StardewModdingAPI.Framework this.Events.Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); } + // NPCs changed + if (watcher.NpcsWatcher.IsChanged) + { + GameLocation location = watcher.Location; + NPC[] added = watcher.NpcsWatcher.Added.ToArray(); + NPC[] removed = watcher.NpcsWatcher.Removed.ToArray(); + watcher.NpcsWatcher.Reset(); + + this.Events.World_NpcListChanged.Raise(new WorldNpcListChangedEventArgs(location, added, removed)); + } + + // objects changed + if (watcher.ObjectsWatcher.IsChanged) + { + GameLocation location = watcher.Location; + KeyValuePair[] added = watcher.ObjectsWatcher.Added.ToArray(); + KeyValuePair[] removed = watcher.ObjectsWatcher.Removed.ToArray(); + watcher.ObjectsWatcher.Reset(); + + this.Events.World_ObjectListChanged.Raise(new WorldObjectListChangedEventArgs(location, added, removed)); + this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); + } + // terrain features changed if (watcher.TerrainFeaturesWatcher.IsChanged) { diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs index d31b1128..4ac455ac 100644 --- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs +++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs @@ -33,6 +33,9 @@ namespace StardewModdingAPI.Framework.StateTracking /// Tracks added or removed buildings. public ICollectionWatcher BuildingsWatcher { get; } + /// Tracks added or removed NPCs. + public ICollectionWatcher NpcsWatcher { get; } + /// Tracks added or removed objects. public IDictionaryWatcher ObjectsWatcher { get; } @@ -50,15 +53,17 @@ namespace StardewModdingAPI.Framework.StateTracking this.Location = location; // init watchers - this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects); this.BuildingsWatcher = location is BuildableGameLocation buildableLocation ? WatcherFactory.ForNetCollection(buildableLocation.buildings) : (ICollectionWatcher)WatcherFactory.ForObservableCollection(new ObservableCollection()); + 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.NpcsWatcher, this.ObjectsWatcher, this.TerrainFeaturesWatcher }); diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 50d8c533..37b624fb 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -88,6 +88,7 @@ + -- cgit From 92006bd6ed20365f1ded4bd07387b0ba9ed0ff92 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 1 Jun 2018 23:16:42 -0400 Subject: add large terrain feature list changed event (#310) --- src/SMAPI/Events/IWorldEvents.cs | 5 ++- ...WorldLargeTerrainFeatureListChangedEventArgs.cs | 39 ++++++++++++++++++++++ src/SMAPI/Framework/Events/EventManager.cs | 6 +++- src/SMAPI/Framework/Events/ModWorldEvents.cs | 9 ++++- src/SMAPI/Framework/SGame.cs | 11 ++++++ .../Framework/StateTracking/LocationTracker.cs | 5 +++ src/SMAPI/StardewModdingAPI.csproj | 1 + 7 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/SMAPI/Events/WorldLargeTerrainFeatureListChangedEventArgs.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs index ce288ae1..6a43baf2 100644 --- a/src/SMAPI/Events/IWorldEvents.cs +++ b/src/SMAPI/Events/IWorldEvents.cs @@ -14,13 +14,16 @@ namespace StardewModdingAPI.Events /// Raised after buildings are added or removed in a location. event EventHandler BuildingListChanged; + /// Raised after large terrain features (like bushes) are added or removed in a location. + event EventHandler LargeTerrainFeatureListChanged; + /// Raised after NPCs are added or removed in a location. event EventHandler NpcListChanged; /// Raised after objects are added or removed in a location. event EventHandler ObjectListChanged; - /// Raised after terrain features are added or removed in a location. + /// Raised after terrain features (like floors and trees) are added or removed in a location. event EventHandler TerrainFeatureListChanged; } } diff --git a/src/SMAPI/Events/WorldLargeTerrainFeatureListChangedEventArgs.cs b/src/SMAPI/Events/WorldLargeTerrainFeatureListChangedEventArgs.cs new file mode 100644 index 00000000..053a0e41 --- /dev/null +++ b/src/SMAPI/Events/WorldLargeTerrainFeatureListChangedEventArgs.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; +using StardewValley.TerrainFeatures; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldLargeTerrainFeatureListChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The large terrain features added to the location. + public IEnumerable Added { get; } + + /// The large terrain features removed from the location. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The large terrain features added to the location. + /// The large terrain features removed from the location. + public WorldLargeTerrainFeatureListChangedEventArgs(GameLocation location, IEnumerable added, IEnumerable removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index cb331e7a..7ce8c640 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -20,13 +20,16 @@ namespace StardewModdingAPI.Framework.Events /// Raised after buildings are added or removed in a location. public readonly ManagedEvent World_BuildingListChanged; + /// Raised after large terrain features (like bushes) are added or removed in a location. + public readonly ManagedEvent World_LargeTerrainFeatureListChanged; + /// Raised after NPCs are added or removed in a location. public readonly ManagedEvent World_NpcListChanged; /// Raised after objects are added or removed in a location. public readonly ManagedEvent World_ObjectListChanged; - /// Raised after terrain features are added or removed in a location. + /// Raised after terrain features (like floors and trees) are added or removed in a location. public readonly ManagedEvent World_TerrainFeatureListChanged; @@ -232,6 +235,7 @@ namespace StardewModdingAPI.Framework.Events // init events (new) this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); + this.World_LargeTerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LargeTerrainFeatureListChanged)); this.World_LocationListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.BuildingListChanged)); this.World_NpcListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.NpcListChanged)); this.World_ObjectListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged)); diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs index ca851550..db03e447 100644 --- a/src/SMAPI/Framework/Events/ModWorldEvents.cs +++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs @@ -33,6 +33,13 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.World_BuildingListChanged.Remove(value); } + /// Raised after large terrain features (like bushes) are added or removed in a location. + public event EventHandler LargeTerrainFeatureListChanged + { + add => this.EventManager.World_LargeTerrainFeatureListChanged.Add(value, this.Mod); + remove => this.EventManager.World_LargeTerrainFeatureListChanged.Remove(value); + } + /// Raised after NPCs are added or removed in a location. public event EventHandler NpcListChanged { @@ -47,7 +54,7 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.World_ObjectListChanged.Remove(value); } - /// Raised after terrain features are added or removed in a location. + /// Raised after terrain features (like floors and trees) are added or removed in a location. public event EventHandler TerrainFeatureListChanged { add => this.EventManager.World_TerrainFeatureListChanged.Add(value); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 38f96566..90dbacfe 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -567,6 +567,17 @@ namespace StardewModdingAPI.Framework this.Events.Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); } + // large terrain features changed + if (watcher.LargeTerrainFeaturesWatcher.IsChanged) + { + GameLocation location = watcher.Location; + LargeTerrainFeature[] added = watcher.LargeTerrainFeaturesWatcher.Added.ToArray(); + LargeTerrainFeature[] removed = watcher.LargeTerrainFeaturesWatcher.Removed.ToArray(); + watcher.LargeTerrainFeaturesWatcher.Reset(); + + this.Events.World_LargeTerrainFeatureListChanged.Raise(new WorldLargeTerrainFeatureListChangedEventArgs(location, added, removed)); + } + // NPCs changed if (watcher.NpcsWatcher.IsChanged) { diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs index 4ac455ac..1b4c0b19 100644 --- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs +++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs @@ -33,6 +33,9 @@ namespace StardewModdingAPI.Framework.StateTracking /// Tracks added or removed buildings. public ICollectionWatcher BuildingsWatcher { get; } + /// Tracks added or removed large terrain features. + public ICollectionWatcher LargeTerrainFeaturesWatcher { get; } + /// Tracks added or removed NPCs. public ICollectionWatcher NpcsWatcher { get; } @@ -56,6 +59,7 @@ namespace StardewModdingAPI.Framework.StateTracking this.BuildingsWatcher = location is BuildableGameLocation buildableLocation ? WatcherFactory.ForNetCollection(buildableLocation.buildings) : (ICollectionWatcher)WatcherFactory.ForObservableCollection(new ObservableCollection()); + this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection(location.largeTerrainFeatures); this.NpcsWatcher = WatcherFactory.ForNetCollection(location.characters); this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects); this.TerrainFeaturesWatcher = WatcherFactory.ForNetDictionary(location.terrainFeatures); @@ -63,6 +67,7 @@ namespace StardewModdingAPI.Framework.StateTracking this.Watchers.AddRange(new IWatcher[] { this.BuildingsWatcher, + this.LargeTerrainFeaturesWatcher, this.NpcsWatcher, this.ObjectsWatcher, this.TerrainFeaturesWatcher diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 37b624fb..f9c93671 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -89,6 +89,7 @@ + -- cgit From a29e2c59d4a01d5b8828644efd6becabc59af28e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 2 Jun 2018 01:04:02 -0400 Subject: disambiguate legacy events internally (#310) --- src/SMAPI/Events/IWorldEvents.cs | 5 +---- src/SMAPI/Events/LocationEvents.cs | 12 ++++++------ src/SMAPI/Framework/Events/EventManager.cs | 12 ++++++------ src/SMAPI/Framework/SGame.cs | 6 +++--- 4 files changed, 16 insertions(+), 19 deletions(-) (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs index 6a43baf2..067a79bc 100644 --- a/src/SMAPI/Events/IWorldEvents.cs +++ b/src/SMAPI/Events/IWorldEvents.cs @@ -2,12 +2,9 @@ using System; namespace StardewModdingAPI.Events { - /// Provides events raised when something changes in the world. + /// Events raised when something changes in the world. public interface IWorldEvents { - /********* - ** Events - *********/ /// Raised after a game location is added or removed. event EventHandler LocationListChanged; diff --git a/src/SMAPI/Events/LocationEvents.cs b/src/SMAPI/Events/LocationEvents.cs index ff75c619..e2108de0 100644 --- a/src/SMAPI/Events/LocationEvents.cs +++ b/src/SMAPI/Events/LocationEvents.cs @@ -19,22 +19,22 @@ namespace StardewModdingAPI.Events /// Raised after a game location is added or removed. public static event EventHandler LocationsChanged { - add => LocationEvents.EventManager.Location_LocationsChanged.Add(value); - remove => LocationEvents.EventManager.Location_LocationsChanged.Remove(value); + add => LocationEvents.EventManager.Legacy_Location_LocationsChanged.Add(value); + remove => LocationEvents.EventManager.Legacy_Location_LocationsChanged.Remove(value); } /// Raised after buildings are added or removed in a location. public static event EventHandler BuildingsChanged { - add => LocationEvents.EventManager.Location_BuildingsChanged.Add(value); - remove => LocationEvents.EventManager.Location_BuildingsChanged.Remove(value); + add => LocationEvents.EventManager.Legacy_Location_BuildingsChanged.Add(value); + remove => LocationEvents.EventManager.Legacy_Location_BuildingsChanged.Remove(value); } /// Raised after objects are added or removed in a location. public static event EventHandler ObjectsChanged { - add => LocationEvents.EventManager.Location_ObjectsChanged.Add(value); - remove => LocationEvents.EventManager.Location_ObjectsChanged.Remove(value); + add => LocationEvents.EventManager.Legacy_Location_ObjectsChanged.Add(value); + remove => LocationEvents.EventManager.Legacy_Location_ObjectsChanged.Remove(value); } diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 7ce8c640..100e4e43 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -133,13 +133,13 @@ namespace StardewModdingAPI.Framework.Events ** LocationEvents ****/ /// Raised after a game location is added or removed. - public readonly ManagedEvent Location_LocationsChanged; + public readonly ManagedEvent Legacy_Location_LocationsChanged; /// Raised after buildings are added or removed in a location. - public readonly ManagedEvent Location_BuildingsChanged; + public readonly ManagedEvent Legacy_Location_BuildingsChanged; /// Raised after objects are added or removed in a location. - public readonly ManagedEvent Location_ObjectsChanged; + public readonly ManagedEvent Legacy_Location_ObjectsChanged; /**** ** MenuEvents @@ -273,9 +273,9 @@ namespace StardewModdingAPI.Framework.Events this.Input_ButtonPressed = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonPressed)); this.Input_ButtonReleased = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonReleased)); - this.Location_LocationsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); - this.Location_BuildingsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.BuildingsChanged)); - this.Location_ObjectsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.ObjectsChanged)); + this.Legacy_Location_LocationsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); + this.Legacy_Location_BuildingsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.BuildingsChanged)); + this.Legacy_Location_ObjectsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.ObjectsChanged)); this.Menu_Changed = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuChanged)); this.Menu_Closed = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuClosed)); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 90dbacfe..1611861f 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -547,7 +547,7 @@ namespace StardewModdingAPI.Framework } this.Events.World_LocationListChanged.Raise(new WorldLocationListChangedEventArgs(added, removed)); - this.Events.Location_LocationsChanged.Raise(new EventArgsLocationsChanged(added, removed)); + this.Events.Legacy_Location_LocationsChanged.Raise(new EventArgsLocationsChanged(added, removed)); } // raise location contents changed @@ -564,7 +564,7 @@ namespace StardewModdingAPI.Framework watcher.BuildingsWatcher.Reset(); this.Events.World_BuildingListChanged.Raise(new WorldBuildingListChangedEventArgs(location, added, removed)); - this.Events.Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); + this.Events.Legacy_Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); } // large terrain features changed @@ -598,7 +598,7 @@ namespace StardewModdingAPI.Framework watcher.ObjectsWatcher.Reset(); this.Events.World_ObjectListChanged.Raise(new WorldObjectListChangedEventArgs(location, added, removed)); - this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); + this.Events.Legacy_Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); } // terrain features changed -- cgit From 0df7a967a6980db7f4da8d393feae97c968e3375 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 2 Jun 2018 01:48:35 -0400 Subject: add new-style input events (#310) --- src/SMAPI/Events/ControlEvents.cs | 28 ++++++------ src/SMAPI/Events/EventArgsInput.cs | 10 ++--- src/SMAPI/Events/IInputEvents.cs | 14 ++++++ src/SMAPI/Events/IModEvents.cs | 3 ++ src/SMAPI/Events/InputButtonPressedEventArgs.cs | 56 ++++++++++++++++++++++++ src/SMAPI/Events/InputButtonReleasedEventArgs.cs | 56 ++++++++++++++++++++++++ src/SMAPI/Events/InputEvents.cs | 8 ++-- src/SMAPI/Framework/Events/EventManager.cs | 48 ++++++++++++-------- src/SMAPI/Framework/Events/ModEvents.cs | 4 ++ src/SMAPI/Framework/Events/ModInputEvents.cs | 36 +++++++++++++++ src/SMAPI/Framework/SGame.cs | 20 +++++---- src/SMAPI/StardewModdingAPI.csproj | 4 ++ 12 files changed, 235 insertions(+), 52 deletions(-) create mode 100644 src/SMAPI/Events/IInputEvents.cs create mode 100644 src/SMAPI/Events/InputButtonPressedEventArgs.cs create mode 100644 src/SMAPI/Events/InputButtonReleasedEventArgs.cs create mode 100644 src/SMAPI/Framework/Events/ModInputEvents.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/ControlEvents.cs b/src/SMAPI/Events/ControlEvents.cs index 973bb245..77bbf3ab 100644 --- a/src/SMAPI/Events/ControlEvents.cs +++ b/src/SMAPI/Events/ControlEvents.cs @@ -20,22 +20,22 @@ namespace StardewModdingAPI.Events /// Raised when the changes. That happens when the player presses or releases a key. public static event EventHandler KeyboardChanged { - add => ControlEvents.EventManager.Control_KeyboardChanged.Add(value); - remove => ControlEvents.EventManager.Control_KeyboardChanged.Remove(value); + add => ControlEvents.EventManager.Legacy_Control_KeyboardChanged.Add(value); + remove => ControlEvents.EventManager.Legacy_Control_KeyboardChanged.Remove(value); } /// Raised when the player presses a keyboard key. public static event EventHandler KeyPressed { - add => ControlEvents.EventManager.Control_KeyPressed.Add(value); - remove => ControlEvents.EventManager.Control_KeyPressed.Remove(value); + add => ControlEvents.EventManager.Legacy_Control_KeyPressed.Add(value); + remove => ControlEvents.EventManager.Legacy_Control_KeyPressed.Remove(value); } /// Raised when the player releases a keyboard key. public static event EventHandler KeyReleased { - add => ControlEvents.EventManager.Control_KeyReleased.Add(value); - remove => ControlEvents.EventManager.Control_KeyReleased.Remove(value); + add => ControlEvents.EventManager.Legacy_Control_KeyReleased.Add(value); + remove => ControlEvents.EventManager.Legacy_Control_KeyReleased.Remove(value); } /// Raised when the changes. That happens when the player moves the mouse, scrolls the mouse wheel, or presses/releases a button. @@ -48,29 +48,29 @@ namespace StardewModdingAPI.Events /// The player pressed a controller button. This event isn't raised for trigger buttons. public static event EventHandler ControllerButtonPressed { - add => ControlEvents.EventManager.Control_ControllerButtonPressed.Add(value); - remove => ControlEvents.EventManager.Control_ControllerButtonPressed.Remove(value); + add => ControlEvents.EventManager.Legacy_Control_ControllerButtonPressed.Add(value); + remove => ControlEvents.EventManager.Legacy_Control_ControllerButtonPressed.Remove(value); } /// The player released a controller button. This event isn't raised for trigger buttons. public static event EventHandler ControllerButtonReleased { - add => ControlEvents.EventManager.Control_ControllerButtonReleased.Add(value); - remove => ControlEvents.EventManager.Control_ControllerButtonReleased.Remove(value); + add => ControlEvents.EventManager.Legacy_Control_ControllerButtonReleased.Add(value); + remove => ControlEvents.EventManager.Legacy_Control_ControllerButtonReleased.Remove(value); } /// The player pressed a controller trigger button. public static event EventHandler ControllerTriggerPressed { - add => ControlEvents.EventManager.Control_ControllerTriggerPressed.Add(value); - remove => ControlEvents.EventManager.Control_ControllerTriggerPressed.Remove(value); + add => ControlEvents.EventManager.Legacy_Control_ControllerTriggerPressed.Add(value); + remove => ControlEvents.EventManager.Legacy_Control_ControllerTriggerPressed.Remove(value); } /// The player released a controller trigger button. public static event EventHandler ControllerTriggerReleased { - add => ControlEvents.EventManager.Control_ControllerTriggerReleased.Add(value); - remove => ControlEvents.EventManager.Control_ControllerTriggerReleased.Remove(value); + add => ControlEvents.EventManager.Legacy_Control_ControllerTriggerReleased.Add(value); + remove => ControlEvents.EventManager.Legacy_Control_ControllerTriggerReleased.Remove(value); } diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs index d60f4017..0cafdba5 100644 --- a/src/SMAPI/Events/EventArgsInput.cs +++ b/src/SMAPI/Events/EventArgsInput.cs @@ -23,10 +23,10 @@ namespace StardewModdingAPI.Events public ICursorPosition Cursor { get; } /// Whether the input should trigger actions on the affected tile. - public bool IsActionButton { get; } + public bool IsActionButton => this.Button.IsActionButton(); /// Whether the input should use tools on the affected tile. - public bool IsUseToolButton { get; } + public bool IsUseToolButton => this.Button.IsUseToolButton(); /// Whether a mod has indicated the key was already handled. public bool IsSuppressed => this.SuppressButtons.Contains(this.Button); @@ -38,15 +38,11 @@ namespace StardewModdingAPI.Events /// Construct an instance. /// The button on the controller, keyboard, or mouse. /// The cursor position. - /// Whether the input should trigger actions on the affected tile. - /// Whether the input should use tools on the affected tile. /// The buttons to suppress. - public EventArgsInput(SButton button, ICursorPosition cursor, bool isActionButton, bool isUseToolButton, HashSet suppressButtons) + public EventArgsInput(SButton button, ICursorPosition cursor, HashSet suppressButtons) { this.Button = button; this.Cursor = cursor; - this.IsActionButton = isActionButton; - this.IsUseToolButton = isUseToolButton; this.SuppressButtons = suppressButtons; } diff --git a/src/SMAPI/Events/IInputEvents.cs b/src/SMAPI/Events/IInputEvents.cs new file mode 100644 index 00000000..92802fda --- /dev/null +++ b/src/SMAPI/Events/IInputEvents.cs @@ -0,0 +1,14 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// Events raised when the player provides input using a controller, keyboard, or mouse. + public interface IInputEvents + { + /// Raised when the player presses a button on the keyboard, controller, or mouse. + event EventHandler ButtonPressed; + + /// Raised when the player releases a button on the keyboard, controller, or mouse. + event EventHandler ButtonReleased; + } +} diff --git a/src/SMAPI/Events/IModEvents.cs b/src/SMAPI/Events/IModEvents.cs index 99e5523f..16ec6557 100644 --- a/src/SMAPI/Events/IModEvents.cs +++ b/src/SMAPI/Events/IModEvents.cs @@ -3,6 +3,9 @@ namespace StardewModdingAPI.Events /// Manages access to events raised by SMAPI. public interface IModEvents { + /// Events raised when the player provides input using a controller, keyboard, or mouse. + IInputEvents Input { get; } + /// Events raised when something changes in the world. IWorldEvents World { get; } } diff --git a/src/SMAPI/Events/InputButtonPressedEventArgs.cs b/src/SMAPI/Events/InputButtonPressedEventArgs.cs new file mode 100644 index 00000000..c8d55cd4 --- /dev/null +++ b/src/SMAPI/Events/InputButtonPressedEventArgs.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; + +namespace StardewModdingAPI.Events +{ + /// Event arguments when a button is pressed. + public class InputButtonPressedArgsInput : EventArgs + { + /********* + ** Properties + *********/ + /// The buttons to suppress. + private readonly HashSet SuppressButtons; + + + /********* + ** Accessors + *********/ + /// The button on the controller, keyboard, or mouse. + public SButton Button { get; } + + /// The current cursor position. + public ICursorPosition Cursor { get; } + + /// Whether a mod has indicated the key was already handled. + public bool IsSuppressed => this.SuppressButtons.Contains(this.Button); + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The button on the controller, keyboard, or mouse. + /// The cursor position. + /// The buttons to suppress. + public InputButtonPressedArgsInput(SButton button, ICursorPosition cursor, HashSet suppressButtons) + { + this.Button = button; + this.Cursor = cursor; + this.SuppressButtons = suppressButtons; + } + + /// Prevent the game from handling the current button press. This doesn't prevent other mods from receiving the event. + public void SuppressButton() + { + this.SuppressButton(this.Button); + } + + /// Prevent the game from handling a button press. This doesn't prevent other mods from receiving the event. + /// The button to suppress. + public void SuppressButton(SButton button) + { + this.SuppressButtons.Add(button); + } + } +} diff --git a/src/SMAPI/Events/InputButtonReleasedEventArgs.cs b/src/SMAPI/Events/InputButtonReleasedEventArgs.cs new file mode 100644 index 00000000..863fab6a --- /dev/null +++ b/src/SMAPI/Events/InputButtonReleasedEventArgs.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; + +namespace StardewModdingAPI.Events +{ + /// Event arguments when a button is released. + public class InputButtonReleasedArgsInput : EventArgs + { + /********* + ** Properties + *********/ + /// The buttons to suppress. + private readonly HashSet SuppressButtons; + + + /********* + ** Accessors + *********/ + /// The button on the controller, keyboard, or mouse. + public SButton Button { get; } + + /// The current cursor position. + public ICursorPosition Cursor { get; } + + /// Whether a mod has indicated the key was already handled. + public bool IsSuppressed => this.SuppressButtons.Contains(this.Button); + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The button on the controller, keyboard, or mouse. + /// The cursor position. + /// The buttons to suppress. + public InputButtonReleasedArgsInput(SButton button, ICursorPosition cursor, HashSet suppressButtons) + { + this.Button = button; + this.Cursor = cursor; + this.SuppressButtons = suppressButtons; + } + + /// Prevent the game from handling the current button press. This doesn't prevent other mods from receiving the event. + public void SuppressButton() + { + this.SuppressButton(this.Button); + } + + /// Prevent the game from handling a button press. This doesn't prevent other mods from receiving the event. + /// The button to suppress. + public void SuppressButton(SButton button) + { + this.SuppressButtons.Add(button); + } + } +} diff --git a/src/SMAPI/Events/InputEvents.cs b/src/SMAPI/Events/InputEvents.cs index 84d7ce5d..e62d6ee6 100644 --- a/src/SMAPI/Events/InputEvents.cs +++ b/src/SMAPI/Events/InputEvents.cs @@ -19,15 +19,15 @@ namespace StardewModdingAPI.Events /// Raised when the player presses a button on the keyboard, controller, or mouse. public static event EventHandler ButtonPressed { - add => InputEvents.EventManager.Input_ButtonPressed.Add(value); - remove => InputEvents.EventManager.Input_ButtonPressed.Remove(value); + add => InputEvents.EventManager.Legacy_Input_ButtonPressed.Add(value); + remove => InputEvents.EventManager.Legacy_Input_ButtonPressed.Remove(value); } /// Raised when the player releases a keyboard key on the keyboard, controller, or mouse. public static event EventHandler ButtonReleased { - add => InputEvents.EventManager.Input_ButtonReleased.Add(value); - remove => InputEvents.EventManager.Input_ButtonReleased.Remove(value); + add => InputEvents.EventManager.Legacy_Input_ButtonReleased.Add(value); + remove => InputEvents.EventManager.Legacy_Input_ButtonReleased.Remove(value); } diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 100e4e43..62d9582e 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -32,6 +32,15 @@ namespace StardewModdingAPI.Framework.Events /// Raised after terrain features (like floors and trees) are added or removed in a location. public readonly ManagedEvent World_TerrainFeatureListChanged; + /**** + ** Input + ****/ + /// Raised when the player presses a button on the keyboard, controller, or mouse. + public readonly ManagedEvent Input_ButtonPressed; + + /// Raised when the player released a button on the keyboard, controller, or mouse. + public readonly ManagedEvent Input_ButtonReleased; + /********* ** Events (old) @@ -46,28 +55,28 @@ namespace StardewModdingAPI.Framework.Events ** ControlEvents ****/ /// Raised when the changes. That happens when the player presses or releases a key. - public readonly ManagedEvent Control_KeyboardChanged; + public readonly ManagedEvent Legacy_Control_KeyboardChanged; /// Raised when the player presses a keyboard key. - public readonly ManagedEvent Control_KeyPressed; + public readonly ManagedEvent Legacy_Control_KeyPressed; /// Raised when the player releases a keyboard key. - public readonly ManagedEvent Control_KeyReleased; + public readonly ManagedEvent Legacy_Control_KeyReleased; /// Raised when the changes. That happens when the player moves the mouse, scrolls the mouse wheel, or presses/releases a button. public readonly ManagedEvent Control_MouseChanged; /// The player pressed a controller button. This event isn't raised for trigger buttons. - public readonly ManagedEvent Control_ControllerButtonPressed; + public readonly ManagedEvent Legacy_Control_ControllerButtonPressed; /// The player released a controller button. This event isn't raised for trigger buttons. - public readonly ManagedEvent Control_ControllerButtonReleased; + public readonly ManagedEvent Legacy_Control_ControllerButtonReleased; /// The player pressed a controller trigger button. - public readonly ManagedEvent Control_ControllerTriggerPressed; + public readonly ManagedEvent Legacy_Control_ControllerTriggerPressed; /// The player released a controller trigger button. - public readonly ManagedEvent Control_ControllerTriggerReleased; + public readonly ManagedEvent Legacy_Control_ControllerTriggerReleased; /**** ** GameEvents @@ -124,10 +133,10 @@ namespace StardewModdingAPI.Framework.Events ** InputEvents ****/ /// Raised when the player presses a button on the keyboard, controller, or mouse. - public readonly ManagedEvent Input_ButtonPressed; + public readonly ManagedEvent Legacy_Input_ButtonPressed; /// Raised when the player releases a keyboard key on the keyboard, controller, or mouse. - public readonly ManagedEvent Input_ButtonReleased; + public readonly ManagedEvent Legacy_Input_ButtonReleased; /**** ** LocationEvents @@ -234,6 +243,9 @@ namespace StardewModdingAPI.Framework.Events ManagedEvent ManageEvent(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); // init events (new) + this.Input_ButtonPressed = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed)); + this.Input_ButtonReleased = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased)); + this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); this.World_LargeTerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LargeTerrainFeatureListChanged)); this.World_LocationListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.BuildingListChanged)); @@ -244,13 +256,13 @@ namespace StardewModdingAPI.Framework.Events // init events (old) this.Content_LocaleChanged = ManageEventOf>(nameof(ContentEvents), nameof(ContentEvents.AfterLocaleChanged)); - this.Control_ControllerButtonPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerButtonPressed)); - this.Control_ControllerButtonReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerButtonReleased)); - this.Control_ControllerTriggerPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerTriggerPressed)); - this.Control_ControllerTriggerReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerTriggerReleased)); - this.Control_KeyboardChanged = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyboardChanged)); - this.Control_KeyPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyPressed)); - this.Control_KeyReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyReleased)); + this.Legacy_Control_ControllerButtonPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerButtonPressed)); + this.Legacy_Control_ControllerButtonReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerButtonReleased)); + this.Legacy_Control_ControllerTriggerPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerTriggerPressed)); + this.Legacy_Control_ControllerTriggerReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerTriggerReleased)); + this.Legacy_Control_KeyboardChanged = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyboardChanged)); + this.Legacy_Control_KeyPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyPressed)); + this.Legacy_Control_KeyReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyReleased)); this.Control_MouseChanged = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.MouseChanged)); this.Game_FirstUpdateTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.FirstUpdateTick)); @@ -270,8 +282,8 @@ namespace StardewModdingAPI.Framework.Events this.Graphics_OnPreRenderGuiEvent = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.OnPreRenderGuiEvent)); this.Graphics_OnPostRenderGuiEvent = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.OnPostRenderGuiEvent)); - this.Input_ButtonPressed = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonPressed)); - this.Input_ButtonReleased = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonReleased)); + this.Legacy_Input_ButtonPressed = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonPressed)); + this.Legacy_Input_ButtonReleased = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonReleased)); this.Legacy_Location_LocationsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); this.Legacy_Location_BuildingsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.BuildingsChanged)); diff --git a/src/SMAPI/Framework/Events/ModEvents.cs b/src/SMAPI/Framework/Events/ModEvents.cs index cc4cf8d7..90853141 100644 --- a/src/SMAPI/Framework/Events/ModEvents.cs +++ b/src/SMAPI/Framework/Events/ModEvents.cs @@ -8,6 +8,9 @@ namespace StardewModdingAPI.Framework.Events /********* ** Accessors *********/ + /// Events raised when the player provides input using a controller, keyboard, or mouse. + public IInputEvents Input { get; } + /// Events raised when something changes in the world. public IWorldEvents World { get; } @@ -20,6 +23,7 @@ namespace StardewModdingAPI.Framework.Events /// The underlying event manager. public ModEvents(IModMetadata mod, EventManager eventManager) { + this.Input = new ModInputEvents(mod, eventManager); this.World = new ModWorldEvents(mod, eventManager); } } diff --git a/src/SMAPI/Framework/Events/ModInputEvents.cs b/src/SMAPI/Framework/Events/ModInputEvents.cs new file mode 100644 index 00000000..18baec16 --- /dev/null +++ b/src/SMAPI/Framework/Events/ModInputEvents.cs @@ -0,0 +1,36 @@ +using System; +using StardewModdingAPI.Events; + +namespace StardewModdingAPI.Framework.Events +{ + /// Events raised when the player provides input using a controller, keyboard, or mouse. + internal class ModInputEvents : ModEventsBase, IInputEvents + { + /********* + ** Accessors + *********/ + /// Raised when the player presses a button on the keyboard, controller, or mouse. + public event EventHandler ButtonPressed + { + add => this.EventManager.Input_ButtonPressed.Add(value); + remove => this.EventManager.Input_ButtonPressed.Remove(value); + } + + /// Raised when the player releases a button on the keyboard, controller, or mouse. + public event EventHandler ButtonReleased + { + add => this.EventManager.Input_ButtonReleased.Add(value); + remove => this.EventManager.Input_ButtonReleased.Remove(value); + } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The mod which uses this instance. + /// The underlying event manager. + internal ModInputEvents(IModMetadata mod, EventManager eventManager) + : base(mod, eventManager) { } + } +} diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 1611861f..f87293c2 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -459,45 +459,47 @@ namespace StardewModdingAPI.Framework if (status == InputStatus.Pressed) { - this.Events.Input_ButtonPressed.Raise(new EventArgsInput(button, cursor, button.IsActionButton(), button.IsUseToolButton(), inputState.SuppressButtons)); + this.Events.Input_ButtonPressed.Raise(new InputButtonPressedArgsInput(button, cursor, inputState.SuppressButtons)); + this.Events.Legacy_Input_ButtonPressed.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons)); // legacy events if (button.TryGetKeyboard(out Keys key)) { if (key != Keys.None) - this.Events.Control_KeyPressed.Raise(new EventArgsKeyPressed(key)); + this.Events.Legacy_Control_KeyPressed.Raise(new EventArgsKeyPressed(key)); } else if (button.TryGetController(out Buttons controllerButton)) { if (controllerButton == Buttons.LeftTrigger || controllerButton == Buttons.RightTrigger) - this.Events.Control_ControllerTriggerPressed.Raise(new EventArgsControllerTriggerPressed(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.RealController.Triggers.Left : inputState.RealController.Triggers.Right)); + this.Events.Legacy_Control_ControllerTriggerPressed.Raise(new EventArgsControllerTriggerPressed(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.RealController.Triggers.Left : inputState.RealController.Triggers.Right)); else - this.Events.Control_ControllerButtonPressed.Raise(new EventArgsControllerButtonPressed(PlayerIndex.One, controllerButton)); + this.Events.Legacy_Control_ControllerButtonPressed.Raise(new EventArgsControllerButtonPressed(PlayerIndex.One, controllerButton)); } } else if (status == InputStatus.Released) { - this.Events.Input_ButtonReleased.Raise(new EventArgsInput(button, cursor, button.IsActionButton(), button.IsUseToolButton(), inputState.SuppressButtons)); + this.Events.Input_ButtonReleased.Raise(new InputButtonReleasedArgsInput(button, cursor, inputState.SuppressButtons)); + this.Events.Legacy_Input_ButtonReleased.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons)); // legacy events if (button.TryGetKeyboard(out Keys key)) { if (key != Keys.None) - this.Events.Control_KeyReleased.Raise(new EventArgsKeyPressed(key)); + this.Events.Legacy_Control_KeyReleased.Raise(new EventArgsKeyPressed(key)); } else if (button.TryGetController(out Buttons controllerButton)) { if (controllerButton == Buttons.LeftTrigger || controllerButton == Buttons.RightTrigger) - this.Events.Control_ControllerTriggerReleased.Raise(new EventArgsControllerTriggerReleased(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.RealController.Triggers.Left : inputState.RealController.Triggers.Right)); + this.Events.Legacy_Control_ControllerTriggerReleased.Raise(new EventArgsControllerTriggerReleased(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.RealController.Triggers.Left : inputState.RealController.Triggers.Right)); else - this.Events.Control_ControllerButtonReleased.Raise(new EventArgsControllerButtonReleased(PlayerIndex.One, controllerButton)); + this.Events.Legacy_Control_ControllerButtonReleased.Raise(new EventArgsControllerButtonReleased(PlayerIndex.One, controllerButton)); } } } // raise legacy state-changed events if (inputState.RealKeyboard != previousInputState.RealKeyboard) - this.Events.Control_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(previousInputState.RealKeyboard, inputState.RealKeyboard)); + this.Events.Legacy_Control_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(previousInputState.RealKeyboard, inputState.RealKeyboard)); if (inputState.RealMouse != previousInputState.RealMouse) this.Events.Control_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, previousInputState.MousePosition, inputState.MousePosition)); } diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 7b9629e2..1bdad1b5 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -85,7 +85,10 @@ Properties\GlobalAssemblyInfo.cs + + + @@ -107,6 +110,7 @@ + -- cgit From 6f931aa576b2b2f6a64e7e0522e01f6a37c92c8a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 2 Jun 2018 02:35:26 -0400 Subject: add Input.CursorMoved event (#310) --- src/SMAPI/Events/ControlEvents.cs | 8 +++---- src/SMAPI/Events/IInputEvents.cs | 7 +++++-- src/SMAPI/Events/InputCursorMovedEventArgs.cs | 30 +++++++++++++++++++++++++++ src/SMAPI/Framework/Events/EventManager.cs | 20 +++++++++++------- src/SMAPI/Framework/Events/ModInputEvents.cs | 11 ++++++++-- src/SMAPI/Framework/SGame.cs | 27 +++++++++++++++++------- src/SMAPI/StardewModdingAPI.csproj | 1 + 7 files changed, 81 insertions(+), 23 deletions(-) create mode 100644 src/SMAPI/Events/InputCursorMovedEventArgs.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/ControlEvents.cs b/src/SMAPI/Events/ControlEvents.cs index 77bbf3ab..a3994d1d 100644 --- a/src/SMAPI/Events/ControlEvents.cs +++ b/src/SMAPI/Events/ControlEvents.cs @@ -24,14 +24,14 @@ namespace StardewModdingAPI.Events remove => ControlEvents.EventManager.Legacy_Control_KeyboardChanged.Remove(value); } - /// Raised when the player presses a keyboard key. + /// Raised after the player presses a keyboard key. public static event EventHandler KeyPressed { add => ControlEvents.EventManager.Legacy_Control_KeyPressed.Add(value); remove => ControlEvents.EventManager.Legacy_Control_KeyPressed.Remove(value); } - /// Raised when the player releases a keyboard key. + /// Raised after the player releases a keyboard key. public static event EventHandler KeyReleased { add => ControlEvents.EventManager.Legacy_Control_KeyReleased.Add(value); @@ -41,8 +41,8 @@ namespace StardewModdingAPI.Events /// Raised when the changes. That happens when the player moves the mouse, scrolls the mouse wheel, or presses/releases a button. public static event EventHandler MouseChanged { - add => ControlEvents.EventManager.Control_MouseChanged.Add(value); - remove => ControlEvents.EventManager.Control_MouseChanged.Remove(value); + add => ControlEvents.EventManager.Legacy_Control_MouseChanged.Add(value); + remove => ControlEvents.EventManager.Legacy_Control_MouseChanged.Remove(value); } /// The player pressed a controller button. This event isn't raised for trigger buttons. diff --git a/src/SMAPI/Events/IInputEvents.cs b/src/SMAPI/Events/IInputEvents.cs index 92802fda..938c772b 100644 --- a/src/SMAPI/Events/IInputEvents.cs +++ b/src/SMAPI/Events/IInputEvents.cs @@ -5,10 +5,13 @@ namespace StardewModdingAPI.Events /// Events raised when the player provides input using a controller, keyboard, or mouse. public interface IInputEvents { - /// Raised when the player presses a button on the keyboard, controller, or mouse. + /// Raised after the player presses a button on the keyboard, controller, or mouse. event EventHandler ButtonPressed; - /// Raised when the player releases a button on the keyboard, controller, or mouse. + /// Raised after the player releases a button on the keyboard, controller, or mouse. event EventHandler ButtonReleased; + + /// Raised after the player moves the in-game cursor. + event EventHandler CursorMoved; } } diff --git a/src/SMAPI/Events/InputCursorMovedEventArgs.cs b/src/SMAPI/Events/InputCursorMovedEventArgs.cs new file mode 100644 index 00000000..02e1ee2c --- /dev/null +++ b/src/SMAPI/Events/InputCursorMovedEventArgs.cs @@ -0,0 +1,30 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// Event arguments when the in-game cursor is moved. + public class InputCursorMovedArgsInput : EventArgs + { + /********* + ** Accessors + *********/ + /// The previous cursor position. + public ICursorPosition OldPosition { get; } + + /// The current cursor position. + public ICursorPosition NewPosition { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The previous cursor position. + /// The new cursor position. + public InputCursorMovedArgsInput(ICursorPosition oldPosition, ICursorPosition newPosition) + { + this.OldPosition = oldPosition; + this.NewPosition = newPosition; + } + } +} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 62d9582e..eea74587 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -35,12 +35,15 @@ namespace StardewModdingAPI.Framework.Events /**** ** Input ****/ - /// Raised when the player presses a button on the keyboard, controller, or mouse. + /// Raised after the player presses a button on the keyboard, controller, or mouse. public readonly ManagedEvent Input_ButtonPressed; - /// Raised when the player released a button on the keyboard, controller, or mouse. + /// Raised after the player released a button on the keyboard, controller, or mouse. public readonly ManagedEvent Input_ButtonReleased; + /// Raised after the player moves the in-game cursor. + public readonly ManagedEvent Input_CursorMoved; + /********* ** Events (old) @@ -57,14 +60,14 @@ namespace StardewModdingAPI.Framework.Events /// Raised when the changes. That happens when the player presses or releases a key. public readonly ManagedEvent Legacy_Control_KeyboardChanged; - /// Raised when the player presses a keyboard key. + /// Raised after the player presses a keyboard key. public readonly ManagedEvent Legacy_Control_KeyPressed; - /// Raised when the player releases a keyboard key. + /// Raised after the player releases a keyboard key. public readonly ManagedEvent Legacy_Control_KeyReleased; /// Raised when the changes. That happens when the player moves the mouse, scrolls the mouse wheel, or presses/releases a button. - public readonly ManagedEvent Control_MouseChanged; + public readonly ManagedEvent Legacy_Control_MouseChanged; /// The player pressed a controller button. This event isn't raised for trigger buttons. public readonly ManagedEvent Legacy_Control_ControllerButtonPressed; @@ -132,10 +135,10 @@ namespace StardewModdingAPI.Framework.Events /**** ** InputEvents ****/ - /// Raised when the player presses a button on the keyboard, controller, or mouse. + /// Raised after the player presses a button on the keyboard, controller, or mouse. public readonly ManagedEvent Legacy_Input_ButtonPressed; - /// Raised when the player releases a keyboard key on the keyboard, controller, or mouse. + /// Raised after the player releases a keyboard key on the keyboard, controller, or mouse. public readonly ManagedEvent Legacy_Input_ButtonReleased; /**** @@ -245,6 +248,7 @@ namespace StardewModdingAPI.Framework.Events // init events (new) this.Input_ButtonPressed = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed)); this.Input_ButtonReleased = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased)); + this.Input_CursorMoved = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.CursorMoved)); this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); this.World_LargeTerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LargeTerrainFeatureListChanged)); @@ -263,7 +267,7 @@ namespace StardewModdingAPI.Framework.Events this.Legacy_Control_KeyboardChanged = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyboardChanged)); this.Legacy_Control_KeyPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyPressed)); this.Legacy_Control_KeyReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyReleased)); - this.Control_MouseChanged = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.MouseChanged)); + this.Legacy_Control_MouseChanged = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.MouseChanged)); this.Game_FirstUpdateTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.FirstUpdateTick)); this.Game_UpdateTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.UpdateTick)); diff --git a/src/SMAPI/Framework/Events/ModInputEvents.cs b/src/SMAPI/Framework/Events/ModInputEvents.cs index 18baec16..48dd0369 100644 --- a/src/SMAPI/Framework/Events/ModInputEvents.cs +++ b/src/SMAPI/Framework/Events/ModInputEvents.cs @@ -9,20 +9,27 @@ namespace StardewModdingAPI.Framework.Events /********* ** Accessors *********/ - /// Raised when the player presses a button on the keyboard, controller, or mouse. + /// Raised after the player presses a button on the keyboard, controller, or mouse. public event EventHandler ButtonPressed { add => this.EventManager.Input_ButtonPressed.Add(value); remove => this.EventManager.Input_ButtonPressed.Remove(value); } - /// Raised when the player releases a button on the keyboard, controller, or mouse. + /// Raised after the player releases a button on the keyboard, controller, or mouse. public event EventHandler ButtonReleased { add => this.EventManager.Input_ButtonReleased.Add(value); remove => this.EventManager.Input_ButtonReleased.Remove(value); } + /// Raised after the player moves the in-game cursor. + public event EventHandler CursorMoved + { + add => this.EventManager.Input_CursorMoved.Add(value); + remove => this.EventManager.Input_CursorMoved.Remove(value); + } + /********* ** Public methods diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index f87293c2..f4e0d3c5 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -103,6 +103,9 @@ namespace StardewModdingAPI.Framework /// The previous content locale. private LocalizedContentManager.LanguageCode? PreviousLocale; + /// The previous cursor position. + private ICursorPosition PreviousCursorPosition; + /// An index incremented on every tick and reset every 60th tick (0–59). private int CurrentUpdateTick; @@ -444,14 +447,24 @@ namespace StardewModdingAPI.Framework { // cursor position Vector2 screenPixels = new Vector2(Game1.getMouseX(), Game1.getMouseY()); - Vector2 tile = new Vector2((int)((Game1.viewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.viewport.Y + screenPixels.Y) / Game1.tileSize)); - Vector2 grabTile = (Game1.mouseCursorTransparency > 0 && Utility.tileWithinRadiusOfPlayer((int)tile.X, (int)tile.Y, 1, Game1.player)) // derived from Game1.pressActionButton - ? tile - : Game1.player.GetGrabTile(); - cursor = new CursorPosition(screenPixels, tile, grabTile); + if (this.PreviousCursorPosition == null || screenPixels != this.PreviousCursorPosition.ScreenPixels) + { + Vector2 tile = new Vector2((int)((Game1.viewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.viewport.Y + screenPixels.Y) / Game1.tileSize)); + Vector2 grabTile = (Game1.mouseCursorTransparency > 0 && Utility.tileWithinRadiusOfPlayer((int)tile.X, (int)tile.Y, 1, Game1.player)) // derived from Game1.pressActionButton + ? tile + : Game1.player.GetGrabTile(); + cursor = new CursorPosition(screenPixels, tile, grabTile); + } + else + cursor = this.PreviousCursorPosition; } - // raise input events + // raise cursor moved event + if (this.PreviousCursorPosition != null && cursor.ScreenPixels != this.PreviousCursorPosition.ScreenPixels) + this.Events.Input_CursorMoved.Raise(new InputCursorMovedArgsInput(this.PreviousCursorPosition, cursor)); + this.PreviousCursorPosition = cursor; + + // raise input button events foreach (var pair in inputState.ActiveButtons) { SButton button = pair.Key; @@ -501,7 +514,7 @@ namespace StardewModdingAPI.Framework if (inputState.RealKeyboard != previousInputState.RealKeyboard) this.Events.Legacy_Control_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(previousInputState.RealKeyboard, inputState.RealKeyboard)); if (inputState.RealMouse != previousInputState.RealMouse) - this.Events.Control_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, previousInputState.MousePosition, inputState.MousePosition)); + this.Events.Legacy_Control_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, previousInputState.MousePosition, inputState.MousePosition)); } } diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 1bdad1b5..604ad64f 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -85,6 +85,7 @@ Properties\GlobalAssemblyInfo.cs + -- cgit From 90f55a6921ac798e03d6f81240d3a9899544c031 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 2 Jun 2018 12:14:15 -0400 Subject: add mouse scroll event (#310) --- src/SMAPI/Events/IInputEvents.cs | 3 ++ .../Events/InputMouseWheelScrolledEventArgs.cs | 38 ++++++++++++++++++++++ src/SMAPI/Framework/Events/EventManager.cs | 4 +++ src/SMAPI/Framework/Events/ModInputEvents.cs | 7 ++++ src/SMAPI/Framework/SGame.cs | 15 +++++++++ src/SMAPI/StardewModdingAPI.csproj | 1 + 6 files changed, 68 insertions(+) create mode 100644 src/SMAPI/Events/InputMouseWheelScrolledEventArgs.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/IInputEvents.cs b/src/SMAPI/Events/IInputEvents.cs index 938c772b..64d82c57 100644 --- a/src/SMAPI/Events/IInputEvents.cs +++ b/src/SMAPI/Events/IInputEvents.cs @@ -13,5 +13,8 @@ namespace StardewModdingAPI.Events /// Raised after the player moves the in-game cursor. event EventHandler CursorMoved; + + /// Raised after the player scrolls the mouse wheel. + event EventHandler MouseWheelScrolled; } } diff --git a/src/SMAPI/Events/InputMouseWheelScrolledEventArgs.cs b/src/SMAPI/Events/InputMouseWheelScrolledEventArgs.cs new file mode 100644 index 00000000..9afab9cc --- /dev/null +++ b/src/SMAPI/Events/InputMouseWheelScrolledEventArgs.cs @@ -0,0 +1,38 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// Event arguments when the player scrolls the mouse wheel. + public class InputMouseWheelScrolledEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The cursor position. + public ICursorPosition Position { get; } + + /// The old scroll value. + public int OldValue { get; } + + /// The new scroll value. + public int NewValue { get; } + + /// The amount by which the scroll value changed. + public int Delta => this.NewValue - this.OldValue; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The cursor position. + /// The old scroll value. + /// The new scroll value. + public InputMouseWheelScrolledEventArgs(ICursorPosition position, int oldValue, int newValue) + { + this.Position = position; + this.OldValue = oldValue; + this.NewValue = newValue; + } + } +} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index eea74587..9f67244a 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -44,6 +44,9 @@ namespace StardewModdingAPI.Framework.Events /// Raised after the player moves the in-game cursor. public readonly ManagedEvent Input_CursorMoved; + /// Raised after the player scrolls the mouse wheel. + public readonly ManagedEvent Input_MouseWheelScrolled; + /********* ** Events (old) @@ -249,6 +252,7 @@ namespace StardewModdingAPI.Framework.Events this.Input_ButtonPressed = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed)); this.Input_ButtonReleased = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased)); this.Input_CursorMoved = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.CursorMoved)); + this.Input_MouseWheelScrolled = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.MouseWheelScrolled)); this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); this.World_LargeTerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LargeTerrainFeatureListChanged)); diff --git a/src/SMAPI/Framework/Events/ModInputEvents.cs b/src/SMAPI/Framework/Events/ModInputEvents.cs index 48dd0369..387ea87a 100644 --- a/src/SMAPI/Framework/Events/ModInputEvents.cs +++ b/src/SMAPI/Framework/Events/ModInputEvents.cs @@ -30,6 +30,13 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.Input_CursorMoved.Remove(value); } + /// Raised after the player scrolls the mouse wheel. + public event EventHandler MouseWheelScrolled + { + add => this.EventManager.Input_MouseWheelScrolled.Add(value); + remove => this.EventManager.Input_MouseWheelScrolled.Remove(value); + } + /********* ** Public methods diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 894a771f..18529728 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -103,6 +103,9 @@ namespace StardewModdingAPI.Framework /// Tracks changes to the cursor position. private readonly IValueWatcher CursorWatcher; + /// Tracks changes to the mouse wheel scroll. + private readonly IValueWatcher MouseWheelScrollWatcher; + /// The previous content locale. private LocalizedContentManager.LanguageCode? PreviousLocale; @@ -172,6 +175,7 @@ namespace StardewModdingAPI.Framework // init watchers Game1.locations = new ObservableCollection(); this.CursorWatcher = WatcherFactory.ForEquatable(() => this.Input.MousePosition); + this.MouseWheelScrollWatcher = WatcherFactory.ForEquatable(() => this.Input.RealMouse.ScrollWheelValue); this.SaveIdWatcher = WatcherFactory.ForEquatable(() => Game1.hasLoadedGame ? Game1.uniqueIDForThisGame : 0); this.WindowSizeWatcher = WatcherFactory.ForEquatable(() => new Point(Game1.viewport.Width, Game1.viewport.Height)); this.TimeWatcher = WatcherFactory.ForEquatable(() => Game1.timeOfDay); @@ -180,6 +184,7 @@ namespace StardewModdingAPI.Framework this.Watchers.AddRange(new IWatcher[] { this.CursorWatcher, + this.MouseWheelScrollWatcher, this.SaveIdWatcher, this.WindowSizeWatcher, this.TimeWatcher, @@ -468,6 +473,16 @@ namespace StardewModdingAPI.Framework } this.PreviousCursorPosition = cursor; + // raise mouse wheel scrolled + if (this.MouseWheelScrollWatcher.IsChanged) + { + int oldValue = this.MouseWheelScrollWatcher.PreviousValue; + int newValue = this.MouseWheelScrollWatcher.CurrentValue; + this.MouseWheelScrollWatcher.Reset(); + + this.Events.Input_MouseWheelScrolled.Raise(new InputMouseWheelScrolledEventArgs(cursor, oldValue, newValue)); + } + // raise input button events foreach (var pair in inputState.ActiveButtons) { diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 604ad64f..b81f1359 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -85,6 +85,7 @@ Properties\GlobalAssemblyInfo.cs + -- cgit From 930a871018467683510ba39d092d401d7df50861 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 10 Jun 2018 21:33:17 -0400 Subject: add debris list changed event (#310) --- src/SMAPI/Events/IWorldEvents.cs | 3 ++ .../Events/WorldDebrisListChangedEventArgs.cs | 38 ++++++++++++++++++++++ src/SMAPI/Framework/Events/EventManager.cs | 4 +++ src/SMAPI/Framework/Events/ModWorldEvents.cs | 7 ++++ src/SMAPI/Framework/SGame.cs | 11 +++++++ .../Framework/StateTracking/LocationTracker.cs | 5 +++ src/SMAPI/Framework/WatcherCore.cs | 2 +- src/SMAPI/StardewModdingAPI.csproj | 1 + 8 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/SMAPI/Events/WorldDebrisListChangedEventArgs.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs index 067a79bc..d4efb53b 100644 --- a/src/SMAPI/Events/IWorldEvents.cs +++ b/src/SMAPI/Events/IWorldEvents.cs @@ -11,6 +11,9 @@ namespace StardewModdingAPI.Events /// Raised after buildings are added or removed in a location. event EventHandler BuildingListChanged; + /// Raised after debris are added or removed in a location. + event EventHandler DebrisListChanged; + /// Raised after large terrain features (like bushes) are added or removed in a location. event EventHandler LargeTerrainFeatureListChanged; diff --git a/src/SMAPI/Events/WorldDebrisListChangedEventArgs.cs b/src/SMAPI/Events/WorldDebrisListChangedEventArgs.cs new file mode 100644 index 00000000..aad9c24d --- /dev/null +++ b/src/SMAPI/Events/WorldDebrisListChangedEventArgs.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class WorldDebrisListChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The debris added to the location. + public IEnumerable Added { get; } + + /// The debris removed from the location. + public IEnumerable Removed { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The debris added to the location. + /// The debris removed from the location. + public WorldDebrisListChangedEventArgs(GameLocation location, IEnumerable added, IEnumerable removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 9f67244a..b05d82ce 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -20,6 +20,9 @@ namespace StardewModdingAPI.Framework.Events /// Raised after buildings are added or removed in a location. public readonly ManagedEvent World_BuildingListChanged; + /// Raised after debris are added or removed in a location. + public readonly ManagedEvent World_DebrisListChanged; + /// Raised after large terrain features (like bushes) are added or removed in a location. public readonly ManagedEvent World_LargeTerrainFeatureListChanged; @@ -255,6 +258,7 @@ namespace StardewModdingAPI.Framework.Events this.Input_MouseWheelScrolled = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.MouseWheelScrolled)); this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); + this.World_DebrisListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.DebrisListChanged)); this.World_LargeTerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LargeTerrainFeatureListChanged)); this.World_LocationListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.BuildingListChanged)); this.World_NpcListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.NpcListChanged)); diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs index e1a53e0c..dc9c0f4c 100644 --- a/src/SMAPI/Framework/Events/ModWorldEvents.cs +++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs @@ -23,6 +23,13 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.World_BuildingListChanged.Remove(value); } + /// Raised after debris are added or removed in a location. + public event EventHandler DebrisListChanged + { + add => this.EventManager.World_DebrisListChanged.Add(value, this.Mod); + remove => this.EventManager.World_DebrisListChanged.Remove(value); + } + /// Raised after large terrain features (like bushes) are added or removed in a location. public event EventHandler LargeTerrainFeatureListChanged { diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 588d30c8..984c1f57 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -536,6 +536,17 @@ namespace StardewModdingAPI.Framework this.Events.Legacy_Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); } + // debris changed + if (watcher.DebrisWatcher.IsChanged) + { + GameLocation location = watcher.Location; + Debris[] added = watcher.DebrisWatcher.Added.ToArray(); + Debris[] removed = watcher.DebrisWatcher.Removed.ToArray(); + watcher.DebrisWatcher.Reset(); + + this.Events.World_DebrisListChanged.Raise(new WorldDebrisListChangedEventArgs(location, added, removed)); + } + // large terrain features changed if (watcher.LargeTerrainFeaturesWatcher.IsChanged) { diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs index 1b4c0b19..708c0716 100644 --- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs +++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs @@ -33,6 +33,9 @@ namespace StardewModdingAPI.Framework.StateTracking /// 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; } @@ -59,6 +62,7 @@ namespace StardewModdingAPI.Framework.StateTracking this.BuildingsWatcher = location is BuildableGameLocation buildableLocation ? WatcherFactory.ForNetCollection(buildableLocation.buildings) : (ICollectionWatcher)WatcherFactory.ForObservableCollection(new ObservableCollection()); + this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris); this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection(location.largeTerrainFeatures); this.NpcsWatcher = WatcherFactory.ForNetCollection(location.characters); this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects); @@ -67,6 +71,7 @@ namespace StardewModdingAPI.Framework.StateTracking this.Watchers.AddRange(new IWatcher[] { this.BuildingsWatcher, + this.DebrisWatcher, this.LargeTerrainFeaturesWatcher, this.NpcsWatcher, this.ObjectsWatcher, diff --git a/src/SMAPI/Framework/WatcherCore.cs b/src/SMAPI/Framework/WatcherCore.cs index 64b063cf..e06423b9 100644 --- a/src/SMAPI/Framework/WatcherCore.cs +++ b/src/SMAPI/Framework/WatcherCore.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Framework internal class WatcherCore { /********* - ** Public methods + ** Properties *********/ /// The underlying watchers for convenience. These are accessible individually as separate properties. private readonly List Watchers = new List(); diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 67c48a57..ab3967c5 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -97,6 +97,7 @@ + -- cgit From 3b078d55daccd13332e2cba1fd5c76f775505d7a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 8 Jul 2018 20:06:33 -0400 Subject: add GameLoop events for SMAPI 3.0 (#310) --- src/SMAPI/Events/GameLoopLaunchedEventArgs.cs | 7 ++++ src/SMAPI/Events/GameLoopUpdatedEventArgs.cs | 36 ++++++++++++++++++++ src/SMAPI/Events/GameLoopUpdatingEventArgs.cs | 36 ++++++++++++++++++++ src/SMAPI/Events/IGameLoopEvents.cs | 17 ++++++++++ src/SMAPI/Events/IModEvents.cs | 3 ++ src/SMAPI/Framework/Events/EventManager.cs | 45 ++++++++++++++++--------- src/SMAPI/Framework/Events/ModEvents.cs | 4 +++ src/SMAPI/Framework/Events/ModGameLoopEvents.cs | 39 +++++++++++++++++++++ src/SMAPI/Framework/SGame.cs | 17 +++++----- src/SMAPI/StardewModdingAPI.csproj | 5 +++ 10 files changed, 186 insertions(+), 23 deletions(-) create mode 100644 src/SMAPI/Events/GameLoopLaunchedEventArgs.cs create mode 100644 src/SMAPI/Events/GameLoopUpdatedEventArgs.cs create mode 100644 src/SMAPI/Events/GameLoopUpdatingEventArgs.cs create mode 100644 src/SMAPI/Events/IGameLoopEvents.cs create mode 100644 src/SMAPI/Framework/Events/ModGameLoopEvents.cs (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/GameLoopLaunchedEventArgs.cs b/src/SMAPI/Events/GameLoopLaunchedEventArgs.cs new file mode 100644 index 00000000..6a42e4f9 --- /dev/null +++ b/src/SMAPI/Events/GameLoopLaunchedEventArgs.cs @@ -0,0 +1,7 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for an event. + public class GameLoopLaunchedEventArgs : EventArgs { } +} diff --git a/src/SMAPI/Events/GameLoopUpdatedEventArgs.cs b/src/SMAPI/Events/GameLoopUpdatedEventArgs.cs new file mode 100644 index 00000000..3ad34b69 --- /dev/null +++ b/src/SMAPI/Events/GameLoopUpdatedEventArgs.cs @@ -0,0 +1,36 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for an event. + public class GameLoopUpdatedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The number of ticks elapsed since the game started, including the current tick. + public uint Ticks { get; } + + /// Whether is a multiple of 60, which happens approximately once per second. + public bool IsOneSecond { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The number of ticks elapsed since the game started, including the current tick. + public GameLoopUpdatedEventArgs(uint ticks) + { + this.Ticks = ticks; + this.IsOneSecond = this.IsMultipleOf(60); + } + + /// Get whether is a multiple of the given . This is mainly useful if you want to run logic intermittently (e.g. e.IsMultipleOf(30) for every half-second). + /// The factor to check. + public bool IsMultipleOf(uint number) + { + return this.Ticks % number == 0; + } + } +} diff --git a/src/SMAPI/Events/GameLoopUpdatingEventArgs.cs b/src/SMAPI/Events/GameLoopUpdatingEventArgs.cs new file mode 100644 index 00000000..d6a8b5c2 --- /dev/null +++ b/src/SMAPI/Events/GameLoopUpdatingEventArgs.cs @@ -0,0 +1,36 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for an event. + public class GameLoopUpdatingEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The number of ticks elapsed since the game started, including the current tick. + public uint Ticks { get; } + + /// Whether is a multiple of 60, which happens approximately once per second. + public bool IsOneSecond { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The number of ticks elapsed since the game started, including the current tick. + public GameLoopUpdatingEventArgs(uint ticks) + { + this.Ticks = ticks; + this.IsOneSecond = this.IsMultipleOf(60); + } + + /// Get whether is a multiple of the given . This is mainly useful if you want to run logic intermittently (e.g. e.IsMultipleOf(30) for every half-second). + /// The factor to check. + public bool IsMultipleOf(uint number) + { + return this.Ticks % number == 0; + } + } +} diff --git a/src/SMAPI/Events/IGameLoopEvents.cs b/src/SMAPI/Events/IGameLoopEvents.cs new file mode 100644 index 00000000..a56b3de3 --- /dev/null +++ b/src/SMAPI/Events/IGameLoopEvents.cs @@ -0,0 +1,17 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// Events linked to the game's update loop. The update loop runs roughly ≈60 times/second to run game logic like state changes, action handling, etc. These can be useful, but you should consider more semantic events like if possible. + public interface IGameLoopEvents + { + /// Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialised at this point, so this is a good time to set up mod integrations. + event EventHandler Launched; + + /// Raised before the game performs its overall update tick (≈60 times per second). + event EventHandler Updating; + + /// Raised after the game performs its overall update tick (≈60 times per second). + event EventHandler Updated; + } +} diff --git a/src/SMAPI/Events/IModEvents.cs b/src/SMAPI/Events/IModEvents.cs index 16ec6557..cf2f8cb8 100644 --- a/src/SMAPI/Events/IModEvents.cs +++ b/src/SMAPI/Events/IModEvents.cs @@ -3,6 +3,9 @@ namespace StardewModdingAPI.Events /// Manages access to events raised by SMAPI. public interface IModEvents { + /// Events linked to the game's update loop. The update loop runs roughly ≈60 times/second to run game logic like state changes, action handling, etc. These can be useful, but you should consider more semantic events like if possible. + IGameLoopEvents GameLoop { get; } + /// Events raised when the player provides input using a controller, keyboard, or mouse. IInputEvents Input { get; } diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index b05d82ce..3d5d0124 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -11,6 +11,33 @@ namespace StardewModdingAPI.Framework.Events /********* ** Events (new) *********/ + /**** + ** Game loop + ****/ + /// Raised after the game is launched, right before the first update tick. + public readonly ManagedEvent GameLoop_Launched; + + /// Raised before the game performs its overall update tick (≈60 times per second). + public readonly ManagedEvent GameLoop_Updating; + + /// Raised after the game performs its overall update tick (≈60 times per second). + public readonly ManagedEvent GameLoop_Updated; + + /**** + ** Input + ****/ + /// Raised after the player presses a button on the keyboard, controller, or mouse. + public readonly ManagedEvent Input_ButtonPressed; + + /// Raised after the player released a button on the keyboard, controller, or mouse. + public readonly ManagedEvent Input_ButtonReleased; + + /// Raised after the player moves the in-game cursor. + public readonly ManagedEvent Input_CursorMoved; + + /// Raised after the player scrolls the mouse wheel. + public readonly ManagedEvent Input_MouseWheelScrolled; + /**** ** World ****/ @@ -35,21 +62,6 @@ namespace StardewModdingAPI.Framework.Events /// Raised after terrain features (like floors and trees) are added or removed in a location. public readonly ManagedEvent World_TerrainFeatureListChanged; - /**** - ** Input - ****/ - /// Raised after the player presses a button on the keyboard, controller, or mouse. - public readonly ManagedEvent Input_ButtonPressed; - - /// Raised after the player released a button on the keyboard, controller, or mouse. - public readonly ManagedEvent Input_ButtonReleased; - - /// Raised after the player moves the in-game cursor. - public readonly ManagedEvent Input_CursorMoved; - - /// Raised after the player scrolls the mouse wheel. - public readonly ManagedEvent Input_MouseWheelScrolled; - /********* ** Events (old) @@ -252,6 +264,9 @@ namespace StardewModdingAPI.Framework.Events ManagedEvent ManageEvent(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); // init events (new) + this.GameLoop_Updating = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Updating)); + this.GameLoop_Updated = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Updated)); + this.Input_ButtonPressed = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed)); this.Input_ButtonReleased = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased)); this.Input_CursorMoved = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.CursorMoved)); diff --git a/src/SMAPI/Framework/Events/ModEvents.cs b/src/SMAPI/Framework/Events/ModEvents.cs index 90853141..9e474457 100644 --- a/src/SMAPI/Framework/Events/ModEvents.cs +++ b/src/SMAPI/Framework/Events/ModEvents.cs @@ -8,6 +8,9 @@ namespace StardewModdingAPI.Framework.Events /********* ** Accessors *********/ + /// Events linked to the game's update loop. The update loop runs roughly ≈60 times/second to run game logic like state changes, action handling, etc. These can be useful, but you should consider more semantic events like if possible. + public IGameLoopEvents GameLoop { get; } + /// Events raised when the player provides input using a controller, keyboard, or mouse. public IInputEvents Input { get; } @@ -23,6 +26,7 @@ namespace StardewModdingAPI.Framework.Events /// The underlying event manager. public ModEvents(IModMetadata mod, EventManager eventManager) { + this.GameLoop = new ModGameLoopEvents(mod, eventManager); this.Input = new ModInputEvents(mod, eventManager); this.World = new ModWorldEvents(mod, eventManager); } diff --git a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs new file mode 100644 index 00000000..1a142b0f --- /dev/null +++ b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs @@ -0,0 +1,39 @@ +using System; +using StardewModdingAPI.Events; + +namespace StardewModdingAPI.Framework.Events +{ + /// Events linked to the game's update loop. The update loop runs roughly ≈60 times/second to run game logic like state changes, action handling, etc. These can be useful, but you should consider more semantic events like if possible. + internal class ModGameLoopEvents : ModEventsBase, IGameLoopEvents + { + /********* + ** Accessors + *********/ + /// Raised after the game is launched, right before the first update tick. + public event EventHandler Launched; + + /// Raised before the game performs its overall update tick (≈60 times per second). + public event EventHandler Updating + { + add => this.EventManager.GameLoop_Updating.Add(value); + remove => this.EventManager.GameLoop_Updating.Remove(value); + } + + /// Raised after the game performs its overall update tick (≈60 times per second). + public event EventHandler Updated + { + add => this.EventManager.GameLoop_Updated.Add(value); + remove => this.EventManager.GameLoop_Updated.Remove(value); + } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The mod which uses this instance. + /// The underlying event manager. + internal ModGameLoopEvents(IModMetadata mod, EventManager eventManager) + : base(mod, eventManager) { } + } +} diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index d3865316..777bc478 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -94,8 +94,8 @@ namespace StardewModdingAPI.Framework /// Whether post-game-startup initialisation has been performed. private bool IsInitialised; - /// Whether this is the very first update tick since the game started. - private bool FirstUpdate; + /// The number of update ticks which have already executed. + private uint TicksElapsed = 0; /// Whether the next content manager requested by the game will be for . private bool NextContentManagerIsMain; @@ -138,7 +138,6 @@ namespace StardewModdingAPI.Framework // init SMAPI this.Monitor = monitor; this.Events = eventManager; - this.FirstUpdate = true; this.Reflection = reflection; this.OnGameInitialised = onGameInitialised; this.OnGameExiting = onGameExiting; @@ -669,25 +668,27 @@ namespace StardewModdingAPI.Framework /********* ** Game update *********/ - this.Input.UpdateSuppression(); + this.TicksElapsed++; + if (this.TicksElapsed == 1) + this.Events.GameLoop_Launched.Raise(new GameLoopLaunchedEventArgs()); + this.Events.GameLoop_Updating.Raise(new GameLoopUpdatingEventArgs(this.TicksElapsed)); try { + this.Input.UpdateSuppression(); base.Update(gameTime); } catch (Exception ex) { this.Monitor.Log($"An error occured in the base update loop: {ex.GetLogSummary()}", LogLevel.Error); } + this.Events.GameLoop_Updated.Raise(new GameLoopUpdatedEventArgs(this.TicksElapsed)); /********* ** Update events *********/ this.Events.Specialised_UnvalidatedUpdateTick.Raise(); - if (this.FirstUpdate) - { - this.FirstUpdate = false; + if (this.TicksElapsed == 1) this.Events.Game_FirstUpdateTick.Raise(); - } this.Events.Game_UpdateTick.Raise(); if (this.CurrentUpdateTick % 2 == 0) this.Events.Game_SecondUpdateTick.Raise(); diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 57c2c9e8..27e98f3a 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -90,15 +90,19 @@ Properties\GlobalAssemblyInfo.cs + + + + @@ -125,6 +129,7 @@ + -- cgit From 68a21ff249c8a6cd9bdcece64e53162831fe7fd9 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 8 Jul 2018 20:50:42 -0400 Subject: fix new event not initialised (#310) --- src/SMAPI/Framework/Events/EventManager.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 3d5d0124..4de333a3 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -264,6 +264,7 @@ namespace StardewModdingAPI.Framework.Events ManagedEvent ManageEvent(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); // init events (new) + this.GameLoop_Launched = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Launched)); this.GameLoop_Updating = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Updating)); this.GameLoop_Updated = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Updated)); -- cgit From 5050bd75e7b86749d994ae268cdc3dabb7f7fcf8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 15 Jul 2018 20:59:31 -0400 Subject: fix misnamed types --- src/SMAPI/Events/IInputEvents.cs | 6 +++--- src/SMAPI/Events/InputButtonPressedEventArgs.cs | 4 ++-- src/SMAPI/Events/InputButtonReleasedEventArgs.cs | 4 ++-- src/SMAPI/Events/InputCursorMovedEventArgs.cs | 4 ++-- src/SMAPI/Framework/Events/EventManager.cs | 12 ++++++------ src/SMAPI/Framework/Events/ModInputEvents.cs | 6 +++--- src/SMAPI/Framework/SGame.cs | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) (limited to 'src/SMAPI/Framework/Events/EventManager.cs') diff --git a/src/SMAPI/Events/IInputEvents.cs b/src/SMAPI/Events/IInputEvents.cs index 64d82c57..8e2ef406 100644 --- a/src/SMAPI/Events/IInputEvents.cs +++ b/src/SMAPI/Events/IInputEvents.cs @@ -6,13 +6,13 @@ namespace StardewModdingAPI.Events public interface IInputEvents { /// Raised after the player presses a button on the keyboard, controller, or mouse. - event EventHandler ButtonPressed; + event EventHandler ButtonPressed; /// Raised after the player releases a button on the keyboard, controller, or mouse. - event EventHandler ButtonReleased; + event EventHandler ButtonReleased; /// Raised after the player moves the in-game cursor. - event EventHandler CursorMoved; + event EventHandler CursorMoved; /// Raised after the player scrolls the mouse wheel. event EventHandler MouseWheelScrolled; diff --git a/src/SMAPI/Events/InputButtonPressedEventArgs.cs b/src/SMAPI/Events/InputButtonPressedEventArgs.cs index 002f7cf1..8c6844dd 100644 --- a/src/SMAPI/Events/InputButtonPressedEventArgs.cs +++ b/src/SMAPI/Events/InputButtonPressedEventArgs.cs @@ -4,7 +4,7 @@ using StardewModdingAPI.Framework.Input; namespace StardewModdingAPI.Events { /// Event arguments when a button is pressed. - public class InputButtonPressedArgsInput : EventArgs + public class InputButtonPressedEventArgs : EventArgs { /********* ** Properties @@ -30,7 +30,7 @@ namespace StardewModdingAPI.Events /// The button on the controller, keyboard, or mouse. /// The cursor position. /// The game's current input state. - internal InputButtonPressedArgsInput(SButton button, ICursorPosition cursor, SInputState inputState) + internal InputButtonPressedEventArgs(SButton button, ICursorPosition cursor, SInputState inputState) { this.Button = button; this.Cursor = cursor; diff --git a/src/SMAPI/Events/InputButtonReleasedEventArgs.cs b/src/SMAPI/Events/InputButtonReleasedEventArgs.cs index bc5e4a89..4b0bc326 100644 --- a/src/SMAPI/Events/InputButtonReleasedEventArgs.cs +++ b/src/SMAPI/Events/InputButtonReleasedEventArgs.cs @@ -4,7 +4,7 @@ using StardewModdingAPI.Framework.Input; namespace StardewModdingAPI.Events { /// Event arguments when a button is released. - public class InputButtonReleasedArgsInput : EventArgs + public class InputButtonReleasedEventArgs : EventArgs { /********* ** Properties @@ -30,7 +30,7 @@ namespace StardewModdingAPI.Events /// The button on the controller, keyboard, or mouse. /// The cursor position. /// The game's current input state. - internal InputButtonReleasedArgsInput(SButton button, ICursorPosition cursor, SInputState inputState) + internal InputButtonReleasedEventArgs(SButton button, ICursorPosition cursor, SInputState inputState) { this.Button = button; this.Cursor = cursor; diff --git a/src/SMAPI/Events/InputCursorMovedEventArgs.cs b/src/SMAPI/Events/InputCursorMovedEventArgs.cs index 02e1ee2c..53aac5b3 100644 --- a/src/SMAPI/Events/InputCursorMovedEventArgs.cs +++ b/src/SMAPI/Events/InputCursorMovedEventArgs.cs @@ -3,7 +3,7 @@ using System; namespace StardewModdingAPI.Events { /// Event arguments when the in-game cursor is moved. - public class InputCursorMovedArgsInput : EventArgs + public class InputCursorMovedEventArgs : EventArgs { /********* ** Accessors @@ -21,7 +21,7 @@ namespace StardewModdingAPI.Events /// Construct an instance. /// The previous cursor position. /// The new cursor position. - public InputCursorMovedArgsInput(ICursorPosition oldPosition, ICursorPosition newPosition) + public InputCursorMovedEventArgs(ICursorPosition oldPosition, ICursorPosition newPosition) { this.OldPosition = oldPosition; this.NewPosition = newPosition; diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 4de333a3..168ddde0 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -27,13 +27,13 @@ namespace StardewModdingAPI.Framework.Events ** Input ****/ /// Raised after the player presses a button on the keyboard, controller, or mouse. - public readonly ManagedEvent Input_ButtonPressed; + public readonly ManagedEvent Input_ButtonPressed; /// Raised after the player released a button on the keyboard, controller, or mouse. - public readonly ManagedEvent Input_ButtonReleased; + public readonly ManagedEvent Input_ButtonReleased; /// Raised after the player moves the in-game cursor. - public readonly ManagedEvent Input_CursorMoved; + public readonly ManagedEvent Input_CursorMoved; /// Raised after the player scrolls the mouse wheel. public readonly ManagedEvent Input_MouseWheelScrolled; @@ -268,9 +268,9 @@ namespace StardewModdingAPI.Framework.Events this.GameLoop_Updating = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Updating)); this.GameLoop_Updated = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Updated)); - this.Input_ButtonPressed = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed)); - this.Input_ButtonReleased = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased)); - this.Input_CursorMoved = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.CursorMoved)); + this.Input_ButtonPressed = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed)); + this.Input_ButtonReleased = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased)); + this.Input_CursorMoved = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.CursorMoved)); this.Input_MouseWheelScrolled = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.MouseWheelScrolled)); this.World_BuildingListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged)); diff --git a/src/SMAPI/Framework/Events/ModInputEvents.cs b/src/SMAPI/Framework/Events/ModInputEvents.cs index 387ea87a..feca34f3 100644 --- a/src/SMAPI/Framework/Events/ModInputEvents.cs +++ b/src/SMAPI/Framework/Events/ModInputEvents.cs @@ -10,21 +10,21 @@ namespace StardewModdingAPI.Framework.Events ** Accessors *********/ /// Raised after the player presses a button on the keyboard, controller, or mouse. - public event EventHandler ButtonPressed + public event EventHandler ButtonPressed { add => this.EventManager.Input_ButtonPressed.Add(value); remove => this.EventManager.Input_ButtonPressed.Remove(value); } /// Raised after the player releases a button on the keyboard, controller, or mouse. - public event EventHandler ButtonReleased + public event EventHandler ButtonReleased { add => this.EventManager.Input_ButtonReleased.Add(value); remove => this.EventManager.Input_ButtonReleased.Remove(value); } /// Raised after the player moves the in-game cursor. - public event EventHandler CursorMoved + public event EventHandler CursorMoved { add => this.EventManager.Input_CursorMoved.Add(value); remove => this.EventManager.Input_CursorMoved.Remove(value); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index a685dfce..961fae08 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -430,7 +430,7 @@ namespace StardewModdingAPI.Framework ICursorPosition now = this.Watchers.CursorWatcher.CurrentValue; this.Watchers.CursorWatcher.Reset(); - this.Events.Input_CursorMoved.Raise(new InputCursorMovedArgsInput(was, now)); + this.Events.Input_CursorMoved.Raise(new InputCursorMovedEventArgs(was, now)); } // raise mouse wheel scrolled @@ -456,7 +456,7 @@ namespace StardewModdingAPI.Framework if (this.VerboseLogging) this.Monitor.Log($"Events: button {button} pressed.", LogLevel.Trace); - this.Events.Input_ButtonPressed.Raise(new InputButtonPressedArgsInput(button, cursor, inputState)); + this.Events.Input_ButtonPressed.Raise(new InputButtonPressedEventArgs(button, cursor, inputState)); this.Events.Legacy_Input_ButtonPressed.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons)); // legacy events @@ -478,7 +478,7 @@ namespace StardewModdingAPI.Framework if (this.VerboseLogging) this.Monitor.Log($"Events: button {button} released.", LogLevel.Trace); - this.Events.Input_ButtonReleased.Raise(new InputButtonReleasedArgsInput(button, cursor, inputState)); + this.Events.Input_ButtonReleased.Raise(new InputButtonReleasedEventArgs(button, cursor, inputState)); this.Events.Legacy_Input_ButtonReleased.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons)); // legacy events -- cgit