diff options
author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2018-07-08 20:06:33 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2018-07-08 20:06:33 -0400 |
commit | 3b078d55daccd13332e2cba1fd5c76f775505d7a (patch) | |
tree | 47a531276effb17a60dbec2a5ae2220102129b3b /src/SMAPI/Framework | |
parent | 7e46cc24630d810f4e2396346124780160cb7aa3 (diff) | |
download | SMAPI-3b078d55daccd13332e2cba1fd5c76f775505d7a.tar.gz SMAPI-3b078d55daccd13332e2cba1fd5c76f775505d7a.tar.bz2 SMAPI-3b078d55daccd13332e2cba1fd5c76f775505d7a.zip |
add GameLoop events for SMAPI 3.0 (#310)
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r-- | src/SMAPI/Framework/Events/EventManager.cs | 45 | ||||
-rw-r--r-- | src/SMAPI/Framework/Events/ModEvents.cs | 4 | ||||
-rw-r--r-- | src/SMAPI/Framework/Events/ModGameLoopEvents.cs | 39 | ||||
-rw-r--r-- | src/SMAPI/Framework/SGame.cs | 17 |
4 files changed, 82 insertions, 23 deletions
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 @@ -12,6 +12,33 @@ namespace StardewModdingAPI.Framework.Events ** Events (new) *********/ /**** + ** Game loop + ****/ + /// <summary>Raised after the game is launched, right before the first update tick.</summary> + public readonly ManagedEvent<GameLoopLaunchedEventArgs> GameLoop_Launched; + + /// <summary>Raised before the game performs its overall update tick (≈60 times per second).</summary> + public readonly ManagedEvent<GameLoopUpdatingEventArgs> GameLoop_Updating; + + /// <summary>Raised after the game performs its overall update tick (≈60 times per second).</summary> + public readonly ManagedEvent<GameLoopUpdatedEventArgs> GameLoop_Updated; + + /**** + ** Input + ****/ + /// <summary>Raised after the player presses a button on the keyboard, controller, or mouse.</summary> + public readonly ManagedEvent<InputButtonPressedArgsInput> Input_ButtonPressed; + + /// <summary>Raised after the player released a button on the keyboard, controller, or mouse.</summary> + public readonly ManagedEvent<InputButtonReleasedArgsInput> Input_ButtonReleased; + + /// <summary>Raised after the player moves the in-game cursor.</summary> + public readonly ManagedEvent<InputCursorMovedArgsInput> Input_CursorMoved; + + /// <summary>Raised after the player scrolls the mouse wheel.</summary> + public readonly ManagedEvent<InputMouseWheelScrolledEventArgs> Input_MouseWheelScrolled; + + /**** ** World ****/ /// <summary>Raised after a game location is added or removed.</summary> @@ -35,21 +62,6 @@ namespace StardewModdingAPI.Framework.Events /// <summary>Raised after terrain features (like floors and trees) are added or removed in a location.</summary> public readonly ManagedEvent<WorldTerrainFeatureListChangedEventArgs> World_TerrainFeatureListChanged; - /**** - ** Input - ****/ - /// <summary>Raised after the player presses a button on the keyboard, controller, or mouse.</summary> - public readonly ManagedEvent<InputButtonPressedArgsInput> Input_ButtonPressed; - - /// <summary>Raised after the player released a button on the keyboard, controller, or mouse.</summary> - public readonly ManagedEvent<InputButtonReleasedArgsInput> Input_ButtonReleased; - - /// <summary>Raised after the player moves the in-game cursor.</summary> - public readonly ManagedEvent<InputCursorMovedArgsInput> Input_CursorMoved; - - /// <summary>Raised after the player scrolls the mouse wheel.</summary> - public readonly ManagedEvent<InputMouseWheelScrolledEventArgs> 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<GameLoopUpdatingEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Updating)); + this.GameLoop_Updated = ManageEventOf<GameLoopUpdatedEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Updated)); + this.Input_ButtonPressed = ManageEventOf<InputButtonPressedArgsInput>(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed)); this.Input_ButtonReleased = ManageEventOf<InputButtonReleasedArgsInput>(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased)); this.Input_CursorMoved = ManageEventOf<InputCursorMovedArgsInput>(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 *********/ + /// <summary>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 <see cref="IModEvents.Input"/> if possible.</summary> + public IGameLoopEvents GameLoop { get; } + /// <summary>Events raised when the player provides input using a controller, keyboard, or mouse.</summary> public IInputEvents Input { get; } @@ -23,6 +26,7 @@ namespace StardewModdingAPI.Framework.Events /// <param name="eventManager">The underlying event manager.</param> 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 +{ + /// <summary>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 <see cref="IInputEvents"/> if possible.</summary> + internal class ModGameLoopEvents : ModEventsBase, IGameLoopEvents + { + /********* + ** Accessors + *********/ + /// <summary>Raised after the game is launched, right before the first update tick.</summary> + public event EventHandler<GameLoopLaunchedEventArgs> Launched; + + /// <summary>Raised before the game performs its overall update tick (≈60 times per second).</summary> + public event EventHandler<GameLoopUpdatingEventArgs> Updating + { + add => this.EventManager.GameLoop_Updating.Add(value); + remove => this.EventManager.GameLoop_Updating.Remove(value); + } + + /// <summary>Raised after the game performs its overall update tick (≈60 times per second).</summary> + public event EventHandler<GameLoopUpdatedEventArgs> Updated + { + add => this.EventManager.GameLoop_Updated.Add(value); + remove => this.EventManager.GameLoop_Updated.Remove(value); + } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="mod">The mod which uses this instance.</param> + /// <param name="eventManager">The underlying event manager.</param> + 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 /// <summary>Whether post-game-startup initialisation has been performed.</summary> private bool IsInitialised; - /// <summary>Whether this is the very first update tick since the game started.</summary> - private bool FirstUpdate; + /// <summary>The number of update ticks which have already executed.</summary> + private uint TicksElapsed = 0; /// <summary>Whether the next content manager requested by the game will be for <see cref="Game1.content"/>.</summary> 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(); |