summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2018-12-23 19:26:02 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2018-12-23 19:26:02 -0500
commit041bd2d6ba726eeea88afed3be307343a6f9286b (patch)
tree99afbee9f86951a1768166a676f0669e096eb221
parent4b325f61b370b24403fa10616178dceefa773420 (diff)
downloadSMAPI-041bd2d6ba726eeea88afed3be307343a6f9286b.tar.gz
SMAPI-041bd2d6ba726eeea88afed3be307343a6f9286b.tar.bz2
SMAPI-041bd2d6ba726eeea88afed3be307343a6f9286b.zip
add Specialised.SavePreloaded event
-rw-r--r--docs/release-notes.md3
-rw-r--r--src/SMAPI/Events/IGameLoopEvents.cs2
-rw-r--r--src/SMAPI/Events/ISpecialisedEvents.cs3
-rw-r--r--src/SMAPI/Events/SavePreloadedEventArgs.cs7
-rw-r--r--src/SMAPI/Framework/Events/EventManager.cs6
-rw-r--r--src/SMAPI/Framework/Events/ModGameLoopEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModSpecialisedEvents.cs7
-rw-r--r--src/SMAPI/Framework/SGame.cs23
-rw-r--r--src/SMAPI/StardewModdingAPI.csproj1
9 files changed, 46 insertions, 8 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md
index eacf0955..3daca07f 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -5,7 +5,8 @@
* Tweaked installer to reduce antivirus false positives.
* For modders:
- * You can now use `ReadSaveData` or `WriteSaveData` immediately after the save is loaded, before the in-game world is initialised.
+ * Added `Specialised.SavePreloaded` event, which is raised immediately after a save is loaded but before the in-game world is fully initialised.
+ * You can now use read/write save data as soon as the save is loaded (instead of once the world is initialised).
## 2.9.3
* For players:
diff --git a/src/SMAPI/Events/IGameLoopEvents.cs b/src/SMAPI/Events/IGameLoopEvents.cs
index e1900f79..ea79aa74 100644
--- a/src/SMAPI/Events/IGameLoopEvents.cs
+++ b/src/SMAPI/Events/IGameLoopEvents.cs
@@ -26,7 +26,7 @@ namespace StardewModdingAPI.Events
/// <summary>Raised after the game finishes writing data to the save file (except the initial save creation).</summary>
event EventHandler<SavedEventArgs> Saved;
- /// <summary>Raised after the player loads a save slot.</summary>
+ /// <summary>Raised after the player loads a save slot and the world is initialised.</summary>
event EventHandler<SaveLoadedEventArgs> SaveLoaded;
/// <summary>Raised after the game begins a new day (including when the player loads a save).</summary>
diff --git a/src/SMAPI/Events/ISpecialisedEvents.cs b/src/SMAPI/Events/ISpecialisedEvents.cs
index 928cd05d..2a19113c 100644
--- a/src/SMAPI/Events/ISpecialisedEvents.cs
+++ b/src/SMAPI/Events/ISpecialisedEvents.cs
@@ -5,6 +5,9 @@ namespace StardewModdingAPI.Events
/// <summary>Events serving specialised edge cases that shouldn't be used by most mods.</summary>
public interface ISpecialisedEvents
{
+ /// <summary>Raised immediately after the player loads a save slot, but before the world is fully initialised. The save and game data are available at this point, but some in-game content (like location maps) haven't been initialised yet.</summary>
+ event EventHandler<SavePreloadedEventArgs> SavePreloaded;
+
/// <summary>Raised before the game state is updated (≈60 times per second), regardless of normal SMAPI validation. This event is not thread-safe and may be invoked while game logic is running asynchronously. Changes to game state in this method may crash the game or corrupt an in-progress save. Do not use this event unless you're fully aware of the context in which your code will be run. Mods using this event will trigger a stability warning in the SMAPI console.</summary>
event EventHandler<UnvalidatedUpdateTickingEventArgs> UnvalidatedUpdateTicking;
diff --git a/src/SMAPI/Events/SavePreloadedEventArgs.cs b/src/SMAPI/Events/SavePreloadedEventArgs.cs
new file mode 100644
index 00000000..03990f5a
--- /dev/null
+++ b/src/SMAPI/Events/SavePreloadedEventArgs.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace StardewModdingAPI.Events
+{
+ /// <summary>Event arguments for an <see cref="ISpecialisedEvents.SavePreloaded"/> event.</summary>
+ public class SavePreloadedEventArgs : EventArgs { }
+}
diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs
index 0ad85adf..bd862046 100644
--- a/src/SMAPI/Framework/Events/EventManager.cs
+++ b/src/SMAPI/Framework/Events/EventManager.cs
@@ -70,7 +70,7 @@ namespace StardewModdingAPI.Framework.Events
/// <summary>Raised after the game finishes writing data to the save file (except the initial save creation).</summary>
public readonly ManagedEvent<SavedEventArgs> Saved;
- /// <summary>Raised after the player loads a save slot.</summary>
+ /// <summary>Raised after the player loads a save slot and the world is initialised.</summary>
public readonly ManagedEvent<SaveLoadedEventArgs> SaveLoaded;
/// <summary>Raised after the game begins a new day, including when loading a save.</summary>
@@ -151,6 +151,9 @@ namespace StardewModdingAPI.Framework.Events
/****
** Specialised
****/
+ /// <summary>Raised immediately after the player loads a save slot, but before the world is fully initialised.</summary>
+ public readonly ManagedEvent<SavePreloadedEventArgs> SavePreloaded;
+
/// <summary>Raised before the game performs its overall update tick (≈60 times per second). See notes on <see cref="ISpecialisedEvents.UnvalidatedUpdateTicking"/>.</summary>
public readonly ManagedEvent<UnvalidatedUpdateTickingEventArgs> UnvalidatedUpdateTicking;
@@ -408,6 +411,7 @@ namespace StardewModdingAPI.Framework.Events
this.ObjectListChanged = ManageEventOf<ObjectListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged));
this.TerrainFeatureListChanged = ManageEventOf<TerrainFeatureListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.TerrainFeatureListChanged));
+ this.SavePreloaded = ManageEventOf<SavePreloadedEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.SavePreloaded));
this.UnvalidatedUpdateTicking = ManageEventOf<UnvalidatedUpdateTickingEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicking));
this.UnvalidatedUpdateTicked = ManageEventOf<UnvalidatedUpdateTickedEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicked));
diff --git a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs
index a5beac99..3a764ab0 100644
--- a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs
+++ b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs
@@ -58,7 +58,7 @@ namespace StardewModdingAPI.Framework.Events
remove => this.EventManager.Saved.Remove(value);
}
- /// <summary>Raised after the player loads a save slot.</summary>
+ /// <summary>Raised after the player loads a save slot and the world is initialised.</summary>
public event EventHandler<SaveLoadedEventArgs> SaveLoaded
{
add => this.EventManager.SaveLoaded.Add(value);
diff --git a/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs b/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs
index 17c32bb8..83e349cf 100644
--- a/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs
+++ b/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs
@@ -9,6 +9,13 @@ namespace StardewModdingAPI.Framework.Events
/*********
** Accessors
*********/
+ /// <summary>Raised immediately after the player loads a save slot, but before the world is fully initialised. The save and game data are available at this point, but some in-game content (like location maps) haven't been initialised yet.</summary>
+ public event EventHandler<SavePreloadedEventArgs> SavePreloaded
+ {
+ add => this.EventManager.SavePreloaded.Add(value);
+ remove => this.EventManager.SavePreloaded.Remove(value);
+ }
+
/// <summary>Raised before the game state is updated (≈60 times per second), regardless of normal SMAPI validation. This event is not thread-safe and may be invoked while game logic is running asynchronously. Changes to game state in this method may crash the game or corrupt an in-progress save. Do not use this event unless you're fully aware of the context in which your code will be run. Mods using this event will trigger a stability warning in the SMAPI console.</summary>
public event EventHandler<UnvalidatedUpdateTickingEventArgs> UnvalidatedUpdateTicking
{
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index d515d3ad..befd9cef 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -69,8 +69,11 @@ namespace StardewModdingAPI.Framework
/// <remarks>Skipping a few frames ensures the game finishes initialising the world before mods try to change it.</remarks>
private readonly Countdown AfterLoadTimer = new Countdown(5);
+ /// <summary>Whether <see cref="EventManager.SavePreloaded"/> was raised for this session.</summary>
+ private bool RaisedPreloadedEvent;
+
/// <summary>Whether the after-load events were raised for this session.</summary>
- private bool RaisedAfterLoadEvent;
+ private bool RaisedLoadedEvent;
/// <summary>Whether the game is saving and SMAPI has already raised <see cref="IGameLoopEvents.Saving"/>.</summary>
private bool IsBetweenSaveEvents;
@@ -217,6 +220,7 @@ namespace StardewModdingAPI.Framework
private void OnReturnedToTitle()
{
this.Monitor.Log("Context: returned to title", LogLevel.Trace);
+ this.RaisedPreloadedEvent = false;
this.Multiplayer.CleanupOnMultiplayerExit();
this.Events.ReturnedToTitle.RaiseEmpty();
#if !SMAPI_3_0_STRICT
@@ -466,7 +470,7 @@ namespace StardewModdingAPI.Framework
*********/
if (wasWorldReady && !Context.IsWorldReady)
this.OnReturnedToTitle();
- else if (!this.RaisedAfterLoadEvent && Context.IsWorldReady)
+ else if (!this.RaisedLoadedEvent && Context.IsWorldReady)
{
// print context
string context = $"Context: loaded saved game '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.";
@@ -480,7 +484,7 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log(context, LogLevel.Trace);
// raise events
- this.RaisedAfterLoadEvent = true;
+ this.RaisedLoadedEvent = true;
this.Events.SaveLoaded.RaiseEmpty();
this.Events.DayStarted.RaiseEmpty();
#if !SMAPI_3_0_STRICT
@@ -824,8 +828,19 @@ namespace StardewModdingAPI.Framework
** Game update
*********/
this.TicksElapsed++;
+
+ // game launched
if (this.TicksElapsed == 1)
this.Events.GameLaunched.Raise(new GameLaunchedEventArgs());
+
+ // preloaded
+ if (Context.IsSaveLoaded && !this.RaisedPreloadedEvent)
+ {
+ this.RaisedPreloadedEvent = true;
+ this.Events.SavePreloaded.RaiseEmpty();
+ }
+
+ // update tick
this.Events.UnvalidatedUpdateTicking.Raise(new UnvalidatedUpdateTickingEventArgs(this.TicksElapsed));
this.Events.UpdateTicking.Raise(new UpdateTickingEventArgs(this.TicksElapsed));
try
@@ -1639,7 +1654,7 @@ namespace StardewModdingAPI.Framework
{
Context.IsWorldReady = false;
this.AfterLoadTimer.Reset();
- this.RaisedAfterLoadEvent = false;
+ this.RaisedLoadedEvent = false;
}
#if !SMAPI_3_0_STRICT
diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj
index 9b00e777..36fa7e0b 100644
--- a/src/SMAPI/StardewModdingAPI.csproj
+++ b/src/SMAPI/StardewModdingAPI.csproj
@@ -150,6 +150,7 @@
<Compile Include="Events\SavedEventArgs.cs" />
<Compile Include="Events\SaveEvents.cs" />
<Compile Include="Events\SaveLoadedEventArgs.cs" />
+ <Compile Include="Events\SavePreloadedEventArgs.cs" />
<Compile Include="Events\SavingEventArgs.cs" />
<Compile Include="Events\SpecialisedEvents.cs" />
<Compile Include="Events\TerrainFeatureListChangedEventArgs.cs" />