diff options
-rw-r--r-- | src/StardewModdingAPI/Framework/ContentEventHelper.cs | 39 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/SContentManager.cs | 48 | ||||
-rw-r--r-- | src/StardewModdingAPI/IContentEventHelper.cs | 14 |
3 files changed, 53 insertions, 48 deletions
diff --git a/src/StardewModdingAPI/Framework/ContentEventHelper.cs b/src/StardewModdingAPI/Framework/ContentEventHelper.cs index d4a9bbb8..a58efe32 100644 --- a/src/StardewModdingAPI/Framework/ContentEventHelper.cs +++ b/src/StardewModdingAPI/Framework/ContentEventHelper.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text.RegularExpressions; using Microsoft.Xna.Framework.Graphics; namespace StardewModdingAPI.Framework @@ -18,8 +17,11 @@ namespace StardewModdingAPI.Framework /********* ** Accessors *********/ - /// <summary>The normalised asset path being read. The format may change between platforms; see <see cref="IsPath"/> to compare with a known path.</summary> - public string Path { get; } + /// <summary>The content's locale code, if the content is localised.</summary> + public string Locale { get; } + + /// <summary>The normalised asset name being read. The format may change between platforms; see <see cref="IsAssetName"/> to compare with a known path.</summary> + public string AssetName { get; } /// <summary>The content data being read.</summary> public object Data { get; private set; } @@ -29,37 +31,24 @@ namespace StardewModdingAPI.Framework ** Public methods *********/ /// <summary>Construct an instance.</summary> - /// <param name="path">The file path being read.</param> + /// <param name="locale">The content's locale code, if the content is localised.</param> + /// <param name="assetName">The normalised asset name being read.</param> /// <param name="data">The content data being read.</param> /// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param> - public ContentEventHelper(string path, object data, Func<string, string> getNormalisedPath) + public ContentEventHelper(string locale, string assetName, object data, Func<string, string> getNormalisedPath) { - this.Path = path; + this.Locale = locale; + this.AssetName = assetName; this.Data = data; this.GetNormalisedPath = getNormalisedPath; } - /// <summary>Get whether the asset path being loaded matches a given path after normalisation.</summary> - /// <param name="path">The expected asset path, relative to the game folder and without the .xnb extension (like 'Data\ObjectInformation').</param> - /// <param name="matchLocalisedVersion">Whether to match a localised version of the asset file (like 'Data\ObjectInformation.ja-JP').</param> - public bool IsPath(string path, bool matchLocalisedVersion = true) + /// <summary>Get whether the asset name being loaded matches a given name after normalisation.</summary> + /// <param name="path">The expected asset path, relative to the game's content folder and without the .xnb extension or locale suffix (like 'Data\ObjectInformation').</param> + public bool IsAssetName(string path) { path = this.GetNormalisedPath(path); - - // equivalent - if (this.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase)) - return true; - - // localised version - if (matchLocalisedVersion) - { - return - this.Path.StartsWith($"{path}.", StringComparison.InvariantCultureIgnoreCase) // starts with given path - && Regex.IsMatch(this.Path.Substring(path.Length + 1), "^[a-z]+-[A-Z]+$"); // ends with locale (e.g. pt-BR) - } - - // no match - return false; + return this.AssetName.Equals(path, StringComparison.InvariantCultureIgnoreCase); } /// <summary>Get the data as a given type.</summary> diff --git a/src/StardewModdingAPI/Framework/SContentManager.cs b/src/StardewModdingAPI/Framework/SContentManager.cs index 45f42bf6..65c330db 100644 --- a/src/StardewModdingAPI/Framework/SContentManager.cs +++ b/src/StardewModdingAPI/Framework/SContentManager.cs @@ -31,7 +31,10 @@ namespace StardewModdingAPI.Framework private readonly IDictionary<string, object> Cache; /// <summary>Applies platform-specific asset key normalisation so it's consistent with the underlying cache.</summary> - private readonly Func<string, string> NormaliseKeyForPlatform; + private readonly Func<string, string> NormaliseAssetNameForPlatform; + + /// <summary>The private <see cref="LocalizedContentManager"/> method which generates the locale portion of an asset name.</summary> + private readonly IPrivateMethod GetKeyLocale; /********* @@ -57,19 +60,18 @@ namespace StardewModdingAPI.Framework this.Monitor = monitor; IReflectionHelper reflection = new ReflectionHelper(); - // get underlying asset cache - this.Cache = reflection - .GetPrivateField<Dictionary<string, object>>(this, "loadedAssets") - .GetValue(); + // get underlying fields for interception + this.Cache = reflection.GetPrivateField<Dictionary<string, object>>(this, "loadedAssets").GetValue(); + this.GetKeyLocale = reflection.GetPrivateMethod(this, "languageCode"); // get asset key normalisation logic if (Constants.TargetPlatform == Platform.Windows) { IPrivateMethod method = reflection.GetPrivateMethod(typeof(TitleContainer), "GetCleanPath"); - this.NormaliseKeyForPlatform = path => method.Invoke<string>(path); + this.NormaliseAssetNameForPlatform = path => method.Invoke<string>(path); } else - this.NormaliseKeyForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load<T> logic + this.NormaliseAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load<T> logic } /// <summary>Load an asset that has been processed by the content pipeline.</summary> @@ -77,8 +79,8 @@ namespace StardewModdingAPI.Framework /// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param> public override T Load<T>(string assetName) { - // normalise key so can override the cache value later - assetName = this.NormaliseKey(assetName); + // normalise asset name so can override the cache value later + assetName = this.NormaliseAssetName(assetName); // skip if no event handlers or already loaded if (!ContentEvents.HasAssetLoadingListeners() || this.Cache.ContainsKey(assetName)) @@ -86,7 +88,8 @@ namespace StardewModdingAPI.Framework // intercept load T data = base.Load<T>(assetName); - IContentEventHelper helper = new ContentEventHelper(assetName, data, this.NormaliseKeyForPlatform); + string cacheLocale = this.GetCacheLocale(assetName, this.Cache); + IContentEventHelper helper = new ContentEventHelper(cacheLocale, assetName, data, this.NormaliseAssetName); ContentEvents.InvokeAssetLoading(this.Monitor, helper); this.Cache[assetName] = helper.Data; return (T)helper.Data; @@ -96,16 +99,27 @@ namespace StardewModdingAPI.Framework /********* ** Private methods *********/ - /// <summary>Normalise an asset key so it's consistent with the underlying cache.</summary> - /// <param name="key">The asset key.</param> - private string NormaliseKey(string key) + /// <summary>Normalise an asset name so it's consistent with the underlying cache.</summary> + /// <param name="assetName">The asset key.</param> + private string NormaliseAssetName(string assetName) { - // ensure key format is consistent - string[] parts = key.Split(SContentManager.PossiblePathSeparators, StringSplitOptions.RemoveEmptyEntries); - key = string.Join(SContentManager.PreferredPathSeparator, parts); + // ensure name format is consistent + string[] parts = assetName.Split(SContentManager.PossiblePathSeparators, StringSplitOptions.RemoveEmptyEntries); + assetName = string.Join(SContentManager.PreferredPathSeparator, parts); // apply platform normalisation logic - return this.NormaliseKeyForPlatform(key); + return this.NormaliseAssetNameForPlatform(assetName); + } + + /// <summary>Get the locale for which the asset name was saved, if any.</summary> + /// <param name="normalisedAssetName">The normalised asset name.</param> + /// <param name="cache">The cache to search.</param> + private string GetCacheLocale(string normalisedAssetName, IDictionary<string, object> cache) + { + string locale = this.GetKeyLocale.Invoke<string>(); + return this.Cache.ContainsKey($"{normalisedAssetName}.{this.GetKeyLocale.Invoke<string>()}") + ? locale + : null; } } } diff --git a/src/StardewModdingAPI/IContentEventHelper.cs b/src/StardewModdingAPI/IContentEventHelper.cs index 98d074d9..be8290eb 100644 --- a/src/StardewModdingAPI/IContentEventHelper.cs +++ b/src/StardewModdingAPI/IContentEventHelper.cs @@ -8,8 +8,11 @@ namespace StardewModdingAPI /********* ** Accessors *********/ - /// <summary>The normalised asset path being read. The format may change between platforms; see <see cref="IsPath"/> to compare with a known path.</summary> - string Path { get; } + /// <summary>The content's locale code, if the content is localised.</summary> + string Locale { get; } + + /// <summary>The normalised asset name being read. The format may change between platforms; see <see cref="IsAssetName"/> to compare with a known path.</summary> + string AssetName { get; } /// <summary>The content data being read.</summary> object Data { get; } @@ -18,10 +21,9 @@ namespace StardewModdingAPI /********* ** Public methods *********/ - /// <summary>Get whether the asset path being loaded matches a given path after normalisation.</summary> - /// <param name="path">The expected asset path, relative to the game folder and without the .xnb extension (like 'Data\ObjectInformation').</param> - /// <param name="matchLocalisedVersion">Whether to match a localised version of the asset file (like 'Data\ObjectInformation.ja-JP').</param> - bool IsPath(string path, bool matchLocalisedVersion = true); + /// <summary>Get whether the asset name being loaded matches a given name after normalisation.</summary> + /// <param name="path">The expected asset path, relative to the game's content folder and without the .xnb extension or locale suffix (like 'Data\ObjectInformation').</param> + bool IsAssetName(string path); /// <summary>Get the data as a given type.</summary> /// <typeparam name="TData">The expected data type.</typeparam> |