diff options
-rw-r--r-- | docs/release-notes.md | 1 | ||||
-rw-r--r-- | src/SMAPI/Events/IGameLoopEvents.cs | 6 | ||||
-rw-r--r-- | src/SMAPI/Events/OneSecondUpdateTickedEventArgs.cs | 32 | ||||
-rw-r--r-- | src/SMAPI/Events/OneSecondUpdateTickingEventArgs.cs | 32 | ||||
-rw-r--r-- | src/SMAPI/Framework/Events/EventManager.cs | 8 | ||||
-rw-r--r-- | src/SMAPI/Framework/Events/ModGameLoopEvents.cs | 14 | ||||
-rw-r--r-- | src/SMAPI/Framework/SGame.cs | 5 | ||||
-rw-r--r-- | src/SMAPI/StardewModdingAPI.csproj | 2 |
8 files changed, 100 insertions, 0 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md index 15747488..5293f1c1 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,7 @@ * Tweaked installer to reduce antivirus false positives. * For modders: + * Added `GameLoop.OneSecondUpdateTicking/Ticked` events. * Added `Specialised.LoadStageChanged` for mods which need to do something at a specific point in the game's save loading process. * You can now use read/write save data as soon as the save is loaded (instead of once the world is initialised). diff --git a/src/SMAPI/Events/IGameLoopEvents.cs b/src/SMAPI/Events/IGameLoopEvents.cs index ea79aa74..6fb56c8b 100644 --- a/src/SMAPI/Events/IGameLoopEvents.cs +++ b/src/SMAPI/Events/IGameLoopEvents.cs @@ -14,6 +14,12 @@ namespace StardewModdingAPI.Events /// <summary>Raised after the game state is updated (≈60 times per second).</summary> event EventHandler<UpdateTickedEventArgs> UpdateTicked; + /// <summary>Raised once per second before the game state is updated.</summary> + event EventHandler<OneSecondUpdateTickingEventArgs> OneSecondUpdateTicking; + + /// <summary>Raised once per second after the game state is updated.</summary> + event EventHandler<OneSecondUpdateTickedEventArgs> OneSecondUpdateTicked; + /// <summary>Raised before the game creates a new save file.</summary> event EventHandler<SaveCreatingEventArgs> SaveCreating; diff --git a/src/SMAPI/Events/OneSecondUpdateTickedEventArgs.cs b/src/SMAPI/Events/OneSecondUpdateTickedEventArgs.cs new file mode 100644 index 00000000..d330502a --- /dev/null +++ b/src/SMAPI/Events/OneSecondUpdateTickedEventArgs.cs @@ -0,0 +1,32 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for an <see cref="IGameLoopEvents.OneSecondUpdateTicked"/> event.</summary> + public class OneSecondUpdateTickedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The number of ticks elapsed since the game started, including the current tick.</summary> + public uint Ticks { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="ticks">The number of ticks elapsed since the game started, including the current tick.</param> + internal OneSecondUpdateTickedEventArgs(uint ticks) + { + this.Ticks = ticks; + } + + /// <summary>Get whether <see cref="Ticks"/> is a multiple of the given <paramref name="number"/>. This is mainly useful if you want to run logic intermittently (e.g. <code>e.IsMultipleOf(30)</code> for every half-second).</summary> + /// <param name="number">The factor to check.</param> + public bool IsMultipleOf(uint number) + { + return this.Ticks % number == 0; + } + } +} diff --git a/src/SMAPI/Events/OneSecondUpdateTickingEventArgs.cs b/src/SMAPI/Events/OneSecondUpdateTickingEventArgs.cs new file mode 100644 index 00000000..cdd9f4cc --- /dev/null +++ b/src/SMAPI/Events/OneSecondUpdateTickingEventArgs.cs @@ -0,0 +1,32 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for an <see cref="IGameLoopEvents.OneSecondUpdateTicking"/> event.</summary> + public class OneSecondUpdateTickingEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The number of ticks elapsed since the game started, including the current tick.</summary> + public uint Ticks { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="ticks">The number of ticks elapsed since the game started, including the current tick.</param> + internal OneSecondUpdateTickingEventArgs(uint ticks) + { + this.Ticks = ticks; + } + + /// <summary>Get whether <see cref="Ticks"/> is a multiple of the given <paramref name="number"/>. This is mainly useful if you want to run logic intermittently (e.g. <code>e.IsMultipleOf(30)</code> for every half-second).</summary> + /// <param name="number">The factor to check.</param> + public bool IsMultipleOf(uint number) + { + return this.Ticks % number == 0; + } + } +} diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index b7f00f52..13244601 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -58,6 +58,12 @@ namespace StardewModdingAPI.Framework.Events /// <summary>Raised after the game performs its overall update tick (≈60 times per second).</summary> public readonly ManagedEvent<UpdateTickedEventArgs> UpdateTicked; + /// <summary>Raised once per second before the game performs its overall update tick.</summary> + public readonly ManagedEvent<OneSecondUpdateTickingEventArgs> OneSecondUpdateTicking; + + /// <summary>Raised once per second after the game performs its overall update tick.</summary> + public readonly ManagedEvent<OneSecondUpdateTickedEventArgs> OneSecondUpdateTicked; + /// <summary>Raised before the game creates the save file.</summary> public readonly ManagedEvent<SaveCreatingEventArgs> SaveCreating; @@ -380,6 +386,8 @@ namespace StardewModdingAPI.Framework.Events this.GameLaunched = ManageEventOf<GameLaunchedEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.GameLaunched)); this.UpdateTicking = ManageEventOf<UpdateTickingEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.UpdateTicking)); this.UpdateTicked = ManageEventOf<UpdateTickedEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.UpdateTicked)); + this.OneSecondUpdateTicking = ManageEventOf<OneSecondUpdateTickingEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.OneSecondUpdateTicking)); + this.OneSecondUpdateTicked = ManageEventOf<OneSecondUpdateTickedEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.OneSecondUpdateTicked)); this.SaveCreating = ManageEventOf<SaveCreatingEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.SaveCreating)); this.SaveCreated = ManageEventOf<SaveCreatedEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.SaveCreated)); this.Saving = ManageEventOf<SavingEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.Saving)); diff --git a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs index 3a764ab0..0177c22e 100644 --- a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs +++ b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs @@ -30,6 +30,20 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.UpdateTicked.Remove(value); } + /// <summary>Raised once per second before the game state is updated.</summary> + public event EventHandler<OneSecondUpdateTickingEventArgs> OneSecondUpdateTicking + { + add => this.EventManager.OneSecondUpdateTicking.Add(value); + remove => this.EventManager.OneSecondUpdateTicking.Remove(value); + } + + /// <summary>Raised once per second after the game state is updated.</summary> + public event EventHandler<OneSecondUpdateTickedEventArgs> OneSecondUpdateTicked + { + add => this.EventManager.OneSecondUpdateTicked.Add(value); + remove => this.EventManager.OneSecondUpdateTicked.Remove(value); + } + /// <summary>Raised before the game creates a new save file.</summary> public event EventHandler<SaveCreatingEventArgs> SaveCreating { diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index cb62de2a..8abe4d16 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -878,8 +878,11 @@ namespace StardewModdingAPI.Framework this.OnLoadStageChanged(LoadStage.Loaded); // update tick + bool isOneSecond = this.TicksElapsed % 60 == 0; this.Events.UnvalidatedUpdateTicking.Raise(new UnvalidatedUpdateTickingEventArgs(this.TicksElapsed)); this.Events.UpdateTicking.Raise(new UpdateTickingEventArgs(this.TicksElapsed)); + if (isOneSecond) + this.Events.OneSecondUpdateTicking.Raise(new OneSecondUpdateTickingEventArgs(this.TicksElapsed)); try { this.Input.UpdateSuppression(); @@ -891,6 +894,8 @@ namespace StardewModdingAPI.Framework } this.Events.UnvalidatedUpdateTicked.Raise(new UnvalidatedUpdateTickedEventArgs(this.TicksElapsed)); this.Events.UpdateTicked.Raise(new UpdateTickedEventArgs(this.TicksElapsed)); + if (isOneSecond) + this.Events.OneSecondUpdateTicked.Raise(new OneSecondUpdateTickedEventArgs(this.TicksElapsed)); /********* ** Update events diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index fdb0c6c7..5540f277 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -135,6 +135,8 @@ <Compile Include="Events\MultiplayerEvents.cs" /> <Compile Include="Events\NpcListChangedEventArgs.cs" /> <Compile Include="Events\ObjectListChangedEventArgs.cs" /> + <Compile Include="Events\OneSecondUpdateTickedEventArgs.cs" /> + <Compile Include="Events\OneSecondUpdateTickingEventArgs.cs" /> <Compile Include="Events\PeerContextReceivedEventArgs.cs" /> <Compile Include="Events\PeerDisconnectedEventArgs.cs" /> <Compile Include="Events\PlayerEvents.cs" /> |