fix error on Linux/Mac when a mod tries to load content immediately after save is loaded

This commit is contained in:
Jesse Plamondon-Willard 2017-05-12 21:09:20 -04:00
parent e84028f22b
commit 588b42742d
2 changed files with 662 additions and 656 deletions

View File

@ -18,6 +18,7 @@ For players:
* SMAPI now remembers if your game crashed and offers help next time you relaunch. * SMAPI now remembers if your game crashed and offers help next time you relaunch.
* Fixed installer finding redundant game paths on Linux. * Fixed installer finding redundant game paths on Linux.
* Fixed save events not being raised after the first day on Linux/Mac. * Fixed save events not being raised after the first day on Linux/Mac.
* Fixed error on Linux/Mac when a mod tries to load content immediately after the save is loaded.
For mod developers: For mod developers:
* Added log entries for basic context changes (e.g. loaded save) to simplify troubleshooting. More detailed logging can be enabled by setting `VerboseLogging: true` in `StardewModdingAPI.config.json`. * Added log entries for basic context changes (e.g. loaded save) to simplify troubleshooting. More detailed logging can be enabled by setting `VerboseLogging: true` in `StardewModdingAPI.config.json`.

View File

@ -264,7 +264,7 @@ namespace StardewModdingAPI.Framework
base.Update(gameTime); base.Update(gameTime);
return; return;
} }
if(this.IsBetweenSaveEvents) if (this.IsBetweenSaveEvents)
{ {
// raise after-save // raise after-save
this.IsBetweenSaveEvents = false; this.IsBetweenSaveEvents = false;
@ -579,6 +579,53 @@ namespace StardewModdingAPI.Framework
/// <summary>The method called to draw everything to the screen.</summary> /// <summary>The method called to draw everything to the screen.</summary>
/// <param name="gameTime">A snapshot of the game timing state.</param> /// <param name="gameTime">A snapshot of the game timing state.</param>
protected override void Draw(GameTime gameTime)
{
Context.IsInDrawLoop = true;
try
{
this.DrawImpl(gameTime);
this.FailedDraws = 0;
}
catch (Exception ex)
{
// log error
this.Monitor.Log($"An error occured in the overridden draw loop: {ex.GetLogSummary()}", LogLevel.Error);
// exit if irrecoverable
if (this.FailedDraws >= this.MaxFailedDraws)
{
this.Monitor.ExitGameImmediately("the game crashed when drawing, and SMAPI was unable to recover the game.");
return;
}
this.FailedDraws++;
// abort in known unrecoverable cases
if (Game1.toolSpriteSheet?.IsDisposed == true)
{
this.Monitor.ExitGameImmediately("the game unexpectedly disposed the tool spritesheet, so it crashed trying to draw a tool. This is a known bug in Stardew Valley 1.2.29, and there's no way to recover from it.");
return;
}
// recover sprite batch
try
{
if (Game1.spriteBatch.IsOpen(SGame.Reflection))
{
this.Monitor.Log("Recovering sprite batch from error...", LogLevel.Trace);
Game1.spriteBatch.End();
}
}
catch (Exception innerEx)
{
this.Monitor.Log($"Could not recover sprite batch state: {innerEx.GetLogSummary()}", LogLevel.Error);
}
}
Context.IsInDrawLoop = false;
}
/// <summary>Replicate the game's draw logic with some changes for SMAPI.</summary>
/// <param name="gameTime">A snapshot of the game timing state.</param>
/// <remarks>This implementation is identical to <see cref="Game1.Draw"/>, except for try..catch around menu draw code, private field references replaced by wrappers, and added events.</remarks> /// <remarks>This implementation is identical to <see cref="Game1.Draw"/>, except for try..catch around menu draw code, private field references replaced by wrappers, and added events.</remarks>
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator", Justification = "copied from game code as-is")]
[SuppressMessage("ReSharper", "LocalVariableHidesMember", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "LocalVariableHidesMember", Justification = "copied from game code as-is")]
@ -587,10 +634,7 @@ namespace StardewModdingAPI.Framework
[SuppressMessage("ReSharper", "RedundantCast", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "RedundantCast", Justification = "copied from game code as-is")]
[SuppressMessage("ReSharper", "RedundantExplicitNullableCreation", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "RedundantExplicitNullableCreation", Justification = "copied from game code as-is")]
[SuppressMessage("ReSharper", "RedundantTypeArgumentsOfMethod", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "RedundantTypeArgumentsOfMethod", Justification = "copied from game code as-is")]
protected override void Draw(GameTime gameTime) private void DrawImpl(GameTime gameTime)
{
Context.IsInDrawLoop = true;
try
{ {
if (Game1.debugMode) if (Game1.debugMode)
{ {
@ -1236,45 +1280,6 @@ namespace StardewModdingAPI.Framework
} }
} }
} }
// reset failed draw count
this.FailedDraws = 0;
}
catch (Exception ex)
{
// log error
this.Monitor.Log($"An error occured in the overridden draw loop: {ex.GetLogSummary()}", LogLevel.Error);
// exit if irrecoverable
if (this.FailedDraws >= this.MaxFailedDraws)
{
this.Monitor.ExitGameImmediately("the game crashed when drawing, and SMAPI was unable to recover the game.");
return;
}
this.FailedDraws++;
// abort in known unrecoverable cases
if (Game1.toolSpriteSheet?.IsDisposed == true)
{
this.Monitor.ExitGameImmediately("the game unexpectedly disposed the tool spritesheet, so it crashed trying to draw a tool. This is a known bug in Stardew Valley 1.2.29, and there's no way to recover from it.");
return;
}
// recover sprite batch
try
{
if (Game1.spriteBatch.IsOpen(SGame.Reflection))
{
this.Monitor.Log("Recovering sprite batch from error...", LogLevel.Trace);
Game1.spriteBatch.End();
}
}
catch (Exception innerEx)
{
this.Monitor.Log($"Could not recover sprite batch state: {innerEx.GetLogSummary()}", LogLevel.Error);
}
}
Context.IsInDrawLoop = false;
} }
/**** /****