diff options
Diffstat (limited to 'src/StardewModdingAPI/Framework/SGame.cs')
-rw-r--r-- | src/StardewModdingAPI/Framework/SGame.cs | 192 |
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; } /********* |