summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs27
-rw-r--r--src/SMAPI/Framework/ContentManagers/BaseContentManager.cs3
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManager.cs25
-rw-r--r--src/SMAPI/Framework/ContentManagers/IContentManager.cs10
4 files changed, 41 insertions, 24 deletions
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index b7c15526..32195fff 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -54,7 +54,7 @@ namespace StardewModdingAPI.Framework
private bool IsDisposed;
/// <summary>A lock used to prevent asynchronous changes to the content manager list.</summary>
- /// <remarks>The game may adds content managers in asynchronous threads (e.g. when populating the load screen).</remarks>
+ /// <remarks>The game may add content managers in asynchronous threads (e.g. when populating the load screen).</remarks>
private readonly ReaderWriterLockSlim ContentManagerLock = new ReaderWriterLockSlim();
/// <summary>A cache of ordered tilesheet IDs used by vanilla maps.</summary>
@@ -207,26 +207,11 @@ namespace StardewModdingAPI.Framework
/// <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);
+ this.ContentManagerLock.InReadLock(() =>
+ {
+ foreach (IContentManager contentManager in this.ContentManagers)
+ contentManager.OnReturningToTitleScreen();
+ });
}
/// <summary>Get whether this asset is mapped to a mod folder.</summary>
diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
index 709c624e..b6b3a7a0 100644
--- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
@@ -133,6 +133,9 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>Perform any cleanup needed when the locale changes.</summary>
public virtual void OnLocaleChanged() { }
+ /// <inheritdoc />
+ public virtual void OnReturningToTitleScreen() { }
+
/// <summary>Normalize path separators in a file path. For asset keys, see <see cref="AssertAndNormalizeAssetName"/> instead.</summary>
/// <param name="path">The file path to normalize.</param>
[Pure]
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
index f8ee575f..e3d1e569 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
@@ -140,6 +140,31 @@ namespace StardewModdingAPI.Framework.ContentManagers
this.Monitor.Log($"Invalidated {invalidated.Length} asset names: {string.Join(", ", invalidated)} for locale change.", LogLevel.Trace);
}
+ /// <inheritdoc />
+ public override 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.
+ if (LocalizedContentManager.CurrentLanguageCode != LocalizedContentManager.LanguageCode.en)
+ this.InvalidateCache((_, _) => true);
+ }
+
/// <summary>Create a new content manager for temporary use.</summary>
public override LocalizedContentManager CreateTemporary()
{
diff --git a/src/SMAPI/Framework/ContentManagers/IContentManager.cs b/src/SMAPI/Framework/ContentManagers/IContentManager.cs
index 0e7edd8f..1e222472 100644
--- a/src/SMAPI/Framework/ContentManagers/IContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/IContentManager.cs
@@ -36,9 +36,6 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
T Load<T>(string assetName, LocalizedContentManager.LanguageCode language, bool useCache);
- /// <summary>Perform any cleanup needed when the locale changes.</summary>
- void OnLocaleChanged();
-
/// <summary>Normalize path separators in a file path. For asset keys, see <see cref="AssertAndNormalizeAssetName"/> instead.</summary>
/// <param name="path">The file path to normalize.</param>
[Pure]
@@ -69,5 +66,12 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <param name="dispose">Whether to dispose invalidated assets. This should only be <c>true</c> when they're being invalidated as part of a dispose, to avoid crashing the game.</param>
/// <returns>Returns the invalidated asset names and instances.</returns>
IDictionary<string, object> InvalidateCache(Func<string, Type, bool> predicate, bool dispose = false);
+
+ /// <summary>Perform any cleanup needed when the locale changes.</summary>
+ void OnLocaleChanged();
+
+ /// <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>
+ void OnReturningToTitleScreen();
}
}