From 624840efe5f3d4135dafeb2939b182cfeb4ec6c3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 7 May 2017 13:09:32 -0400 Subject: use more robust sprite batch recovery logic (#283) --- .../Framework/InternalExtensions.cs | 22 ++++++++++++++++++ src/StardewModdingAPI/Framework/SGame.cs | 27 +++++++++++----------- 2 files changed, 36 insertions(+), 13 deletions(-) (limited to 'src/StardewModdingAPI/Framework') diff --git a/src/StardewModdingAPI/Framework/InternalExtensions.cs b/src/StardewModdingAPI/Framework/InternalExtensions.cs index 5199c72d..cadf6598 100644 --- a/src/StardewModdingAPI/Framework/InternalExtensions.cs +++ b/src/StardewModdingAPI/Framework/InternalExtensions.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.Xna.Framework.Graphics; +using StardewValley; namespace StardewModdingAPI.Framework { @@ -128,5 +130,25 @@ namespace StardewModdingAPI.Framework deprecationManager.Warn(modName, nounPhrase, version, severity); } } + + /**** + ** Sprite batch + ****/ + /// Get whether the sprite batch is between a begin and end pair. + /// The sprite batch to check. + /// The reflection helper with which to access private fields. + public static bool IsOpen(this SpriteBatch spriteBatch, IReflectionHelper reflection) + { + // get field name + const string fieldName = +#if SMAPI_FOR_WINDOWS + "inBeginEndPair"; +#else + "_beginCalled"; +#endif + + // get result + return reflection.GetPrivateValue(Game1.spriteBatch, fieldName); + } } } diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index f8226529..7dae937b 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -38,7 +38,7 @@ namespace StardewModdingAPI.Framework private readonly int MaxFailedDraws = 120; // roughly two seconds /// The number of consecutive failed draws. - private int FailedDraws = 0; + private int FailedDraws; /// Whether the player has loaded a save and the world has finished initialising. private bool IsWorldReady => this.AfterLoadTimer < 0; @@ -956,6 +956,9 @@ namespace StardewModdingAPI.Framework } 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) { @@ -964,22 +967,20 @@ namespace StardewModdingAPI.Framework } this.FailedDraws++; - // log error - this.Monitor.Log($"An error occured in the overridden draw loop: {ex.GetLogSummary()}", LogLevel.Error); - - // fix sprite batch + // recover sprite batch try { - bool isSpriteBatchOpen = -#if SMAPI_FOR_WINDOWS - SGame.Reflection.GetPrivateValue(Game1.spriteBatch, "inBeginEndPair"); -#else - SGame.Reflection.GetPrivateValue(Game1.spriteBatch, "_beginCalled"); -#endif - if (isSpriteBatchOpen) + if (Game1.spriteBatch.IsOpen(SGame.Reflection)) { this.Monitor.Log("Recovering sprite batch from error...", LogLevel.Trace); - Game1.spriteBatch.End(); + try + { + Game1.spriteBatch.End(); + } + catch + { + Game1.spriteBatch = new SpriteBatch(this.GraphicsDevice); // sprite batch is broken, try replacing it + } } } catch (Exception innerEx) -- cgit