From b77eab6e0a09099998aa806302694e82216e79f8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 25 Mar 2022 00:35:31 -0400 Subject: add AssetReady content event (#766) --- src/SMAPI/Framework/ContentCoordinator.cs | 10 +++++++++- src/SMAPI/Framework/ContentManagers/GameContentManager.cs | 12 ++++++++++-- .../ContentManagers/GameContentManagerForAssetPropagation.cs | 4 ++-- src/SMAPI/Framework/Events/EventManager.cs | 6 ++++-- src/SMAPI/Framework/Events/ModContentEvents.cs | 7 +++++++ src/SMAPI/Framework/SCore.cs | 11 +++++++++++ 6 files changed, 43 insertions(+), 7 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index 4f696928..4dbbae15 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -49,6 +49,9 @@ namespace StardewModdingAPI.Framework /// A callback to invoke the first time *any* game content manager loads an asset. private readonly Action OnLoadingFirstAsset; + /// A callback to invoke when an asset is fully loaded. + private readonly Action OnAssetLoaded; + /// A callback to invoke when any asset names have been invalidated from the cache. private readonly Action> OnAssetsInvalidated; @@ -111,16 +114,18 @@ namespace StardewModdingAPI.Framework /// Simplifies access to private code. /// Encapsulates SMAPI's JSON file parsing. /// A callback to invoke the first time *any* game content manager loads an asset. + /// A callback to invoke when an asset is fully loaded. /// Whether to enable more aggressive memory optimizations. /// A callback to invoke when any asset names have been invalidated from the cache. /// Get the load/edit operations to apply to an asset by querying registered event handlers. - public ContentCoordinator(IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action onLoadingFirstAsset, bool aggressiveMemoryOptimizations, Action> onAssetsInvalidated, Func> requestAssetOperations) + public ContentCoordinator(IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action onLoadingFirstAsset, Action onAssetLoaded, bool aggressiveMemoryOptimizations, Action> onAssetsInvalidated, Func> requestAssetOperations) { this.AggressiveMemoryOptimizations = aggressiveMemoryOptimizations; this.Monitor = monitor ?? throw new ArgumentNullException(nameof(monitor)); this.Reflection = reflection; this.JsonHelper = jsonHelper; this.OnLoadingFirstAsset = onLoadingFirstAsset; + this.OnAssetLoaded = onAssetLoaded; this.OnAssetsInvalidated = onAssetsInvalidated; this.RequestAssetOperations = requestAssetOperations; this.FullRootDirectory = Path.Combine(Constants.GamePath, rootDirectory); @@ -135,6 +140,7 @@ namespace StardewModdingAPI.Framework reflection: reflection, onDisposing: this.OnDisposing, onLoadingFirstAsset: onLoadingFirstAsset, + onAssetLoaded: onAssetLoaded, aggressiveMemoryOptimizations: aggressiveMemoryOptimizations ) ); @@ -148,6 +154,7 @@ namespace StardewModdingAPI.Framework reflection: reflection, onDisposing: this.OnDisposing, onLoadingFirstAsset: onLoadingFirstAsset, + onAssetLoaded: onAssetLoaded, aggressiveMemoryOptimizations: aggressiveMemoryOptimizations ); this.ContentManagers.Add(contentManagerForAssetPropagation); @@ -172,6 +179,7 @@ namespace StardewModdingAPI.Framework reflection: this.Reflection, onDisposing: this.OnDisposing, onLoadingFirstAsset: this.OnLoadingFirstAsset, + onAssetLoaded: this.OnAssetLoaded, aggressiveMemoryOptimizations: this.AggressiveMemoryOptimizations ); this.ContentManagers.Add(manager); diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 642e526c..12ed5506 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -35,6 +35,9 @@ namespace StardewModdingAPI.Framework.ContentManagers /// A callback to invoke the first time *any* game content manager loads an asset. private readonly Action OnLoadingFirstAsset; + /// A callback to invoke when an asset is fully loaded. + private readonly Action OnAssetLoaded; + /********* ** Public methods @@ -49,11 +52,13 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Simplifies access to private code. /// A callback to invoke when the content manager is being disposed. /// A callback to invoke the first time *any* game content manager loads an asset. + /// A callback to invoke when an asset is fully loaded. /// Whether to enable more aggressive memory optimizations. - public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action onDisposing, Action onLoadingFirstAsset, bool aggressiveMemoryOptimizations) + public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action onDisposing, Action onLoadingFirstAsset, Action onAssetLoaded, bool aggressiveMemoryOptimizations) : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: false, aggressiveMemoryOptimizations: aggressiveMemoryOptimizations) { this.OnLoadingFirstAsset = onLoadingFirstAsset; + this.OnAssetLoaded = onAssetLoaded; } /// @@ -129,8 +134,11 @@ namespace StardewModdingAPI.Framework.ContentManagers }); } - // update cache & return data + // update cache this.TrackAsset(assetName, data, language, useCache); + + // raise event & return data + this.OnAssetLoaded(this, assetName); return data; } diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs index 206ece30..847e2ce1 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 *********/ /// - public GameContentManagerForAssetPropagation(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action onDisposing, Action onLoadingFirstAsset, bool aggressiveMemoryOptimizations) - : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, onLoadingFirstAsset, aggressiveMemoryOptimizations) { } + public GameContentManagerForAssetPropagation(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action onDisposing, Action onLoadingFirstAsset, Action onAssetLoaded, bool aggressiveMemoryOptimizations) + : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, onLoadingFirstAsset, onAssetLoaded, aggressiveMemoryOptimizations) { } /// public override T Load(IAssetName assetName, LanguageCode language, bool useCache) diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 96582380..bcfd7dd7 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -1,10 +1,8 @@ -using System.Diagnostics.CodeAnalysis; using StardewModdingAPI.Events; namespace StardewModdingAPI.Framework.Events { /// Manages SMAPI events. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Private fields are deliberately named to simplify organisation.")] internal class EventManager { /********* @@ -19,6 +17,9 @@ namespace StardewModdingAPI.Framework.Events /// public readonly ManagedEvent AssetsInvalidated; + /// + public readonly ManagedEvent AssetReady; + /**** ** Display @@ -202,6 +203,7 @@ namespace StardewModdingAPI.Framework.Events // init events this.AssetRequested = ManageEventOf(nameof(IModEvents.Content), nameof(IContentEvents.AssetRequested)); this.AssetsInvalidated = ManageEventOf(nameof(IModEvents.Content), nameof(IContentEvents.AssetsInvalidated)); + this.AssetReady = ManageEventOf(nameof(IModEvents.Content), nameof(IContentEvents.AssetReady)); this.MenuChanged = ManageEventOf(nameof(IModEvents.Display), nameof(IDisplayEvents.MenuChanged)); this.Rendering = ManageEventOf(nameof(IModEvents.Display), nameof(IDisplayEvents.Rendering), isPerformanceCritical: true); diff --git a/src/SMAPI/Framework/Events/ModContentEvents.cs b/src/SMAPI/Framework/Events/ModContentEvents.cs index 4d0cfb97..cb242e99 100644 --- a/src/SMAPI/Framework/Events/ModContentEvents.cs +++ b/src/SMAPI/Framework/Events/ModContentEvents.cs @@ -23,6 +23,13 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.AssetsInvalidated.Remove(value); } + /// + public event EventHandler AssetReady + { + add => this.EventManager.AssetReady.Add(value, this.Mod); + remove => this.EventManager.AssetReady.Remove(value); + } + /********* ** Public methods diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index e9bc9a2b..9d97ec7d 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -19,6 +19,7 @@ using Newtonsoft.Json; using StardewModdingAPI.Enums; using StardewModdingAPI.Events; using StardewModdingAPI.Framework.Content; +using StardewModdingAPI.Framework.ContentManagers; using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Input; @@ -1106,6 +1107,15 @@ namespace StardewModdingAPI.Framework this.EventManager.DayEnding.RaiseEmpty(); } + /// A callback invoked after an asset is fully loaded through a content manager. + /// The content manager through which the asset was loaded. + /// The asset name that was loaded. + private void OnAssetLoaded(IContentManager contentManager, IAssetName assetName) + { + if (this.EventManager.AssetReady.HasListeners()) + this.EventManager.AssetReady.Raise(new AssetReadyEventArgs(assetName)); + } + /// A callback invoked after assets have been invalidated from the content cache. /// The invalidated asset names. private void OnAssetsInvalidated(IEnumerable assetNames) @@ -1183,6 +1193,7 @@ namespace StardewModdingAPI.Framework reflection: this.Reflection, jsonHelper: this.Toolkit.JsonHelper, onLoadingFirstAsset: this.InitializeBeforeFirstAssetLoaded, + onAssetLoaded: this.OnAssetLoaded, onAssetsInvalidated: this.OnAssetsInvalidated, aggressiveMemoryOptimizations: this.Settings.AggressiveMemoryOptimizations, requestAssetOperations: this.RequestAssetOperations -- cgit