diff options
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r-- | src/SMAPI/Framework/ContentCoordinator.cs | 17 | ||||
-rw-r--r-- | src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs | 47 |
2 files changed, 62 insertions, 2 deletions
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index 81265fa2..6a7385c3 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -117,8 +117,21 @@ namespace StardewModdingAPI.Framework aggressiveMemoryOptimizations: aggressiveMemoryOptimizations ) ); + var contentManagerForAssetPropagation = new GameContentManagerForAssetPropagation( + name: nameof(GameContentManagerForAssetPropagation), + serviceProvider: serviceProvider, + rootDirectory: rootDirectory, + currentCulture: currentCulture, + coordinator: this, + monitor: monitor, + reflection: reflection, + onDisposing: this.OnDisposing, + onLoadingFirstAsset: onLoadingFirstAsset, + aggressiveMemoryOptimizations: aggressiveMemoryOptimizations + ); + this.ContentManagers.Add(contentManagerForAssetPropagation); this.VanillaContentManager = new LocalizedContentManager(serviceProvider, rootDirectory); - this.CoreAssets = new CoreAssetPropagator(this.MainContentManager.AssertAndNormalizeAssetName, reflection, aggressiveMemoryOptimizations); + this.CoreAssets = new CoreAssetPropagator(this.MainContentManager, contentManagerForAssetPropagation, reflection, aggressiveMemoryOptimizations); } /// <summary>Get a new content manager which handles reading files from the game content folder with support for interception.</summary> @@ -298,7 +311,7 @@ namespace StardewModdingAPI.Framework // reload core game assets if (removedAssets.Any()) { - IDictionary<string, bool> propagated = this.CoreAssets.Propagate(this.MainContentManager, removedAssets.ToDictionary(p => p.Key, p => p.Value)); // use an intercepted content manager + IDictionary<string, bool> propagated = this.CoreAssets.Propagate(removedAssets.ToDictionary(p => p.Key, p => p.Value)); // use an intercepted content manager this.Monitor.Log($"Invalidated {removedAssets.Count} asset names ({string.Join(", ", removedAssets.Keys.OrderBy(p => p, StringComparer.OrdinalIgnoreCase))}); propagated {propagated.Count(p => p.Value)} core assets.", LogLevel.Trace); } else diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs new file mode 100644 index 00000000..cbbebf02 --- /dev/null +++ b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs @@ -0,0 +1,47 @@ +using System; +using System.Globalization; +using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI.Framework.Reflection; +using StardewValley; + +namespace StardewModdingAPI.Framework.ContentManagers +{ + /// <summary>An extension of <see cref="GameContentManager"/> specifically optimized for asset propagation.</summary> + /// <remarks>This avoids sharing an asset cache with <see cref="Game1.content"/> or mods, so that assets can be safely disposed when the vanilla game no longer references them.</remarks> + internal class GameContentManagerForAssetPropagation : GameContentManager + { + /********* + ** Fields + *********/ + /// <summary>A unique value used in <see cref="Texture2D"/> to identify assets loaded through this instance.</summary> + private readonly string Tag = $"Pathoschild.SMAPI/LoadedBy:{nameof(GameContentManagerForAssetPropagation)}"; + + + /********* + ** Public methods + *********/ + /// <inheritdoc /> + public GameContentManagerForAssetPropagation(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, Action onLoadingFirstAsset, bool aggressiveMemoryOptimizations) + : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, onLoadingFirstAsset, aggressiveMemoryOptimizations) { } + + /// <inheritdoc /> + public override T Load<T>(string assetName, LanguageCode language, bool useCache) + { + T data = base.Load<T>(assetName, language, useCache); + + if (data is Texture2D texture) + texture.Tag = this.Tag; + + return data; + } + + /// <summary>Get whether a texture was loaded by this content manager.</summary> + /// <param name="texture">The texture to check.</param> + public bool IsReponsibleFor(Texture2D texture) + { + return + texture?.Tag is string tag + && tag.Contains(this.Tag); + } + } +} |