summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI/Framework/SGame.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/StardewModdingAPI/Framework/SGame.cs')
-rw-r--r--src/StardewModdingAPI/Framework/SGame.cs192
1 files changed, 92 insertions, 100 deletions
diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs
index 7ee72af2..a340b995 100644
--- a/src/StardewModdingAPI/Framework/SGame.cs
+++ b/src/StardewModdingAPI/Framework/SGame.cs
@@ -39,9 +39,6 @@ namespace StardewModdingAPI.Framework
/// <summary>The number of consecutive failed draws.</summary>
private int FailedDraws;
- /// <summary>Whether the player has loaded a save and the world has finished initialising.</summary>
- private bool IsWorldReady => this.AfterLoadTimer < 0;
-
/// <summary>Whether the game is returning to the menu.</summary>
private bool IsExiting;
@@ -90,6 +87,9 @@ namespace StardewModdingAPI.Framework
/// <summary>The keys that just entered the up state.</summary>
private Keys[] FrameReleasedKeys => this.PreviouslyPressedKeys.Except(this.CurrentlyPressedKeys).ToArray();
+ /// <summary>The previous save ID at last check.</summary>
+ private ulong PreviousSaveID;
+
/// <summary>A hash of <see cref="Game1.locations"/> at last check.</summary>
private int PreviousGameLocations;
@@ -168,7 +168,7 @@ namespace StardewModdingAPI.Framework
private static Stopwatch _fpsStopwatch => SGame.Reflection.GetPrivateField<Stopwatch>(typeof(Game1), nameof(SGame._fpsStopwatch)).GetValue();
private static float _fps
{
- set { SGame.Reflection.GetPrivateField<float>(typeof(Game1), nameof(_fps)).SetValue(value); }
+ set => SGame.Reflection.GetPrivateField<float>(typeof(Game1), nameof(_fps)).SetValue(value);
}
private static Task _newDayTask => SGame.Reflection.GetPrivateField<Task>(typeof(Game1), nameof(_newDayTask)).GetValue();
private Color bgColor => SGame.Reflection.GetPrivateField<Color>(this, nameof(bgColor)).GetValue();
@@ -202,6 +202,15 @@ namespace StardewModdingAPI.Framework
SGame.Reflection = reflection;
Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; // required by Stardew Valley
+
+ // The game uses the default content manager instead of Game1.CreateContentManager in
+ // several cases (See http://community.playstarbound.com/threads/130058/page-27#post-3159274).
+ // The workaround is...
+ // 1. Override the default content manager.
+ // 2. Since Game1.content isn't initialised yet, and we need one main instance to
+ // support custom map tilesheets, detect when Game1.content is being initialised
+ // and use the same instance.
+ this.Content = new SContentManager(this.Content.ServiceProvider, this.Content.RootDirectory, this.Monitor);
}
/****
@@ -212,6 +221,12 @@ namespace StardewModdingAPI.Framework
/// <param name="rootDirectory">The root directory to search for content.</param>
protected override LocalizedContentManager CreateContentManager(IServiceProvider serviceProvider, string rootDirectory)
{
+ // When Game1.content is being initialised, use SMAPI's main content manager instance.
+ // See comment in SGame constructor.
+ if (Game1.content == null && this.Content is SContentManager mainContentManager)
+ return mainContentManager;
+
+ // build new instance
return new SContentManager(this.Content.ServiceProvider, this.Content.RootDirectory, this.Monitor);
}
@@ -306,6 +321,7 @@ namespace StardewModdingAPI.Framework
if (this.AfterLoadTimer == 0)
{
this.Monitor.Log($"Context: loaded saved game '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace);
+ Context.IsWorldReady = true;
SaveEvents.InvokeAfterLoad(this.Monitor);
PlayerEvents.InvokeLoadedGame(this.Monitor, new EventArgsLoadedGameChanged(Game1.hasLoadedGame));
@@ -322,9 +338,11 @@ namespace StardewModdingAPI.Framework
this.IsExiting = true;
// after exit to title
- if (this.IsWorldReady && this.IsExiting && Game1.activeClickableMenu is TitleMenu)
+ if (Context.IsWorldReady && this.IsExiting && Game1.activeClickableMenu is TitleMenu)
{
this.Monitor.Log("Context: returned to title", LogLevel.Trace);
+ Context.IsWorldReady = false;
+
SaveEvents.InvokeAfterReturnToTitle(this.Monitor);
this.AfterLoadTimer = 5;
this.IsExiting = false;
@@ -418,109 +436,83 @@ namespace StardewModdingAPI.Framework
/*********
** World & player events
*********/
- if (this.IsWorldReady)
+ if (Context.IsWorldReady)
{
- // raise location list changed
- if (this.GetHash(Game1.locations) != this.PreviousGameLocations)
- {
- LocationEvents.InvokeLocationsChanged(this.Monitor, Game1.locations);
- this.PreviousGameLocations = this.GetHash(Game1.locations);
- }
-
- // raise current location changed
- if (Game1.currentLocation != this.PreviousGameLocation)
- {
- if (this.VerboseLogging)
- this.Monitor.Log($"Context: set location to {Game1.currentLocation?.Name ?? "(none)"}.", LogLevel.Trace);
- LocationEvents.InvokeCurrentLocationChanged(this.Monitor, this.PreviousGameLocation, Game1.currentLocation);
- this.PreviousGameLocation = Game1.currentLocation;
- }
-
- // raise player changed
- if (Game1.player != this.PreviousFarmer)
- {
- PlayerEvents.InvokeFarmerChanged(this.Monitor, this.PreviousFarmer, Game1.player);
- this.PreviousFarmer = Game1.player;
- }
-
- // raise player leveled up a skill
- if (Game1.player.combatLevel != this.PreviousCombatLevel)
- {
- PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Combat, Game1.player.combatLevel);
- this.PreviousCombatLevel = Game1.player.combatLevel;
- }
- if (Game1.player.farmingLevel != this.PreviousFarmingLevel)
- {
- PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Farming, Game1.player.farmingLevel);
- this.PreviousFarmingLevel = Game1.player.farmingLevel;
- }
- if (Game1.player.fishingLevel != this.PreviousFishingLevel)
- {
- PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Fishing, Game1.player.fishingLevel);
- this.PreviousFishingLevel = Game1.player.fishingLevel;
- }
- if (Game1.player.foragingLevel != this.PreviousForagingLevel)
- {
- PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Foraging, Game1.player.foragingLevel);
- this.PreviousForagingLevel = Game1.player.foragingLevel;
- }
- if (Game1.player.miningLevel != this.PreviousMiningLevel)
- {
- PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Mining, Game1.player.miningLevel);
- this.PreviousMiningLevel = Game1.player.miningLevel;
- }
- if (Game1.player.luckLevel != this.PreviousLuckLevel)
+ // raise events (only when something changes, not on the initial load)
+ if (Game1.uniqueIDForThisGame == this.PreviousSaveID)
{
- PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Luck, Game1.player.luckLevel);
- this.PreviousLuckLevel = Game1.player.luckLevel;
- }
+ // raise location list changed
+ if (this.GetHash(Game1.locations) != this.PreviousGameLocations)
+ LocationEvents.InvokeLocationsChanged(this.Monitor, Game1.locations);
- // raise player inventory changed
- ItemStackChange[] changedItems = this.GetInventoryChanges(Game1.player.items, this.PreviousItems).ToArray();
- if (changedItems.Any())
- {
- PlayerEvents.InvokeInventoryChanged(this.Monitor, Game1.player.items, changedItems);
- this.PreviousItems = Game1.player.items.Where(n => n != null).ToDictionary(n => n, n => n.Stack);
- }
-
- // raise current location's object list changed
- {
- int? objectHash = Game1.currentLocation?.objects != null ? this.GetHash(Game1.currentLocation.objects) : (int?)null;
- if (objectHash != null && this.PreviousLocationObjects != objectHash)
+ // raise current location changed
+ if (Game1.currentLocation != this.PreviousGameLocation)
{
- LocationEvents.InvokeOnNewLocationObject(this.Monitor, Game1.currentLocation.objects);
- this.PreviousLocationObjects = objectHash.Value;
+ if (this.VerboseLogging)
+ this.Monitor.Log($"Context: set location to {Game1.currentLocation?.Name ?? "(none)"}.", LogLevel.Trace);
+ LocationEvents.InvokeCurrentLocationChanged(this.Monitor, this.PreviousGameLocation, Game1.currentLocation);
}
- }
- // raise time changed
- if (Game1.timeOfDay != this.PreviousTime)
- {
- TimeEvents.InvokeTimeOfDayChanged(this.Monitor, this.PreviousTime, Game1.timeOfDay);
- this.PreviousTime = Game1.timeOfDay;
- }
- if (Game1.dayOfMonth != this.PreviousDay)
- {
- TimeEvents.InvokeDayOfMonthChanged(this.Monitor, this.PreviousDay, Game1.dayOfMonth);
- this.PreviousDay = Game1.dayOfMonth;
- }
- if (Game1.currentSeason != this.PreviousSeason)
- {
- TimeEvents.InvokeSeasonOfYearChanged(this.Monitor, this.PreviousSeason, Game1.currentSeason);
- this.PreviousSeason = Game1.currentSeason;
- }
- if (Game1.year != this.PreviousYear)
- {
- TimeEvents.InvokeYearOfGameChanged(this.Monitor, this.PreviousYear, Game1.year);
- this.PreviousYear = Game1.year;
- }
+ // raise player changed
+ if (Game1.player != this.PreviousFarmer)
+ PlayerEvents.InvokeFarmerChanged(this.Monitor, this.PreviousFarmer, Game1.player);
+
+ // raise player leveled up a skill
+ if (Game1.player.combatLevel != this.PreviousCombatLevel)
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Combat, Game1.player.combatLevel);
+ if (Game1.player.farmingLevel != this.PreviousFarmingLevel)
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Farming, Game1.player.farmingLevel);
+ if (Game1.player.fishingLevel != this.PreviousFishingLevel)
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Fishing, Game1.player.fishingLevel);
+ if (Game1.player.foragingLevel != this.PreviousForagingLevel)
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Foraging, Game1.player.foragingLevel);
+ if (Game1.player.miningLevel != this.PreviousMiningLevel)
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Mining, Game1.player.miningLevel);
+ if (Game1.player.luckLevel != this.PreviousLuckLevel)
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Luck, Game1.player.luckLevel);
+
+ // raise player inventory changed
+ ItemStackChange[] changedItems = this.GetInventoryChanges(Game1.player.items, this.PreviousItems).ToArray();
+ if (changedItems.Any())
+ PlayerEvents.InvokeInventoryChanged(this.Monitor, Game1.player.items, changedItems);
+
+ // raise current location's object list changed
+ if (this.GetHash(Game1.currentLocation.objects) != this.PreviousLocationObjects)
+ LocationEvents.InvokeOnNewLocationObject(this.Monitor, Game1.currentLocation.objects);
- // raise mine level changed
- if (Game1.mine != null && Game1.mine.mineLevel != this.PreviousMineLevel)
- {
- MineEvents.InvokeMineLevelChanged(this.Monitor, this.PreviousMineLevel, Game1.mine.mineLevel);
- this.PreviousMineLevel = Game1.mine.mineLevel;
+ // raise time changed
+ if (Game1.timeOfDay != this.PreviousTime)
+ TimeEvents.InvokeTimeOfDayChanged(this.Monitor, this.PreviousTime, Game1.timeOfDay);
+ if (Game1.dayOfMonth != this.PreviousDay)
+ TimeEvents.InvokeDayOfMonthChanged(this.Monitor, this.PreviousDay, Game1.dayOfMonth);
+ if (Game1.currentSeason != this.PreviousSeason)
+ TimeEvents.InvokeSeasonOfYearChanged(this.Monitor, this.PreviousSeason, Game1.currentSeason);
+ if (Game1.year != this.PreviousYear)
+ TimeEvents.InvokeYearOfGameChanged(this.Monitor, this.PreviousYear, Game1.year);
+
+ // raise mine level changed
+ if (Game1.mine != null && Game1.mine.mineLevel != this.PreviousMineLevel)
+ MineEvents.InvokeMineLevelChanged(this.Monitor, this.PreviousMineLevel, Game1.mine.mineLevel);
}
+
+ // update state
+ this.PreviousGameLocations = this.GetHash(Game1.locations);
+ this.PreviousGameLocation = Game1.currentLocation;
+ this.PreviousFarmer = Game1.player;
+ this.PreviousCombatLevel = Game1.player.combatLevel;
+ this.PreviousFarmingLevel = Game1.player.farmingLevel;
+ this.PreviousFishingLevel = Game1.player.fishingLevel;
+ this.PreviousForagingLevel = Game1.player.foragingLevel;
+ this.PreviousMiningLevel = Game1.player.miningLevel;
+ this.PreviousLuckLevel = Game1.player.luckLevel;
+ this.PreviousItems = Game1.player.items.Where(n => n != null).ToDictionary(n => n, n => n.Stack);
+ this.PreviousLocationObjects = this.GetHash(Game1.currentLocation.objects);
+ this.PreviousTime = Game1.timeOfDay;
+ this.PreviousDay = Game1.dayOfMonth;
+ this.PreviousSeason = Game1.currentSeason;
+ this.PreviousYear = Game1.year;
+ this.PreviousMineLevel = Game1.mine.mineLevel;
+ this.PreviousSaveID = Game1.uniqueIDForThisGame;
}
/*********