summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-06-13 23:49:05 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-09-14 18:04:00 -0400
commitfdf221addee883f4b1ddcd42f92876f7a816c7a1 (patch)
treeae9a7e65b9adb6ec38672c2602cf3b322bc40dcf /src
parent31c882c8cea66bbd2805cc5aab11abbce248782c (diff)
downloadSMAPI-fdf221addee883f4b1ddcd42f92876f7a816c7a1.tar.gz
SMAPI-fdf221addee883f4b1ddcd42f92876f7a816c7a1.tar.bz2
SMAPI-fdf221addee883f4b1ddcd42f92876f7a816c7a1.zip
reorganise update loop a bit (#648)
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI/Framework/SGame.cs667
1 files changed, 340 insertions, 327 deletions
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 2a3f16d4..1145207f 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -28,7 +28,6 @@ using StardewValley.Menus;
using StardewValley.TerrainFeatures;
using StardewValley.Tools;
using xTile.Dimensions;
-using xTile.Layers;
using SObject = StardewValley.Object;
namespace StardewModdingAPI.Framework
@@ -270,15 +269,27 @@ namespace StardewModdingAPI.Framework
this.DeprecationManager.PrintQueued();
/*********
- ** Special cases
+ ** First-tick initialisation
*********/
- // Perform first-tick initialisation.
if (!this.IsInitialised)
{
this.IsInitialised = true;
this.InitialiseAfterGameStarted();
}
+ /*********
+ ** Update input
+ *********/
+ // This should *always* run, even when suppressing mod events, since the game uses
+ // this too. For example, doing this after mod event suppression would prevent the
+ // user from doing anything on the overnight shipping screen.
+ SInputState inputState = this.Input;
+ if (this.IsActive)
+ inputState.TrueUpdate();
+
+ /*********
+ ** Special cases
+ *********/
// Abort if SMAPI is exiting.
if (this.CancellationToken.IsCancellationRequested)
{
@@ -345,6 +356,38 @@ namespace StardewModdingAPI.Framework
return;
}
+ // Raise minimal events while saving.
+ // While the game is writing to the save file in the background, mods can unexpectedly
+ // fail since they don't have exclusive access to resources (e.g. collection changed
+ // during enumeration errors). To avoid problems, events are not invoked while a save
+ // is in progress. It's safe to raise SaveEvents.BeforeSave as soon as the menu is
+ // opened (since the save hasn't started yet), but all other events should be suppressed.
+ if (Context.IsSaving)
+ {
+ // raise before-create
+ if (!Context.IsWorldReady && !this.IsBetweenCreateEvents)
+ {
+ this.IsBetweenCreateEvents = true;
+ this.Monitor.Log("Context: before save creation.", LogLevel.Trace);
+ events.SaveCreating.RaiseEmpty();
+ }
+
+ // raise before-save
+ if (Context.IsWorldReady && !this.IsBetweenSaveEvents)
+ {
+ this.IsBetweenSaveEvents = true;
+ this.Monitor.Log("Context: before save.", LogLevel.Trace);
+ events.Saving.RaiseEmpty();
+ }
+
+ // suppress non-save events
+ events.UnvalidatedUpdateTicking.RaiseEmpty();
+ SGame.TicksElapsed++;
+ base.Update(gameTime);
+ events.UnvalidatedUpdateTicked.RaiseEmpty();
+ return;
+ }
+
/*********
** Execute commands
*********/
@@ -383,66 +426,6 @@ namespace StardewModdingAPI.Framework
}
/*********
- ** Update input
- *********/
- // This should *always* run, even when suppressing mod events, since the game uses
- // this too. For example, doing this after mod event suppression would prevent the
- // user from doing anything on the overnight shipping screen.
- SInputState inputState = this.Input;
- if (this.IsActive)
- inputState.TrueUpdate();
-
- /*********
- ** Save events + suppress events during save
- *********/
- // While the game is writing to the save file in the background, mods can unexpectedly
- // fail since they don't have exclusive access to resources (e.g. collection changed
- // during enumeration errors). To avoid problems, events are not invoked while a save
- // is in progress. It's safe to raise SaveEvents.BeforeSave as soon as the menu is
- // opened (since the save hasn't started yet), but all other events should be suppressed.
- if (Context.IsSaving)
- {
- // raise before-create
- if (!Context.IsWorldReady && !this.IsBetweenCreateEvents)
- {
- this.IsBetweenCreateEvents = true;
- this.Monitor.Log("Context: before save creation.", LogLevel.Trace);
- events.SaveCreating.RaiseEmpty();
- }
-
- // raise before-save
- if (Context.IsWorldReady && !this.IsBetweenSaveEvents)
- {
- this.IsBetweenSaveEvents = true;
- this.Monitor.Log("Context: before save.", LogLevel.Trace);
- events.Saving.RaiseEmpty();
- }
-
- // suppress non-save events
- events.UnvalidatedUpdateTicking.RaiseEmpty();
- SGame.TicksElapsed++;
- base.Update(gameTime);
- events.UnvalidatedUpdateTicked.RaiseEmpty();
- return;
- }
- if (this.IsBetweenCreateEvents)
- {
- // raise after-create
- this.IsBetweenCreateEvents = false;
- this.Monitor.Log($"Context: after save creation, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace);
- this.OnLoadStageChanged(LoadStage.CreatedSaveFile);
- events.SaveCreated.RaiseEmpty();
- }
- if (this.IsBetweenSaveEvents)
- {
- // raise after-save
- this.IsBetweenSaveEvents = false;
- this.Monitor.Log($"Context: after save, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace);
- events.Saved.RaiseEmpty();
- events.DayStarted.RaiseEmpty();
- }
-
- /*********
** Update context
*********/
bool wasWorldReady = Context.IsWorldReady;
@@ -464,340 +447,370 @@ namespace StardewModdingAPI.Framework
this.Watchers.Update();
/*********
- ** Locale changed events
+ ** Pre-update events
*********/
- if (this.Watchers.LocaleWatcher.IsChanged)
{
- this.Monitor.Log($"Context: locale set to {this.Watchers.LocaleWatcher.CurrentValue}.", LogLevel.Trace);
-
- this.Watchers.LocaleWatcher.Reset();
- }
-
- /*********
- ** Load / return-to-title events
- *********/
- if (wasWorldReady && !Context.IsWorldReady)
- this.OnLoadStageChanged(LoadStage.None);
- else if (Context.IsWorldReady && Context.LoadStage != LoadStage.Ready)
- {
- // print context
- string context = $"Context: loaded save '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}, locale set to {this.ContentCore.Language}.";
- if (Context.IsMultiplayer)
+ /*********
+ ** Save created/loaded events
+ *********/
+ if (this.IsBetweenCreateEvents)
{
- int onlineCount = Game1.getOnlineFarmers().Count();
- context += $" {(Context.IsMainPlayer ? "Main player" : "Farmhand")} with {onlineCount} {(onlineCount == 1 ? "player" : "players")} online.";
+ // raise after-create
+ this.IsBetweenCreateEvents = false;
+ this.Monitor.Log($"Context: after save creation, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace);
+ this.OnLoadStageChanged(LoadStage.CreatedSaveFile);
+ events.SaveCreated.RaiseEmpty();
+ }
+ if (this.IsBetweenSaveEvents)
+ {
+ // raise after-save
+ this.IsBetweenSaveEvents = false;
+ this.Monitor.Log($"Context: after save, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace);
+ events.Saved.RaiseEmpty();
+ events.DayStarted.RaiseEmpty();
}
- else
- context += " Single-player.";
- this.Monitor.Log(context, LogLevel.Trace);
- // raise events
- this.OnLoadStageChanged(LoadStage.Ready);
- events.SaveLoaded.RaiseEmpty();
- events.DayStarted.RaiseEmpty();
- }
+ /*********
+ ** Locale changed events
+ *********/
+ if (this.Watchers.LocaleWatcher.IsChanged)
+ {
+ this.Monitor.Log($"Context: locale set to {this.Watchers.LocaleWatcher.CurrentValue}.", LogLevel.Trace);
- /*********
- ** Window events
- *********/
- // Here we depend on the game's viewport instead of listening to the Window.Resize
- // event because we need to notify mods after the game handles the resize, so the
- // game's metadata (like Game1.viewport) are updated. That's a bit complicated
- // since the game adds & removes its own handler on the fly.
- if (this.Watchers.WindowSizeWatcher.IsChanged)
- {
- if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Events: window size changed to {this.Watchers.WindowSizeWatcher.CurrentValue}.", LogLevel.Trace);
+ this.Watchers.LocaleWatcher.Reset();
+ }
- Point oldSize = this.Watchers.WindowSizeWatcher.PreviousValue;
- Point newSize = this.Watchers.WindowSizeWatcher.CurrentValue;
+ /*********
+ ** Load / return-to-title events
+ *********/
+ if (wasWorldReady && !Context.IsWorldReady)
+ this.OnLoadStageChanged(LoadStage.None);
+ else if (Context.IsWorldReady && Context.LoadStage != LoadStage.Ready)
+ {
+ // print context
+ string context = $"Context: loaded save '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}, locale set to {this.ContentCore.Language}.";
+ if (Context.IsMultiplayer)
+ {
+ int onlineCount = Game1.getOnlineFarmers().Count();
+ context += $" {(Context.IsMainPlayer ? "Main player" : "Farmhand")} with {onlineCount} {(onlineCount == 1 ? "player" : "players")} online.";
+ }
+ else
+ context += " Single-player.";
+ this.Monitor.Log(context, LogLevel.Trace);
- events.WindowResized.Raise(new WindowResizedEventArgs(oldSize, newSize));
- this.Watchers.WindowSizeWatcher.Reset();
- }
+ // raise events
+ this.OnLoadStageChanged(LoadStage.Ready);
+ events.SaveLoaded.RaiseEmpty();
+ events.DayStarted.RaiseEmpty();
+ }
- /*********
- ** Input events (if window has focus)
- *********/
- if (this.IsActive)
- {
- // raise events
- bool isChatInput = Game1.IsChatting || (Context.IsMultiplayer && Context.IsWorldReady && Game1.activeClickableMenu == null && Game1.currentMinigame == null && inputState.IsAnyDown(Game1.options.chatButton));
- if (!isChatInput)
+ /*********
+ ** Window events
+ *********/
+ // Here we depend on the game's viewport instead of listening to the Window.Resize
+ // event because we need to notify mods after the game handles the resize, so the
+ // game's metadata (like Game1.viewport) are updated. That's a bit complicated
+ // since the game adds & removes its own handler on the fly.
+ if (this.Watchers.WindowSizeWatcher.IsChanged)
{
- ICursorPosition cursor = this.Input.CursorPosition;
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log($"Events: window size changed to {this.Watchers.WindowSizeWatcher.CurrentValue}.", LogLevel.Trace);
- // raise cursor moved event
- if (this.Watchers.CursorWatcher.IsChanged)
- {
- if (events.CursorMoved.HasListeners())
- {
- ICursorPosition was = this.Watchers.CursorWatcher.PreviousValue;
- ICursorPosition now = this.Watchers.CursorWatcher.CurrentValue;
- this.Watchers.CursorWatcher.Reset();
+ Point oldSize = this.Watchers.WindowSizeWatcher.PreviousValue;
+ Point newSize = this.Watchers.WindowSizeWatcher.CurrentValue;
- events.CursorMoved.Raise(new CursorMovedEventArgs(was, now));
- }
- else
- this.Watchers.CursorWatcher.Reset();
- }
+ events.WindowResized.Raise(new WindowResizedEventArgs(oldSize, newSize));
+ this.Watchers.WindowSizeWatcher.Reset();
+ }
- // raise mouse wheel scrolled
- if (this.Watchers.MouseWheelScrollWatcher.IsChanged)
+ /*********
+ ** Input events (if window has focus)
+ *********/
+ if (this.IsActive)
+ {
+ // raise events
+ bool isChatInput = Game1.IsChatting || (Context.IsMultiplayer && Context.IsWorldReady && Game1.activeClickableMenu == null && Game1.currentMinigame == null && inputState.IsAnyDown(Game1.options.chatButton));
+ if (!isChatInput)
{
- if (events.MouseWheelScrolled.HasListeners() || this.Monitor.IsVerbose)
+ ICursorPosition cursor = this.Input.CursorPosition;
+
+ // raise cursor moved event
+ if (this.Watchers.CursorWatcher.IsChanged)
{
- int was = this.Watchers.MouseWheelScrollWatcher.PreviousValue;
- int now = this.Watchers.MouseWheelScrollWatcher.CurrentValue;
- this.Watchers.MouseWheelScrollWatcher.Reset();
+ if (events.CursorMoved.HasListeners())
+ {
+ ICursorPosition was = this.Watchers.CursorWatcher.PreviousValue;
+ ICursorPosition now = this.Watchers.CursorWatcher.CurrentValue;
+ this.Watchers.CursorWatcher.Reset();
- if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Events: mouse wheel scrolled to {now}.", LogLevel.Trace);
- events.MouseWheelScrolled.Raise(new MouseWheelScrolledEventArgs(cursor, was, now));
+ events.CursorMoved.Raise(new CursorMovedEventArgs(was, now));
+ }
+ else
+ this.Watchers.CursorWatcher.Reset();
}
- else
- this.Watchers.MouseWheelScrollWatcher.Reset();
- }
-
- // raise input button events
- foreach (var pair in inputState.ActiveButtons)
- {
- SButton button = pair.Key;
- InputStatus status = pair.Value;
- if (status == InputStatus.Pressed)
+ // raise mouse wheel scrolled
+ if (this.Watchers.MouseWheelScrollWatcher.IsChanged)
{
- if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Events: button {button} pressed.", LogLevel.Trace);
+ if (events.MouseWheelScrolled.HasListeners() || this.Monitor.IsVerbose)
+ {
+ int was = this.Watchers.MouseWheelScrollWatcher.PreviousValue;
+ int now = this.Watchers.MouseWheelScrollWatcher.CurrentValue;
+ this.Watchers.MouseWheelScrollWatcher.Reset();
- events.ButtonPressed.Raise(new ButtonPressedEventArgs(button, cursor, inputState));
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log($"Events: mouse wheel scrolled to {now}.", LogLevel.Trace);
+ events.MouseWheelScrolled.Raise(new MouseWheelScrolledEventArgs(cursor, was, now));
+ }
+ else
+ this.Watchers.MouseWheelScrollWatcher.Reset();
}
- else if (status == InputStatus.Released)
+
+ // raise input button events
+ foreach (var pair in inputState.ActiveButtons)
{
- if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Events: button {button} released.", LogLevel.Trace);
+ SButton button = pair.Key;
+ InputStatus status = pair.Value;
+
+ if (status == InputStatus.Pressed)
+ {
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log($"Events: button {button} pressed.", LogLevel.Trace);
- events.ButtonReleased.Raise(new ButtonReleasedEventArgs(button, cursor, inputState));
+ events.ButtonPressed.Raise(new ButtonPressedEventArgs(button, cursor, inputState));
+ }
+ else if (status == InputStatus.Released)
+ {
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log($"Events: button {button} released.", LogLevel.Trace);
+
+ events.ButtonReleased.Raise(new ButtonReleasedEventArgs(button, cursor, inputState));
+ }
}
}
}
- }
-
- /*********
- ** Menu events
- *********/
- if (this.Watchers.ActiveMenuWatcher.IsChanged)
- {
- IClickableMenu was = this.Watchers.ActiveMenuWatcher.PreviousValue;
- IClickableMenu now = this.Watchers.ActiveMenuWatcher.CurrentValue;
- this.Watchers.ActiveMenuWatcher.Reset(); // reset here so a mod changing the menu will be raised as a new event afterwards
- if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Context: menu changed from {was?.GetType().FullName ?? "none"} to {now?.GetType().FullName ?? "none"}.", LogLevel.Trace);
+ /*********
+ ** Menu events
+ *********/
+ if (this.Watchers.ActiveMenuWatcher.IsChanged)
+ {
+ IClickableMenu was = this.Watchers.ActiveMenuWatcher.PreviousValue;
+ IClickableMenu now = this.Watchers.ActiveMenuWatcher.CurrentValue;
+ this.Watchers.ActiveMenuWatcher.Reset(); // reset here so a mod changing the menu will be raised as a new event afterwards
- // raise menu events
- events.MenuChanged.Raise(new MenuChangedEventArgs(was, now));
- }
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log($"Context: menu changed from {was?.GetType().FullName ?? "none"} to {now?.GetType().FullName ?? "none"}.", LogLevel.Trace);
- /*********
- ** World & player events
- *********/
- if (Context.IsWorldReady)
- {
- bool raiseWorldEvents = !this.Watchers.SaveIdWatcher.IsChanged; // don't report changes from unloaded => loaded
+ // raise menu events
+ events.MenuChanged.Raise(new MenuChangedEventArgs(was, now));
+ }
- // raise location changes
- if (this.Watchers.LocationsWatcher.IsChanged)
+ /*********
+ ** World & player events
+ *********/
+ if (Context.IsWorldReady)
{
- // location list changes
- if (this.Watchers.LocationsWatcher.IsLocationListChanged)
- {
- GameLocation[] added = this.Watchers.LocationsWatcher.Added.ToArray();
- GameLocation[] removed = this.Watchers.LocationsWatcher.Removed.ToArray();
- this.Watchers.LocationsWatcher.ResetLocationList();
+ bool raiseWorldEvents = !this.Watchers.SaveIdWatcher.IsChanged; // don't report changes from unloaded => loaded
- if (this.Monitor.IsVerbose)
+ // raise location changes
+ if (this.Watchers.LocationsWatcher.IsChanged)
+ {
+ // location list changes
+ if (this.Watchers.LocationsWatcher.IsLocationListChanged)
{
- string addedText = added.Any() ? string.Join(", ", added.Select(p => p.Name)) : "none";
- string removedText = removed.Any() ? string.Join(", ", removed.Select(p => p.Name)) : "none";
- this.Monitor.Log($"Context: location list changed (added {addedText}; removed {removedText}).", LogLevel.Trace);
- }
+ GameLocation[] added = this.Watchers.LocationsWatcher.Added.ToArray();
+ GameLocation[] removed = this.Watchers.LocationsWatcher.Removed.ToArray();
+ this.Watchers.LocationsWatcher.ResetLocationList();
- events.LocationListChanged.Raise(new LocationListChangedEventArgs(added, removed));
- }
+ if (this.Monitor.IsVerbose)
+ {
+ string addedText = added.Any() ? string.Join(", ", added.Select(p => p.Name)) : "none";
+ string removedText = removed.Any() ? string.Join(", ", removed.Select(p => p.Name)) : "none";
+ this.Monitor.Log($"Context: location list changed (added {addedText}; removed {removedText}).", LogLevel.Trace);
+ }
- // raise location contents changed
- if (raiseWorldEvents)
- {
- foreach (LocationTracker watcher in this.Watchers.LocationsWatcher.Locations)
+ events.LocationListChanged.Raise(new LocationListChangedEventArgs(added, removed));
+ }
+
+ // raise location contents changed
+ if (raiseWorldEvents)
{
- // buildings changed
- if (watcher.BuildingsWatcher.IsChanged)
+ foreach (LocationTracker watcher in this.Watchers.LocationsWatcher.Locations)
{
- GameLocation location = watcher.Location;
- Building[] added = watcher.BuildingsWatcher.Added.ToArray();
- Building[] removed = watcher.BuildingsWatcher.Removed.ToArray();
- watcher.BuildingsWatcher.Reset();
+ // buildings changed
+ if (watcher.BuildingsWatcher.IsChanged)
+ {
+ GameLocation location = watcher.Location;
+ Building[] added = watcher.BuildingsWatcher.Added.ToArray();
+ Building[] removed = watcher.BuildingsWatcher.Removed.ToArray();
+ watcher.BuildingsWatcher.Reset();
- events.BuildingListChanged.Raise(new BuildingListChangedEventArgs(location, added, removed));
- }
+ events.BuildingListChanged.Raise(new BuildingListChangedEventArgs(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();
+ // 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();
- events.DebrisListChanged.Raise(new DebrisListChangedEventArgs(location, added, removed));
- }
+ events.DebrisListChanged.Raise(new DebrisListChangedEventArgs(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();
+ // 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();
- events.LargeTerrainFeatureListChanged.Raise(new LargeTerrainFeatureListChangedEventArgs(location, added, removed));
- }
+ events.LargeTerrainFeatureListChanged.Raise(new LargeTerrainFeatureListChangedEventArgs(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();
+ // 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();
- events.NpcListChanged.Raise(new NpcListChangedEventArgs(location, added, removed));
- }
+ events.NpcListChanged.Raise(new NpcListChangedEventArgs(location, added, removed));
+ }
- // objects changed
- if (watcher.ObjectsWatcher.IsChanged)
- {
- GameLocation location = watcher.Location;
- KeyValuePair<Vector2, SObject>[] added = watcher.ObjectsWatcher.Added.ToArray();
- KeyValuePair<Vector2, SObject>[] removed = watcher.ObjectsWatcher.Removed.ToArray();
- watcher.ObjectsWatcher.Reset();
+ // objects changed
+ if (watcher.ObjectsWatcher.IsChanged)
+ {
+ GameLocation location = watcher.Location;
+ KeyValuePair<Vector2, SObject>[] added = watcher.ObjectsWatcher.Added.ToArray();
+ KeyValuePair<Vector2, SObject>[] removed = watcher.ObjectsWatcher.Removed.ToArray();
+ watcher.ObjectsWatcher.Reset();
- events.ObjectListChanged.Raise(new ObjectListChangedEventArgs(location, added, removed));
- }
+ events.ObjectListChanged.Raise(new ObjectListChangedEventArgs(location, added, removed));
+ }
- // terrain features changed
- if (watcher.TerrainFeaturesWatcher.IsChanged)
- {
- GameLocation location = watcher.Location;
- KeyValuePair<Vector2, TerrainFeature>[] added = watcher.TerrainFeaturesWatcher.Added.ToArray();
- KeyValuePair<Vector2, TerrainFeature>[] removed = watcher.TerrainFeaturesWatcher.Removed.ToArray();
- watcher.TerrainFeaturesWatcher.Reset();
+ // terrain features changed
+ if (watcher.TerrainFeaturesWatcher.IsChanged)
+ {
+ GameLocation location = watcher.Location;
+ KeyValuePair<Vector2, TerrainFeature>[] added = watcher.TerrainFeaturesWatcher.Added.ToArray();
+ KeyValuePair<Vector2, TerrainFeature>[] removed = watcher.TerrainFeaturesWatcher.Removed.ToArray();
+ watcher.TerrainFeaturesWatcher.Reset();
- events.TerrainFeatureListChanged.Raise(new TerrainFeatureListChangedEventArgs(location, added, removed));
+ events.TerrainFeatureListChanged.Raise(new TerrainFeatureListChangedEventArgs(location, added, removed));
+ }
}
}
+ else
+ this.Watchers.LocationsWatcher.Reset();
}
- else
- this.Watchers.LocationsWatcher.Reset();
- }
-
- // raise time changed
- if (raiseWorldEvents && this.Watchers.TimeWatcher.IsChanged)
- {
- int was = this.Watchers.TimeWatcher.PreviousValue;
- int now = this.Watchers.TimeWatcher.CurrentValue;
- this.Watchers.TimeWatcher.Reset();
- if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Events: time changed from {was} to {now}.", LogLevel.Trace);
-
- events.TimeChanged.Raise(new TimeChangedEventArgs(was, now));
- }
- else
- this.Watchers.TimeWatcher.Reset();
-
- // raise player events
- if (raiseWorldEvents)
- {
- PlayerTracker playerTracker = this.Watchers.CurrentPlayerTracker;
-
- // raise current location changed
- if (playerTracker.TryGetNewLocation(out GameLocation newLocation))
+ // raise time changed
+ if (raiseWorldEvents && this.Watchers.TimeWatcher.IsChanged)
{
+ int was = this.Watchers.TimeWatcher.PreviousValue;
+ int now = this.Watchers.TimeWatcher.CurrentValue;
+ this.Watchers.TimeWatcher.Reset();
+
if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Context: set location to {newLocation.Name}.", LogLevel.Trace);
+ this.Monitor.Log($"Events: time changed from {was} to {now}.", LogLevel.Trace);
- GameLocation oldLocation = playerTracker.LocationWatcher.PreviousValue;
- events.Warped.Raise(new WarpedEventArgs(playerTracker.Player, oldLocation, newLocation));
+ events.TimeChanged.Raise(new TimeChangedEventArgs(was, now));
}
+ else
+ this.Watchers.TimeWatcher.Reset();
- // raise player leveled up a skill
- foreach (KeyValuePair<SkillType, IValueWatcher<int>> pair in playerTracker.GetChangedSkills())
+ // raise player events
+ if (raiseWorldEvents)
{
- if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Events: player skill '{pair.Key}' changed from {pair.Value.PreviousValue} to {pair.Value.CurrentValue}.", LogLevel.Trace);
+ PlayerTracker playerTracker = this.Watchers.CurrentPlayerTracker;
- events.LevelChanged.Raise(new LevelChangedEventArgs(playerTracker.Player, pair.Key, pair.Value.PreviousValue, pair.Value.CurrentValue));
- }
+ // raise current location changed
+ if (playerTracker.TryGetNewLocation(out GameLocation newLocation))
+ {
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log($"Context: set location to {newLocation.Name}.", LogLevel.Trace);
- // raise player inventory changed
- ItemStackChange[] changedItems = playerTracker.GetInventoryChanges().ToArray();
- if (changedItems.Any())
- {
- if (this.Monitor.IsVerbose)
- this.Monitor.Log("Events: player inventory changed.", LogLevel.Trace);
- events.InventoryChanged.Raise(new InventoryChangedEventArgs(playerTracker.Player, changedItems));
- }
+ GameLocation oldLocation = playerTracker.LocationWatcher.PreviousValue;
+ events.Warped.Raise(new WarpedEventArgs(playerTracker.Player, oldLocation, newLocation));
+ }
- // raise mine level changed
- if (playerTracker.TryGetNewMineLevel(out int mineLevel))
- {
- if (this.Monitor.IsVerbose)
- this.Monitor.Log($"Context: mine level changed to {mineLevel}.", LogLevel.Trace);
+ // raise player leveled up a skill
+ foreach (KeyValuePair<SkillType, IValueWatcher<int>> pair in playerTracker.GetChangedSkills())
+ {
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log($"Events: player skill '{pair.Key}' changed from {pair.Value.PreviousValue} to {pair.Value.CurrentValue}.", LogLevel.Trace);
+
+ events.LevelChanged.Raise(new LevelChangedEventArgs(playerTracker.Player, pair.Key, pair.Value.PreviousValue, pair.Value.CurrentValue));
+ }
+
+ // raise player inventory changed
+ ItemStackChange[] changedItems = playerTracker.GetInventoryChanges().ToArray();
+ if (changedItems.Any())
+ {
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log("Events: player inventory changed.", LogLevel.Trace);
+ events.InventoryChanged.Raise(new InventoryChangedEventArgs(playerTracker.Player, changedItems));
+ }
+
+ // raise mine level changed
+ if (playerTracker.TryGetNewMineLevel(out int mineLevel))
+ {
+ if (this.Monitor.IsVerbose)
+ this.Monitor.Log($"Context: mine level changed to {mineLevel}.", LogLevel.Trace);
+ }
}
+ this.Watchers.CurrentPlayerTracker?.Reset();
+
+ // update save ID watcher
+ this.Watchers.SaveIdWatcher.Reset();
+ }
+
+ /*********
+ ** Game update
+ *********/
+ // game launched
+ bool isFirstTick = SGame.TicksElapsed == 0;
+ if (isFirstTick)
+ {
+ Context.IsGameLaunched = true;
+ events.GameLaunched.Raise(new GameLaunchedEventArgs());
}
- this.Watchers.CurrentPlayerTracker?.Reset();
- }
- // update save ID watcher
- this.Watchers.SaveIdWatcher.Reset();
+ // preloaded
+ if (Context.IsSaveLoaded && Context.LoadStage != LoadStage.Loaded && Context.LoadStage != LoadStage.Ready && Game1.dayOfMonth != 0)
+ this.OnLoadStageChanged(LoadStage.Loaded);
+ }
/*********
- ** Game update
+ ** Game update tick
*********/
- // game launched
- bool isFirstTick = SGame.TicksElapsed == 0;
- if (isFirstTick)
{
- Context.IsGameLaunched = true;
- events.GameLaunched.Raise(new GameLaunchedEventArgs());
- }
-
- // preloaded
- if (Context.IsSaveLoaded && Context.LoadStage != LoadStage.Loaded && Context.LoadStage != LoadStage.Ready && Game1.dayOfMonth != 0)
- this.OnLoadStageChanged(LoadStage.Loaded);
+ bool isOneSecond = SGame.TicksElapsed % 60 == 0;
+ events.UnvalidatedUpdateTicking.RaiseEmpty();
+ events.UpdateTicking.RaiseEmpty();
+ if (isOneSecond)
+ events.OneSecondUpdateTicking.RaiseEmpty();
+ try
+ {
+ this.Input.UpdateSuppression();
+ SGame.TicksElapsed++;
+ base.Update(gameTime);
+ }
+ catch (Exception ex)
+ {
+ this.MonitorForGame.Log($"An error occured in the base update loop: {ex.GetLogSummary()}", LogLevel.Error);
+ }
- // update tick
- bool isOneSecond = SGame.TicksElapsed % 60 == 0;
- events.UnvalidatedUpdateTicking.RaiseEmpty();
- events.UpdateTicking.RaiseEmpty();
- if (isOneSecond)
- events.OneSecondUpdateTicking.RaiseEmpty();
- try
- {
- this.Input.UpdateSuppression();
- SGame.TicksElapsed++;
- base.Update(gameTime);
- }
- catch (Exception ex)
- {
- this.MonitorForGame.Log($"An error occured in the base update loop: {ex.GetLogSummary()}", LogLevel.Error);
+ events.UnvalidatedUpdateTicked.RaiseEmpty();
+ events.UpdateTicked.RaiseEmpty();
+ if (isOneSecond)
+ events.OneSecondUpdateTicked.RaiseEmpty();
}
- events.UnvalidatedUpdateTicked.RaiseEmpty();
- events.UpdateTicked.RaiseEmpty();
- if (isOneSecond)
- events.OneSecondUpdateTicked.RaiseEmpty();
/*********
** Update events