diff --git a/docs/release-notes.md b/docs/release-notes.md
index a8f8ccfd8..98392c17c 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -10,6 +10,7 @@
* Added `--use-current-shell` to avoid opening a separate terminal window.
* Fixed `--no-terminal` still opening a terminal window, even if nothing is logged to it (thanks to Ryhon0!).
* Fixed warning text when a mod causes an asset load conflict with itself.
+ * Fixed support for `_international` content assets (used in the movie theater).
* For mod authors:
* Added [content events](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Events#Content), which will replace `IAssetEditor` and `IAssetLoader` in SMAPI 4.0.0.
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index 8e7465de9..a4d290681 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -61,9 +61,6 @@ internal class ContentCoordinator : IDisposable
/// The loaded content managers (including the ).
private readonly List ContentManagers = new();
- /// The language code for language-agnostic mod assets.
- private readonly LocalizedContentManager.LanguageCode DefaultLanguage = Constants.DefaultLanguage;
-
/// Whether the content coordinator has been disposed.
private bool IsDisposed;
@@ -350,7 +347,7 @@ public T LoadManagedAsset(string contentManagerID, IAssetName relativePath)
throw new InvalidOperationException($"The '{contentManagerID}' prefix isn't handled by any mod.");
// get fresh asset
- return contentManager.Load(relativePath, this.DefaultLanguage, useCache: false);
+ return contentManager.LoadExact(relativePath, useCache: false);
}
/// Purge matched assets from the cache.
@@ -467,9 +464,9 @@ public IEnumerable GetLoadedValues(IAssetName assetName)
return this.ContentManagerLock.InReadLock(() =>
{
List values = new List();
- foreach (IContentManager content in this.ContentManagers.Where(p => !p.IsNamespaced && p.IsLoaded(assetName, p.Language)))
+ foreach (IContentManager content in this.ContentManagers.Where(p => !p.IsNamespaced && p.IsLoaded(assetName)))
{
- object value = content.Load(assetName, this.Language, useCache: true);
+ object value = content.LoadExact(assetName, useCache: true);
values.Add(value);
}
return values;
@@ -582,6 +579,8 @@ private bool TryLoadVanillaAsset(string assetName, out T asset)
/// The asset info to load or edit.
private IEnumerable GetAssetOperationsWithoutCache(IAssetInfo info)
{
+ IAssetInfo legacyInfo = this.GetLegacyAssetInfo(info);
+
// new content API
foreach (AssetOperationGroup group in this.RequestAssetOperations(info))
yield return group;
@@ -592,12 +591,12 @@ private IEnumerable GetAssetOperationsWithoutCache(IAsse
// check if loader applies
try
{
- if (!loader.Data.CanLoad(info))
+ if (!loader.Data.CanLoad(legacyInfo))
continue;
}
catch (Exception ex)
{
- loader.Mod.LogAsMod($"Mod failed when checking whether it could load asset '{info.Name}', and will be ignored. Error details:\n{ex.GetLogSummary()}", LogLevel.Error);
+ loader.Mod.LogAsMod($"Mod failed when checking whether it could load asset '{legacyInfo.Name}', and will be ignored. Error details:\n{ex.GetLogSummary()}", LogLevel.Error);
continue;
}
@@ -610,7 +609,9 @@ private IEnumerable GetAssetOperationsWithoutCache(IAsse
mod: loader.Mod,
priority: AssetLoadPriority.Exclusive,
onBehalfOf: null,
- getData: assetInfo => loader.Data.Load(assetInfo)
+ getData: assetInfo => loader.Data.Load(
+ this.GetLegacyAssetInfo(assetInfo)
+ )
)
},
editOperations: Array.Empty()
@@ -623,12 +624,12 @@ private IEnumerable GetAssetOperationsWithoutCache(IAsse
// check if editor applies
try
{
- if (!editor.Data.CanEdit(info))
+ if (!editor.Data.CanEdit(legacyInfo))
continue;
}
catch (Exception ex)
{
- editor.Mod.LogAsMod($"Mod crashed when checking whether it could edit asset '{info.Name}', and will be ignored. Error details:\n{ex.GetLogSummary()}", LogLevel.Error);
+ editor.Mod.LogAsMod($"Mod crashed when checking whether it could edit asset '{legacyInfo.Name}', and will be ignored. Error details:\n{ex.GetLogSummary()}", LogLevel.Error);
continue;
}
@@ -642,11 +643,75 @@ private IEnumerable GetAssetOperationsWithoutCache(IAsse
mod: editor.Mod,
priority: AssetEditPriority.Default,
onBehalfOf: null,
- applyEdit: assetData => editor.Data.Edit(assetData)
+ applyEdit: assetData => editor.Data.Edit(
+ this.GetLegacyAssetData(assetData)
+ )
)
}
);
}
}
+
+ /// Get an asset info compatible with legacy and instances, which always expect the base name.
+ /// The asset info.
+ private IAssetInfo GetLegacyAssetInfo(IAssetInfo asset)
+ {
+ if (!this.TryGetLegacyAssetName(asset.Name, out IAssetName legacyName))
+ return asset;
+
+ return new AssetInfo(
+ locale: null,
+ assetName: legacyName,
+ type: asset.DataType,
+ getNormalizedPath: this.MainContentManager.AssertAndNormalizeAssetName
+ );
+ }
+
+ /// Get an asset data compatible with legacy and instances, which always expect the base name.
+ /// The asset data.
+ private IAssetData GetLegacyAssetData(IAssetData asset)
+ {
+ if (!this.TryGetLegacyAssetName(asset.Name, out IAssetName legacyName))
+ return asset;
+
+ return asset.Name.LocaleCode == null
+ ? asset
+ : new AssetDataForObject(
+ locale: null,
+ assetName: legacyName,
+ data: asset.Data,
+ getNormalizedPath: this.MainContentManager.AssertAndNormalizeAssetName
+ );
+ }
+
+ /// Get an asset name compatible with legacy and instances, which always expect the base name.
+ /// The asset name to map.
+ /// The legacy asset name (or the if no change is needed).
+ /// Returns whether any change is needed for legacy compatibility.
+ private bool TryGetLegacyAssetName(IAssetName asset, out IAssetName newAsset)
+ {
+ // strip _international suffix
+ const string internationalSuffix = "_international";
+ if (asset.Name.EndsWith(internationalSuffix))
+ {
+ newAsset = new AssetName(
+ baseName: asset.Name[..^internationalSuffix.Length],
+ localeCode: null,
+ languageCode: null
+ );
+ return true;
+ }
+
+ // else strip locale
+ if (asset.LocaleCode != null)
+ {
+ newAsset = new AssetName(asset.BaseName, null, null);
+ return true;
+ }
+
+ // else no change needed
+ newAsset = asset;
+ return false;
+ }
}
}
diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
index 030c60a75..b1ace259a 100644
--- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
@@ -5,6 +5,7 @@
using System.Globalization;
using System.IO;
using System.Linq;
+using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Framework.Content;
using StardewModdingAPI.Framework.Exceptions;
@@ -32,6 +33,9 @@ internal abstract class BaseContentManager : LocalizedContentManager, IContentMa
/// Whether to enable more aggressive memory optimizations.
protected readonly bool AggressiveMemoryOptimizations;
+ /// Whether to automatically try resolving keys to a localized form if available.
+ protected bool TryLocalizeKeys = true;
+
/// Whether the content coordinator has been disposed.
private bool IsDisposed;
@@ -39,7 +43,7 @@ internal abstract class BaseContentManager : LocalizedContentManager, IContentMa
private readonly Action OnDisposing;
/// A list of disposable assets.
- private readonly List> Disposables = new List>();
+ private readonly List> Disposables = new();
/// The disposable assets tracked by the base content manager.
/// This should be kept empty to avoid keeping disposable assets referenced forever, which prevents garbage collection when they're unused. Disposable assets are tracked by instead, which avoids a hard reference.
@@ -115,11 +119,51 @@ public override T Load(string assetName)
public override T Load(string assetName, LanguageCode language)
{
IAssetName parsedName = this.Coordinator.ParseAssetName(assetName);
- return this.Load(parsedName, language, useCache: true);
+ return this.LoadLocalized(parsedName, language, useCache: true);
}
///
- public abstract T Load(IAssetName assetName, LanguageCode language, bool useCache);
+ public T LoadLocalized(IAssetName assetName, LanguageCode language, bool useCache)
+ {
+ // ignore locale in English (or if disabled)
+ if (!this.TryLocalizeKeys || language == LocalizedContentManager.LanguageCode.en)
+ return this.LoadExact(assetName, useCache: useCache);
+
+ // check for localized asset
+ if (!LocalizedContentManager.localizedAssetNames.TryGetValue(assetName.Name, out _))
+ {
+ string localeCode = this.LanguageCodeString(language);
+ IAssetName localizedName = new AssetName(baseName: assetName.BaseName, localeCode: localeCode, languageCode: language);
+
+ try
+ {
+ this.LoadExact(localizedName, useCache: useCache);
+ LocalizedContentManager.localizedAssetNames[assetName.Name] = localizedName.Name;
+ }
+ catch (ContentLoadException)
+ {
+ localizedName = new AssetName(assetName.BaseName + "_international", null, null);
+ try
+ {
+ this.LoadExact(localizedName, useCache: useCache);
+ LocalizedContentManager.localizedAssetNames[assetName.Name] = localizedName.Name;
+ }
+ catch (ContentLoadException)
+ {
+ LocalizedContentManager.localizedAssetNames[assetName.Name] = assetName.Name;
+ }
+ }
+ }
+
+ // use cached key
+ string rawName = LocalizedContentManager.localizedAssetNames[assetName.Name];
+ if (assetName.Name != rawName)
+ assetName = this.Coordinator.ParseAssetName(assetName.Name);
+ return this.LoadExact(assetName, useCache: useCache);
+ }
+
+ ///
+ public abstract T LoadExact(IAssetName assetName, bool useCache);
///
public virtual void OnLocaleChanged() { }
@@ -154,7 +198,11 @@ public string GetLocale(LanguageCode language)
}
///
- public abstract bool IsLoaded(IAssetName assetName, LanguageCode language);
+ public bool IsLoaded(IAssetName assetName)
+ {
+ return this.Cache.ContainsKey(assetName.Name);
+ }
+
/****
** Cache invalidation
@@ -241,26 +289,29 @@ protected string NormalizePathSeparators(string path)
/// The type of asset to load.
/// The normalized asset key.
/// Whether to read/write the loaded asset to the asset cache.
- protected virtual T RawLoad(string assetName, bool useCache)
+ protected virtual T RawLoad(IAssetName assetName, bool useCache)
{
return useCache
- ? base.LoadBase(assetName)
- : base.ReadAsset(assetName, disposable => this.Disposables.Add(new WeakReference(disposable)));
+ ? base.LoadBase(assetName.Name)
+ : base.ReadAsset(assetName.Name, disposable => this.Disposables.Add(new WeakReference(disposable)));
}
/// Add tracking data to an asset and add it to the cache.
/// The type of asset to inject.
/// The asset path relative to the loader root directory, not including the .xnb extension.
/// The asset value.
- /// The language code for which to inject the asset.
/// Whether to save the asset to the asset cache.
- protected virtual void TrackAsset(IAssetName assetName, T value, LanguageCode language, bool useCache)
+ protected virtual void TrackAsset(IAssetName assetName, T value, bool useCache)
{
// track asset key
if (value is Texture2D texture)
texture.Name = assetName.Name;
- // cache asset
+ // save to cache
+ // Note: even if the asset was loaded and cached right before this method was called,
+ // we need to fully re-inject it because a mod editor may have changed the asset in a
+ // way that doesn't change the instance stored in the cache, e.g. using
+ // `asset.ReplaceWith`.
if (useCache)
this.Cache[assetName.Name] = value;
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
index a121f4c01..500c01918 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
@@ -4,11 +4,9 @@
using System.IO;
using System.Linq;
using System.Reflection;
-using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework.Content;
-using StardewModdingAPI.Framework.Exceptions;
using StardewModdingAPI.Framework.Reflection;
using StardewModdingAPI.Framework.Utilities;
using StardewModdingAPI.Internal;
@@ -91,7 +89,7 @@ public override bool DoesAssetExist(IAssetName assetName)
}
///
- public override T Load(IAssetName assetName, LanguageCode language, bool useCache)
+ public override T LoadExact(IAssetName assetName, bool useCache)
{
// raise first-load callback
if (GameContentManager.IsFirstLoad)
@@ -100,19 +98,15 @@ public override T Load(IAssetName assetName, LanguageCode language, bool useC
this.OnLoadingFirstAsset();
}
- // normalize asset name
- if (assetName.LanguageCode.HasValue)
- return this.Load(this.Coordinator.ParseAssetName(assetName.BaseName), assetName.LanguageCode.Value, useCache);
-
// get from cache
- if (useCache && this.IsLoaded(assetName, language))
- return this.RawLoad(assetName, language, useCache: true);
+ if (useCache && this.IsLoaded(assetName))
+ return this.RawLoad(assetName, useCache: true);
// get managed asset
if (this.Coordinator.TryParseManagedAssetKey(assetName.Name, out string contentManagerID, out IAssetName relativePath))
{
T managedAsset = this.Coordinator.LoadManagedAsset(contentManagerID, relativePath);
- this.TrackAsset(assetName, managedAsset, language, useCache);
+ this.TrackAsset(assetName, managedAsset, useCache);
return managedAsset;
}
@@ -122,44 +116,29 @@ public override T Load(IAssetName assetName, LanguageCode language, bool useC
{
this.Monitor.Log($"Broke loop while loading asset '{assetName}'.", LogLevel.Warn);
this.Monitor.Log($"Bypassing mod loaders for this asset. Stack trace:\n{Environment.StackTrace}");
- data = this.RawLoad(assetName, language, useCache);
+ data = this.RawLoad(assetName, useCache);
}
else
{
data = this.AssetsBeingLoaded.Track(assetName.Name, () =>
{
- string locale = this.GetLocale(language);
- IAssetInfo info = new AssetInfo(locale, assetName, typeof(T), this.AssertAndNormalizeAssetName);
+ IAssetInfo info = new AssetInfo(assetName.LocaleCode, assetName, typeof(T), this.AssertAndNormalizeAssetName);
IAssetData asset =
this.ApplyLoader(info)
- ?? new AssetDataForObject(info, this.RawLoad(assetName, language, useCache), this.AssertAndNormalizeAssetName);
+ ?? new AssetDataForObject(info, this.RawLoad(assetName, useCache), this.AssertAndNormalizeAssetName);
asset = this.ApplyEditors(info, asset);
return (T)asset.Data;
});
}
// update cache
- this.TrackAsset(assetName, data, language, useCache);
+ this.TrackAsset(assetName, data, useCache);
// raise event & return data
this.OnAssetLoaded(this, assetName);
return data;
}
- ///
- public override bool IsLoaded(IAssetName assetName, LanguageCode language)
- {
- string cachedKey = null;
- bool localized =
- language != LanguageCode.en
- && !this.Coordinator.IsManagedAssetKey(assetName)
- && this.LocalizedAssetNames.TryGetValue(assetName.Name, out cachedKey);
-
- return localized
- ? this.Cache.ContainsKey(cachedKey)
- : this.Cache.ContainsKey(assetName.Name);
- }
-
///
public override void OnLocaleChanged()
{
@@ -175,7 +154,7 @@ public override void OnLocaleChanged()
// invalidate translatable assets
string[] invalidated = this
- .InvalidateCache((key, type) =>
+ .InvalidateCache((key, _) =>
removeAssetNames.Contains(key)
|| removeAssetNames.Contains(this.Coordinator.ParseAssetName(key).BaseName)
)
@@ -196,81 +175,6 @@ public override LocalizedContentManager CreateTemporary()
/*********
** Private methods
*********/
- ///
- protected override void TrackAsset(IAssetName assetName, T value, LanguageCode language, bool useCache)
- {
- // handle explicit language in asset name
- {
- if (assetName.LanguageCode.HasValue)
- {
- this.TrackAsset(this.Coordinator.ParseAssetName(assetName.BaseName), value, assetName.LanguageCode.Value, useCache);
- return;
- }
- }
-
- // save to cache
- // Note: even if the asset was loaded and cached right before this method was called,
- // we need to fully re-inject it here for two reasons:
- // 1. So we can look up an asset by its base or localized key (the game/XNA logic
- // only caches by the most specific key).
- // 2. Because a mod asset loader/editor may have changed the asset in a way that
- // doesn't change the instance stored in the cache, e.g. using `asset.ReplaceWith`.
- if (useCache)
- {
- IAssetName translatedKey = new AssetName(assetName.Name, this.GetLocale(language), language);
- base.TrackAsset(assetName, value, language, useCache: true);
- if (this.Cache.ContainsKey(translatedKey.Name))
- base.TrackAsset(translatedKey, value, language, useCache: true);
-
- // track whether the injected asset is translatable for is-loaded lookups
- if (this.Cache.ContainsKey(translatedKey.Name))
- this.LocalizedAssetNames[assetName.Name] = translatedKey.Name;
- else if (this.Cache.ContainsKey(assetName.Name))
- this.LocalizedAssetNames[assetName.Name] = assetName.Name;
- else
- this.Monitor.Log($"Asset '{assetName}' could not be found in the cache immediately after injection.", LogLevel.Error);
- }
- }
-
- /// Load an asset file directly from the underlying content manager.
- /// The type of asset to load.
- /// The normalized asset key.
- /// The language code for which to load content.
- /// Whether to read/write the loaded asset to the asset cache.
- /// Derived from .
- private T RawLoad(IAssetName assetName, LanguageCode language, bool useCache)
- {
- try
- {
- // use cached key
- if (language == this.Language && this.LocalizedAssetNames.TryGetValue(assetName.Name, out string cachedKey))
- return base.RawLoad(cachedKey, useCache);
-
- // try translated key
- if (language != LanguageCode.en)
- {
- string translatedKey = $"{assetName}.{this.GetLocale(language)}";
- try
- {
- T obj = base.RawLoad(translatedKey, useCache);
- this.LocalizedAssetNames[assetName.Name] = translatedKey;
- return obj;
- }
- catch (ContentLoadException)
- {
- this.LocalizedAssetNames[assetName.Name] = assetName.Name;
- }
- }
-
- // try base asset
- return base.RawLoad(assetName.Name, useCache);
- }
- catch (ContentLoadException ex) when (ex.InnerException is FileNotFoundException { InnerException: null })
- {
- throw new SContentLoadException($"Error loading \"{assetName}\": it isn't in the Content folder and no mod provided it.");
- }
- }
-
/// Load the initial asset from the registered loaders.
/// The basic asset metadata.
/// Returns the loaded asset metadata, or null if no loader matched.
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs
index 847e2ce17..3f7188da5 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs
@@ -25,9 +25,9 @@ public GameContentManagerForAssetPropagation(string name, IServiceProvider servi
: base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, onLoadingFirstAsset, onAssetLoaded, aggressiveMemoryOptimizations) { }
///
- public override T Load(IAssetName assetName, LanguageCode language, bool useCache)
+ public override T LoadExact(IAssetName assetName, bool useCache)
{
- T data = base.Load(assetName, language, useCache);
+ T data = base.LoadExact(assetName, useCache);
if (data is Texture2D texture)
texture.Tag = this.Tag;
diff --git a/src/SMAPI/Framework/ContentManagers/IContentManager.cs b/src/SMAPI/Framework/ContentManagers/IContentManager.cs
index 6d71472fe..4de9a8c3e 100644
--- a/src/SMAPI/Framework/ContentManagers/IContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/IContentManager.cs
@@ -32,12 +32,17 @@ internal interface IContentManager : IDisposable
/// The normalized asset name.
bool DoesAssetExist(IAssetName assetName);
- /// Load an asset that has been processed by the content pipeline.
+ /// Load an asset through the content pipeline, using a localized variant of the if available.
/// The type of asset to load.
/// The asset name relative to the loader root directory.
- /// The language code for which to load content.
/// Whether to read/write the loaded asset to the asset cache.
- T Load(IAssetName assetName, LocalizedContentManager.LanguageCode language, bool useCache);
+ T LoadLocalized(IAssetName assetName, LocalizedContentManager.LanguageCode language, bool useCache);
+
+ /// Load an asset through the content pipeline, using the exact asset name without checking for localized variants.
+ /// The type of asset to load.
+ /// The asset name relative to the loader root directory.
+ /// Whether to read/write the loaded asset to the asset cache.
+ T LoadExact(IAssetName assetName, bool useCache);
/// Assert that the given key has a valid format and return a normalized form consistent with the underlying cache.
/// The asset key to check.
@@ -53,8 +58,7 @@ internal interface IContentManager : IDisposable
/// Get whether the content manager has already loaded and cached the given asset.
/// The asset path relative to the loader root directory, not including the .xnb extension.
- /// The language.
- bool IsLoaded(IAssetName assetName, LocalizedContentManager.LanguageCode language);
+ bool IsLoaded(IAssetName assetName);
/// Purge matched assets from the cache.
/// Matches the asset keys to invalidate.
diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
index 90836fcf9..375b5e0e2 100644
--- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
@@ -61,6 +61,8 @@ public ModContentManager(string name, IContentManager gameContentManager, IServi
this.GameContentManager = gameContentManager;
this.JsonHelper = jsonHelper;
this.ModName = modName;
+
+ this.TryLocalizeKeys = false;
}
///
@@ -80,14 +82,7 @@ public override T Load(string assetName)
}
///
- public override T Load(string assetName, LanguageCode language)
- {
- IAssetName parsedName = this.Coordinator.ParseAssetName(assetName);
- return this.Load(parsedName, language, useCache: false);
- }
-
- ///
- public override T Load(IAssetName assetName, LanguageCode language, bool useCache)
+ public override T LoadExact(IAssetName assetName, bool useCache)
{
// disable caching
// This is necessary to avoid assets being shared between content managers, which can
@@ -97,11 +92,6 @@ public override T Load(IAssetName assetName, LanguageCode language, bool useC
if (useCache)
throw new InvalidOperationException("Mod content managers don't support asset caching.");
- // disable language handling
- // Mod files don't support automatic translation logic, so this should never happen.
- if (language != this.DefaultLanguage)
- throw new InvalidOperationException("Localized assets aren't supported by the mod content manager.");
-
// resolve managed asset key
{
if (this.Coordinator.TryParseManagedAssetKey(assetName.Name, out string contentManagerID, out IAssetName relativePath))
@@ -130,14 +120,14 @@ public override T Load(IAssetName assetName, LanguageCode language, bool useC
{
// the underlying content manager adds a .xnb extension implicitly, so
// we need to strip it here to avoid trying to load a '.xnb.xnb' file.
- string loadName = assetName.Name[..^".xnb".Length];
+ IAssetName loadName = this.Coordinator.ParseAssetName(assetName.Name[..^".xnb".Length]);
// load asset
asset = this.RawLoad(loadName, useCache: false);
if (asset is Map map)
{
- map.assetPath = loadName;
- this.FixTilesheetPaths(map, relativeMapPath: loadName, fixEagerPathPrefixes: true);
+ map.assetPath = loadName.Name;
+ this.FixTilesheetPaths(map, relativeMapPath: loadName.Name, fixEagerPathPrefixes: true);
}
}
break;
@@ -201,16 +191,10 @@ public override T Load(IAssetName assetName, LanguageCode language, bool useC
}
// track & return asset
- this.TrackAsset(assetName, asset, language, useCache);
+ this.TrackAsset(assetName, asset, useCache);
return asset;
}
- ///
- public override bool IsLoaded(IAssetName assetName, LanguageCode language)
- {
- return this.Cache.ContainsKey(assetName.Name);
- }
-
///
public override LocalizedContentManager CreateTemporary()
{
@@ -371,7 +355,7 @@ private bool TryGetTilesheetAssetName(string modRelativeMapFolder, string relati
IAssetName contentKey = this.Coordinator.ParseAssetName(this.GetContentKeyForTilesheetImageSource(relativePath));
try
{
- this.GameContentManager.Load(contentKey, this.Language, useCache: true); // no need to bypass cache here, since we're not storing the asset
+ this.GameContentManager.LoadLocalized(contentKey, this.GameContentManager.Language, useCache: true); // no need to bypass cache here, since we're not storing the asset
assetName = contentKey;
return true;
}
diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
index 4e522c8d3..3416c2867 100644
--- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
@@ -88,10 +88,10 @@ public T Load(string key, ContentSource source = ContentSource.ModFolder)
switch (source)
{
case ContentSource.GameContent:
- return this.GameContentManager.Load(assetName, this.CurrentLocaleConstant, useCache: false);
+ return this.GameContentManager.LoadLocalized(assetName, this.CurrentLocaleConstant, useCache: false);
case ContentSource.ModFolder:
- return this.ModContentManager.Load(assetName, Constants.DefaultLanguage, useCache: false);
+ return this.ModContentManager.LoadExact(assetName, useCache: false);
default:
throw new SContentLoadException($"{this.ModName} failed loading content asset '{key}' from {source}: unknown content source '{source}'.");