summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs17
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs47
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);
+ }
+ }
+}