From efec87065780426db15c51a7e68315ff488a89c0 Mon Sep 17 00:00:00 2001
From: Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com>
Date: Sat, 6 Feb 2021 13:03:37 -0500
Subject: fix edge case in non-English asset cache after returning to title
 screen

---
 docs/release-notes.md                     |  1 +
 src/SMAPI/Framework/ContentCoordinator.cs | 26 ++++++++++++++++++++++++++
 src/SMAPI/Framework/SCore.cs              |  1 +
 3 files changed, 28 insertions(+)

diff --git a/docs/release-notes.md b/docs/release-notes.md
index 9cea9fa9..9f4ea50a 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -14,6 +14,7 @@
 
 * For modders:
   * Fixed SMAPI toolkit defaulting the mod type incorrectly if a mod's `manifest.json` has neither `EntryDll` nor `ContentPackFor`. This only affects external tools, since SMAPI itself validates those fields separately.
+  * Fixed edge case when playing in non-English where translatable assets loaded via `IAssetLoader` would no longer be applied after returning to the title screen unless manually invalidated from the cache.
 
 ## 3.9.1
 Released 25 January 2021 for Stardew Valley 1.5.4 or later.
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index 6a7385c3..b7c15526 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -203,6 +203,32 @@ namespace StardewModdingAPI.Framework
             });
         }
 
+        /// <summary>Clean up when the player is returning to the title screen.</summary>
+        /// <remarks>This is called after the player returns to the title screen, but before <see cref="Game1.CleanupReturningToTitle"/> runs.</remarks>
+        public void OnReturningToTitleScreen()
+        {
+            // The game clears LocalizedContentManager.localizedAssetNames after returning to the title screen. That
+            // causes an inconsistency in the SMAPI asset cache, which leads to an edge case where assets already
+            // provided by mods via IAssetLoader when playing in non-English are ignored.
+            //
+            // For example, let's say a mod provides the 'Data\mail' asset through IAssetLoader when playing in
+            // Portuguese. Here's the normal load process after it's loaded:
+            //   1. The game requests Data\mail.
+            //   2. SMAPI sees that it's already cached, and calls LoadRaw to bypass asset interception.
+            //   3. LoadRaw sees that there's a localized key mapping, and gets the mapped key.
+            //   4. In this case "Data\mail" is mapped to "Data\mail" since it was loaded by a mod, so it loads that
+            //      asset.
+            //
+            // When the game clears localizedAssetNames, that process goes wrong in step 4:
+            //  3. LoadRaw sees that there's no localized key mapping *and* the locale is non-English, so it attempts
+            //     to load from the localized key format.
+            //  4. In this case that's 'Data\mail.pt-BR', so it successfully loads that asset.
+            //  5. Since we've bypassed asset interception at this point, it's loaded directly from the base content
+            //     manager without mod changes.
+
+            this.InvalidateCache(asset => true);
+        }
+
         /// <summary>Get whether this asset is mapped to a mod folder.</summary>
         /// <param name="key">The asset key.</param>
         public bool IsManagedAssetKey(string key)
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index 0ae69f0f..2d783eb2 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -1118,6 +1118,7 @@ namespace StardewModdingAPI.Framework
         {
             // perform cleanup
             this.Multiplayer.CleanupOnMultiplayerExit();
+            this.ContentCore.OnReturningToTitleScreen();
             this.JustReturnedToTitle = true;
         }
 
-- 
cgit