summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Framework/ContentManagers/GameContentManager.cs')
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManager.cs120
1 files changed, 78 insertions, 42 deletions
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
index 90278c36..ecabcaca 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using Microsoft.Xna.Framework.Content;
using StardewModdingAPI.Framework.Content;
using StardewModdingAPI.Framework.Exceptions;
using StardewModdingAPI.Framework.Reflection;
@@ -59,7 +60,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <typeparam name="T">The type of asset to load.</typeparam>
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
/// <param name="language">The language code for which to load content.</param>
- public override T Load<T>(string assetName, LanguageCode language)
+ /// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
+ public override T Load<T>(string assetName, LocalizedContentManager.LanguageCode language, bool useCache)
{
// raise first-load callback
if (GameContentManager.IsFirstLoad)
@@ -71,17 +73,18 @@ namespace StardewModdingAPI.Framework.ContentManagers
// normalise asset name
assetName = this.AssertAndNormaliseAssetName(assetName);
if (this.TryParseExplicitLanguageAssetKey(assetName, out string newAssetName, out LanguageCode newLanguage))
- return this.Load<T>(newAssetName, newLanguage);
+ return this.Load<T>(newAssetName, newLanguage, useCache);
// get from cache
- if (this.IsLoaded(assetName))
- return base.Load<T>(assetName, language);
+ if (useCache && this.IsLoaded(assetName))
+ return this.RawLoad<T>(assetName, language, useCache: true);
// get managed asset
if (this.Coordinator.TryParseManagedAssetKey(assetName, out string contentManagerID, out string relativePath))
{
- T managedAsset = this.Coordinator.LoadAndCloneManagedAsset<T>(assetName, contentManagerID, relativePath, language);
- this.Inject(assetName, managedAsset, language);
+ T managedAsset = this.Coordinator.LoadManagedAsset<T>(assetName, contentManagerID, relativePath, language);
+ if (useCache)
+ this.Inject(assetName, managedAsset, language);
return managedAsset;
}
@@ -91,7 +94,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
{
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}", LogLevel.Trace);
- data = base.Load<T>(assetName, language);
+ data = this.RawLoad<T>(assetName, language, useCache);
}
else
{
@@ -101,7 +104,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
IAssetInfo info = new AssetInfo(locale, assetName, typeof(T), this.AssertAndNormaliseAssetName);
IAssetData asset =
this.ApplyLoader<T>(info)
- ?? new AssetDataForObject(info, base.Load<T>(assetName, language), this.AssertAndNormaliseAssetName);
+ ?? new AssetDataForObject(info, this.RawLoad<T>(assetName, language, useCache), this.AssertAndNormaliseAssetName);
asset = this.ApplyEditors<T>(info, asset);
return (T)asset.Data;
});
@@ -112,39 +115,6 @@ namespace StardewModdingAPI.Framework.ContentManagers
return data;
}
- /// <summary>Inject an asset into the cache.</summary>
- /// <typeparam name="T">The type of asset to inject.</typeparam>
- /// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
- /// <param name="value">The asset value.</param>
- /// <param name="language">The language code for which to inject the asset.</param>
- public override void Inject<T>(string assetName, T value, LanguageCode language)
- {
- // handle explicit language in asset name
- {
- if (this.TryParseExplicitLanguageAssetKey(assetName, out string newAssetName, out LanguageCode newLanguage))
- {
- this.Inject(newAssetName, value, newLanguage);
- return;
- }
- }
- base.Inject(assetName, value, language);
-
- // track whether the injected asset is translatable for is-loaded lookups
- string keyWithLocale = $"{assetName}.{this.GetLocale(language)}";
- if (this.Cache.ContainsKey(keyWithLocale))
- {
- this.IsLocalisableLookup[assetName] = true;
- this.IsLocalisableLookup[keyWithLocale] = true;
- }
- else if (this.Cache.ContainsKey(assetName))
- {
- this.IsLocalisableLookup[assetName] = false;
- this.IsLocalisableLookup[keyWithLocale] = false;
- }
- else
- this.Monitor.Log($"Asset '{assetName}' could not be found in the cache immediately after injection.", LogLevel.Error);
- }
-
/// <summary>Perform any cleanup needed when the locale changes.</summary>
public override void OnLocaleChanged()
{
@@ -199,6 +169,72 @@ namespace StardewModdingAPI.Framework.ContentManagers
return false;
}
+ /// <summary>Inject an asset into the cache.</summary>
+ /// <typeparam name="T">The type of asset to inject.</typeparam>
+ /// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
+ /// <param name="value">The asset value.</param>
+ /// <param name="language">The language code for which to inject the asset.</param>
+ protected override void Inject<T>(string assetName, T value, LanguageCode language)
+ {
+ // handle explicit language in asset name
+ {
+ if (this.TryParseExplicitLanguageAssetKey(assetName, out string newAssetName, out LanguageCode newLanguage))
+ {
+ this.Inject(newAssetName, value, newLanguage);
+ return;
+ }
+ }
+ base.Inject(assetName, value, language);
+
+ // track whether the injected asset is translatable for is-loaded lookups
+ string keyWithLocale = $"{assetName}.{this.GetLocale(language)}";
+ if (this.Cache.ContainsKey(keyWithLocale))
+ {
+ this.IsLocalisableLookup[assetName] = true;
+ this.IsLocalisableLookup[keyWithLocale] = true;
+ }
+ else if (this.Cache.ContainsKey(assetName))
+ {
+ this.IsLocalisableLookup[assetName] = false;
+ this.IsLocalisableLookup[keyWithLocale] = false;
+ }
+ else
+ this.Monitor.Log($"Asset '{assetName}' could not be found in the cache immediately after injection.", LogLevel.Error);
+ }
+
+ /// <summary>Load an asset file directly from the underlying content manager.</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The normalised asset key.</param>
+ /// <param name="language">The language code for which to load content.</param>
+ /// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
+ /// <remarks>Derived from <see cref="LocalizedContentManager.Load{T}(string, LocalizedContentManager.LanguageCode)"/>.</remarks>
+ private T RawLoad<T>(string assetName, LanguageCode language, bool useCache)
+ {
+ // try translated asset
+ if (language != LocalizedContentManager.LanguageCode.en)
+ {
+ string translatedKey = $"{assetName}.{this.GetLocale(language)}";
+ if (!this.IsLocalisableLookup.TryGetValue(translatedKey, out bool isTranslatable) || isTranslatable)
+ {
+ try
+ {
+ T obj = base.RawLoad<T>(translatedKey, useCache);
+ this.IsLocalisableLookup[assetName] = true;
+ this.IsLocalisableLookup[translatedKey] = true;
+ return obj;
+ }
+ catch (ContentLoadException)
+ {
+ this.IsLocalisableLookup[assetName] = false;
+ this.IsLocalisableLookup[translatedKey] = false;
+ }
+ }
+ }
+
+ // try base asset
+ return base.RawLoad<T>(assetName, useCache);
+ }
+
/// <summary>Parse an asset key that contains an explicit language into its asset name and language, if applicable.</summary>
/// <param name="rawAsset">The asset key to parse.</param>
/// <param name="assetName">The asset name without the language code.</param>
@@ -260,7 +296,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
T data;
try
{
- data = this.CloneIfPossible(loader.Load<T>(info));
+ data = loader.Load<T>(info);
this.Monitor.Log($"{mod.DisplayName} loaded asset '{info.AssetName}'.", LogLevel.Trace);
}
catch (Exception ex)