diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2022-05-06 20:58:19 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2022-05-06 20:58:19 -0400 |
commit | e7e6327b3c85d52ab666aad2a054fbbdbd9431da (patch) | |
tree | 436b963d47bd8062ab38b676f57cbfb5c4e99821 /src/SMAPI/Framework/ContentManagers | |
parent | c8ad50dad1d706a1901798f9396f6becfea36c0e (diff) | |
parent | b45f50b57e3895620a682e2c7a438391dce0c5dd (diff) | |
download | SMAPI-e7e6327b3c85d52ab666aad2a054fbbdbd9431da.tar.gz SMAPI-e7e6327b3c85d52ab666aad2a054fbbdbd9431da.tar.bz2 SMAPI-e7e6327b3c85d52ab666aad2a054fbbdbd9431da.zip |
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI/Framework/ContentManagers')
4 files changed, 62 insertions, 28 deletions
diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs index b2e3ec0f..e4695588 100644 --- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs @@ -11,7 +11,6 @@ using StardewModdingAPI.Framework.Content; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Reflection; using StardewValley; -using xTile; namespace StardewModdingAPI.Framework.ContentManagers { @@ -33,9 +32,6 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <summary>Simplifies access to private code.</summary> protected readonly Reflector Reflection; - /// <summary>Whether to enable more aggressive memory optimizations.</summary> - protected readonly bool AggressiveMemoryOptimizations; - /// <summary>Whether to automatically try resolving keys to a localized form if available.</summary> protected bool TryLocalizeKeys = true; @@ -82,8 +78,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <param name="reflection">Simplifies access to private code.</param> /// <param name="onDisposing">A callback to invoke when the content manager is being disposed.</param> /// <param name="isNamespaced">Whether this content manager handles managed asset keys (e.g. to load assets from a mod folder).</param> - /// <param name="aggressiveMemoryOptimizations">Whether to enable more aggressive memory optimizations.</param> - protected BaseContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, bool isNamespaced, bool aggressiveMemoryOptimizations) + protected BaseContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, bool isNamespaced) : base(serviceProvider, rootDirectory, currentCulture) { // init @@ -95,7 +90,6 @@ namespace StardewModdingAPI.Framework.ContentManagers this.Reflection = reflection; this.OnDisposing = onDisposing; this.IsNamespaced = isNamespaced; - this.AggressiveMemoryOptimizations = aggressiveMemoryOptimizations; // get asset data this.BaseDisposableReferences = reflection.GetField<List<IDisposable>?>(this, "disposableAssets").GetValue() @@ -117,6 +111,26 @@ namespace StardewModdingAPI.Framework.ContentManagers } /// <inheritdoc /> + [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse", Justification = "Copied as-is from game code")] + public sealed override string LoadBaseString(string path) + { + try + { + // copied as-is from LocalizedContentManager.LoadBaseString + // This is only changed to call this.Load instead of base.Load, to support mod assets + this.ParseStringPath(path, out string assetName, out string key); + Dictionary<string, string> strings = this.Load<Dictionary<string, string>>(assetName, LanguageCode.en); + return strings != null && strings.ContainsKey(key) + ? this.GetString(strings, key) + : path; + } + catch (Exception ex) + { + throw new InvalidOperationException($"Failed loading string path '{path}' from '{this.Name}'.", ex); + } + } + + /// <inheritdoc /> public sealed override T Load<T>(string assetName) { return this.Load<T>(assetName, this.Language); @@ -231,14 +245,6 @@ namespace StardewModdingAPI.Framework.ContentManagers removeAssets[baseAssetName] = asset; remove = true; } - - // dispose if safe - if (remove && this.AggressiveMemoryOptimizations) - { - if (asset is Map map) - map.DisposeTileSheets(Game1.mapDisplayDevice); - } - return remove; }, dispose); @@ -345,5 +351,34 @@ namespace StardewModdingAPI.Framework.ContentManagers // avoid hard disposable references; see remarks on the field this.BaseDisposableReferences.Clear(); } + + /**** + ** Private methods copied from the game code + ****/ +#pragma warning disable CS1574 // <see cref /> can't be resolved: the reference is valid but private + /// <summary>Parse a string path like <c>assetName:key</c>.</summary> + /// <param name="path">The string path.</param> + /// <param name="assetName">The extracted asset name.</param> + /// <param name="key">The extracted entry key.</param> + /// <exception cref="ContentLoadException">The string path is not in a valid format.</exception> + /// <remarks>This is copied as-is from <see cref="LocalizedContentManager.parseStringPath"/>.</remarks> + private void ParseStringPath(string path, out string assetName, out string key) + { + int length = path.IndexOf(':'); + assetName = length != -1 ? path.Substring(0, length) : throw new ContentLoadException("Unable to parse string path: " + path); + key = path.Substring(length + 1, path.Length - length - 1); + } + + /// <summary>Get a string value from a dictionary asset.</summary> + /// <param name="strings">The asset to read.</param> + /// <param name="key">The string key to find.</param> + /// <remarks>This is copied as-is from <see cref="LocalizedContentManager.GetString"/>.</remarks> + private string GetString(Dictionary<string, string> strings, string key) + { + return strings.TryGetValue(key + ".desktop", out string? str) + ? str + : strings[key]; + } +#pragma warning restore CS1574 } } diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 083df454..c53040e1 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -51,9 +51,8 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <param name="onDisposing">A callback to invoke when the content manager is being disposed.</param> /// <param name="onLoadingFirstAsset">A callback to invoke the first time *any* game content manager loads an asset.</param> /// <param name="onAssetLoaded">A callback to invoke when an asset is fully loaded.</param> - /// <param name="aggressiveMemoryOptimizations">Whether to enable more aggressive memory optimizations.</param> - public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, Action onLoadingFirstAsset, Action<BaseContentManager, IAssetName> onAssetLoaded, bool aggressiveMemoryOptimizations) - : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: false, aggressiveMemoryOptimizations: aggressiveMemoryOptimizations) + public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, Action onLoadingFirstAsset, Action<BaseContentManager, IAssetName> onAssetLoaded) + : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: false) { this.OnLoadingFirstAsset = onLoadingFirstAsset; this.OnAssetLoaded = onAssetLoaded; diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs index 1b0e1016..5c574a1a 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs @@ -21,8 +21,8 @@ namespace StardewModdingAPI.Framework.ContentManagers ** Public methods *********/ /// <inheritdoc /> - public GameContentManagerForAssetPropagation(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, Action onLoadingFirstAsset, Action<BaseContentManager, IAssetName> onAssetLoaded, bool aggressiveMemoryOptimizations) - : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, onLoadingFirstAsset, onAssetLoaded, aggressiveMemoryOptimizations) { } + public GameContentManagerForAssetPropagation(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, Action onLoadingFirstAsset, Action<BaseContentManager, IAssetName> onAssetLoaded) + : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, onLoadingFirstAsset, onAssetLoaded) { } /// <inheritdoc /> public override T LoadExact<T>(IAssetName assetName, bool useCache) diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index 8f64c5a8..65dffd8b 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -10,6 +10,7 @@ using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; +using StardewModdingAPI.Toolkit.Utilities.PathLookups; using StardewValley; using xTile; using xTile.Format; @@ -32,8 +33,8 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <summary>The game content manager used for map tilesheets not provided by the mod.</summary> private readonly IContentManager GameContentManager; - /// <summary>A case-insensitive lookup of relative paths within the <see cref="ContentManager.RootDirectory"/>.</summary> - private readonly CaseInsensitivePathLookup RelativePathCache; + /// <summary>A lookup for relative paths within the <see cref="ContentManager.RootDirectory"/>.</summary> + private readonly IFilePathLookup RelativePathLookup; /// <summary>If a map tilesheet's image source has no file extensions, the file extensions to check for in the local mod folder.</summary> private readonly string[] LocalTilesheetExtensions = { ".png", ".xnb" }; @@ -54,13 +55,12 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <param name="reflection">Simplifies access to private code.</param> /// <param name="jsonHelper">Encapsulates SMAPI's JSON file parsing.</param> /// <param name="onDisposing">A callback to invoke when the content manager is being disposed.</param> - /// <param name="aggressiveMemoryOptimizations">Whether to enable more aggressive memory optimizations.</param> - /// <param name="relativePathCache">A case-insensitive lookup of relative paths within the <paramref name="rootDirectory"/>.</param> - public ModContentManager(string name, IContentManager gameContentManager, IServiceProvider serviceProvider, string modName, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action<BaseContentManager> onDisposing, bool aggressiveMemoryOptimizations, CaseInsensitivePathLookup relativePathCache) - : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: true, aggressiveMemoryOptimizations: aggressiveMemoryOptimizations) + /// <param name="relativePathLookup">A lookup for relative paths within the <paramref name="rootDirectory"/>.</param> + public ModContentManager(string name, IContentManager gameContentManager, IServiceProvider serviceProvider, string modName, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action<BaseContentManager> onDisposing, IFilePathLookup relativePathLookup) + : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: true) { this.GameContentManager = gameContentManager; - this.RelativePathCache = relativePathCache; + this.RelativePathLookup = relativePathLookup; this.JsonHelper = jsonHelper; this.ModName = modName; @@ -257,7 +257,7 @@ namespace StardewModdingAPI.Framework.ContentManagers private FileInfo GetModFile(string path) { // map to case-insensitive path if needed - path = this.RelativePathCache.GetFilePath(path); + path = this.RelativePathLookup.GetFilePath(path); // try exact match FileInfo file = new(Path.Combine(this.FullRootDirectory, path)); |