summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-04-01 22:59:50 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-04-01 22:59:50 -0400
commitbac1f34f65412419656eea15ea81081f8a29867e (patch)
tree7721b47edcf67e33b2995ecea6b870fc60a270a1 /src/SMAPI
parent6ad8ca932eb697a76dd9df43d6ae93c7ca4b2af5 (diff)
downloadSMAPI-bac1f34f65412419656eea15ea81081f8a29867e.tar.gz
SMAPI-bac1f34f65412419656eea15ea81081f8a29867e.tar.bz2
SMAPI-bac1f34f65412419656eea15ea81081f8a29867e.zip
fix local file path asset name parsing locale codes in rare cases (#766)
Mod file paths can't be localized through the content pipeline. Normally the locale would be ignored anyway due to the file extension, but it'd be incorrectly parsed if the file name ended with a locale and no file extension (like "assets/example.fr-FR").
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs20
-rw-r--r--src/SMAPI/Framework/ContentManagers/BaseContentManager.cs6
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs6
-rw-r--r--src/SMAPI/Framework/ModHelpers/ContentHelper.cs12
-rw-r--r--src/SMAPI/Framework/ModHelpers/GameContentHelper.cs6
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModContentHelper.cs4
6 files changed, 30 insertions, 24 deletions
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index 108257bf..8483d45d 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -156,7 +156,7 @@ namespace StardewModdingAPI.Framework
);
this.ContentManagers.Add(contentManagerForAssetPropagation);
this.VanillaContentManager = new LocalizedContentManager(serviceProvider, rootDirectory);
- this.CoreAssets = new CoreAssetPropagator(this.MainContentManager, contentManagerForAssetPropagation, this.Monitor, reflection, aggressiveMemoryOptimizations, this.ParseAssetName);
+ this.CoreAssets = new CoreAssetPropagator(this.MainContentManager, contentManagerForAssetPropagation, this.Monitor, reflection, aggressiveMemoryOptimizations, name => this.ParseAssetName(name, allowLocales: true));
this.LocaleCodes = new Lazy<Dictionary<string, LocalizedContentManager.LanguageCode>>(() => this.GetLocaleCodes(customLanguages: Enumerable.Empty<ModLanguage>()));
}
@@ -269,11 +269,17 @@ namespace StardewModdingAPI.Framework
/// <summary>Parse a raw asset name.</summary>
/// <param name="rawName">The raw asset name to parse.</param>
+ /// <param name="allowLocales">Whether to parse locales in the <paramref name="rawName"/>. If this is false, any locale codes in the name are treated as if they were part of the base name (e.g. for mod files).</param>
/// <exception cref="ArgumentException">The <paramref name="rawName"/> is null or empty.</exception>
- public AssetName ParseAssetName(string rawName)
+ public AssetName ParseAssetName(string rawName, bool allowLocales)
{
return !string.IsNullOrWhiteSpace(rawName)
- ? AssetName.Parse(rawName, parseLocale: locale => this.LocaleCodes.Value.TryGetValue(locale, out LocalizedContentManager.LanguageCode langCode) ? langCode : null)
+ ? AssetName.Parse(
+ rawName: rawName,
+ parseLocale: allowLocales
+ ? locale => this.LocaleCodes.Value.TryGetValue(locale, out LocalizedContentManager.LanguageCode langCode) ? langCode : null
+ : _ => null
+ )
: throw new ArgumentException("The asset name can't be null or empty.", nameof(rawName));
}
@@ -303,7 +309,7 @@ namespace StardewModdingAPI.Framework
if (parts.Length != 3) // managed key prefix, mod id, relative path
return false;
contentManagerID = Path.Combine(parts[0], parts[1]);
- relativePath = this.ParseAssetName(parts[2]);
+ relativePath = this.ParseAssetName(parts[2], allowLocales: false);
return true;
}
@@ -357,7 +363,7 @@ namespace StardewModdingAPI.Framework
string locale = this.GetLocale();
return this.InvalidateCache((_, rawName, type) =>
{
- IAssetName assetName = this.ParseAssetName(rawName);
+ IAssetName assetName = this.ParseAssetName(rawName, allowLocales: true);
IAssetInfo info = new AssetInfo(locale, assetName, type, this.MainContentManager.AssertAndNormalizeAssetName);
return predicate(info);
}, dispose);
@@ -378,7 +384,7 @@ namespace StardewModdingAPI.Framework
{
foreach ((string key, object asset) in contentManager.InvalidateCache((key, type) => predicate(contentManager, key, type), dispose))
{
- AssetName assetName = this.ParseAssetName(key);
+ AssetName assetName = this.ParseAssetName(key, allowLocales: true);
if (!invalidatedAssets.ContainsKey(assetName))
invalidatedAssets[assetName] = asset.GetType();
}
@@ -394,7 +400,7 @@ namespace StardewModdingAPI.Framework
continue;
// get map path
- AssetName mapPath = this.ParseAssetName(this.MainContentManager.AssertAndNormalizeAssetName(location.mapPath.Value));
+ AssetName mapPath = this.ParseAssetName(this.MainContentManager.AssertAndNormalizeAssetName(location.mapPath.Value), allowLocales: true);
if (!invalidatedAssets.ContainsKey(mapPath) && predicate(this.MainContentManager, mapPath.Name, typeof(Map)))
invalidatedAssets[mapPath] = typeof(Map);
}
diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
index 2d921cc3..31199b3a 100644
--- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
@@ -119,7 +119,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
public sealed override T Load<T>(string assetName, LanguageCode language)
{
assetName = this.PrenormalizeRawAssetName(assetName);
- IAssetName parsedName = this.Coordinator.ParseAssetName(assetName);
+ IAssetName parsedName = this.Coordinator.ParseAssetName(assetName, allowLocales: this.TryLocalizeKeys);
return this.LoadLocalized<T>(parsedName, language, useCache: true);
}
@@ -161,7 +161,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
// use cached key
string rawName = LocalizedContentManager.localizedAssetNames[assetName.Name];
if (assetName.Name != rawName)
- assetName = this.Coordinator.ParseAssetName(rawName);
+ assetName = this.Coordinator.ParseAssetName(rawName, allowLocales: this.TryLocalizeKeys);
return this.LoadExact<T>(assetName, useCache: useCache);
}
@@ -213,7 +213,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
IDictionary<string, object> removeAssets = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
this.Cache.Remove((key, asset) =>
{
- string baseAssetName = this.Coordinator.ParseAssetName(key).BaseName;
+ string baseAssetName = this.Coordinator.ParseAssetName(key, allowLocales: this.TryLocalizeKeys).BaseName;
// check if asset should be removed
bool remove = removeAssets.ContainsKey(baseAssetName);
diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
index 63b40d66..9ed989da 100644
--- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
@@ -111,7 +111,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
{
// 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.
- IAssetName loadName = this.Coordinator.ParseAssetName(assetName.Name[..^".xnb".Length]);
+ IAssetName loadName = this.Coordinator.ParseAssetName(assetName.Name[..^".xnb".Length], allowLocales: false);
// load asset
asset = this.RawLoad<T>(loadName, useCache: false);
@@ -201,7 +201,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
string relativePath = PathUtilities.GetRelativePath(this.RootDirectory, file.FullName);
string internalKey = Path.Combine(this.Name, relativePath);
- return this.Coordinator.ParseAssetName(internalKey);
+ return this.Coordinator.ParseAssetName(internalKey, allowLocales: false);
}
@@ -343,7 +343,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
}
// get from game assets
- IAssetName contentKey = this.Coordinator.ParseAssetName(this.GetContentKeyForTilesheetImageSource(relativePath));
+ IAssetName contentKey = this.Coordinator.ParseAssetName(this.GetContentKeyForTilesheetImageSource(relativePath), allowLocales: false);
try
{
this.GameContentManager.LoadLocalized<Texture2D>(contentKey, this.GameContentManager.Language, useCache: true); // no need to bypass cache here, since we're not storing the asset
diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
index b0064532..ae914c46 100644
--- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
@@ -107,7 +107,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <inheritdoc />
public T Load<T>(string key, ContentSource source = ContentSource.ModFolder)
{
- IAssetName assetName = this.ContentCore.ParseAssetName(key);
+ IAssetName assetName = this.ContentCore.ParseAssetName(key, allowLocales: source == ContentSource.GameContent);
try
{
@@ -157,21 +157,21 @@ namespace StardewModdingAPI.Framework.ModHelpers
public bool InvalidateCache(string key)
{
string actualKey = this.GetActualAssetKey(key, ContentSource.GameContent);
- this.Monitor.Log($"Requested cache invalidation for '{actualKey}'.", LogLevel.Trace);
+ this.Monitor.Log($"Requested cache invalidation for '{actualKey}'.");
return this.ContentCore.InvalidateCache(asset => asset.Name.IsEquivalentTo(actualKey)).Any();
}
/// <inheritdoc />
public bool InvalidateCache<T>()
{
- this.Monitor.Log($"Requested cache invalidation for all assets of type {typeof(T)}. This is an expensive operation and should be avoided if possible.", LogLevel.Trace);
- return this.ContentCore.InvalidateCache((contentManager, key, type) => typeof(T).IsAssignableFrom(type)).Any();
+ this.Monitor.Log($"Requested cache invalidation for all assets of type {typeof(T)}. This is an expensive operation and should be avoided if possible.");
+ return this.ContentCore.InvalidateCache((_, _, type) => typeof(T).IsAssignableFrom(type)).Any();
}
/// <inheritdoc />
public bool InvalidateCache(Func<IAssetInfo, bool> predicate)
{
- this.Monitor.Log("Requested cache invalidation for all assets matching a predicate.", LogLevel.Trace);
+ this.Monitor.Log("Requested cache invalidation for all assets matching a predicate.");
return this.ContentCore.InvalidateCache(predicate).Any();
}
@@ -183,7 +183,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
assetName ??= $"temp/{Guid.NewGuid():N}";
- return new AssetDataForObject(this.CurrentLocale, this.ContentCore.ParseAssetName(assetName), data, this.NormalizeAssetName);
+ return new AssetDataForObject(this.CurrentLocale, this.ContentCore.ParseAssetName(assetName, allowLocales: true/* no way to know if it's a game or mod asset here*/), data, this.NormalizeAssetName);
}
diff --git a/src/SMAPI/Framework/ModHelpers/GameContentHelper.cs b/src/SMAPI/Framework/ModHelpers/GameContentHelper.cs
index 42a4de20..0eb385d4 100644
--- a/src/SMAPI/Framework/ModHelpers/GameContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/GameContentHelper.cs
@@ -58,13 +58,13 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <inheritdoc />
public IAssetName ParseAssetName(string rawName)
{
- return this.ContentCore.ParseAssetName(rawName);
+ return this.ContentCore.ParseAssetName(rawName, allowLocales: true);
}
/// <inheritdoc />
public T Load<T>(string key)
{
- IAssetName assetName = this.ContentCore.ParseAssetName(key);
+ IAssetName assetName = this.ContentCore.ParseAssetName(key, allowLocales: true);
return this.Load<T>(assetName);
}
@@ -117,7 +117,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
assetName ??= $"temp/{Guid.NewGuid():N}";
- return new AssetDataForObject(this.CurrentLocale, this.ContentCore.ParseAssetName(assetName), data, key => this.ParseAssetName(key).Name);
+ return new AssetDataForObject(this.CurrentLocale, this.ContentCore.ParseAssetName(assetName, allowLocales: true), data, key => this.ParseAssetName(key).Name);
}
/// <summary>Get the underlying game content manager.</summary>
diff --git a/src/SMAPI/Framework/ModHelpers/ModContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ModContentHelper.cs
index 45899dd7..2379583c 100644
--- a/src/SMAPI/Framework/ModHelpers/ModContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModContentHelper.cs
@@ -43,7 +43,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <inheritdoc />
public T Load<T>(string relativePath)
{
- IAssetName assetName = this.ContentCore.ParseAssetName(relativePath);
+ IAssetName assetName = this.ContentCore.ParseAssetName(relativePath, allowLocales: false);
try
{
@@ -69,7 +69,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
relativePath ??= $"temp/{Guid.NewGuid():N}";
- return new AssetDataForObject(this.ContentCore.GetLocale(), this.ContentCore.ParseAssetName(relativePath), data, key => this.ContentCore.ParseAssetName(key).Name);
+ return new AssetDataForObject(this.ContentCore.GetLocale(), this.ContentCore.ParseAssetName(relativePath, allowLocales: false), data, key => this.ContentCore.ParseAssetName(key, allowLocales: false).Name);
}
}
}