From bbe5983acdd082d2185a69e2ad37d659a298223d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 11 May 2022 21:36:45 -0400 Subject: rewrite asset operations to reduce allocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • When raising AssetRequested, SMAPI now creates a single event args model and reuses it for each handler. • There's now a single AssetOperationGroup per asset, which tracks the loaders/editors registered by every mod for that asset. • The operation group's loader/editor lists are now used directly instead of querying them. --- src/SMAPI/Events/AssetRequestedEventArgs.cs | 43 +++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) (limited to 'src/SMAPI/Events') diff --git a/src/SMAPI/Events/AssetRequestedEventArgs.cs b/src/SMAPI/Events/AssetRequestedEventArgs.cs index d0aef1db..d6561028 100644 --- a/src/SMAPI/Events/AssetRequestedEventArgs.cs +++ b/src/SMAPI/Events/AssetRequestedEventArgs.cs @@ -14,7 +14,7 @@ namespace StardewModdingAPI.Events ** Fields *********/ /// The mod handling the event. - private readonly IModMetadata Mod; + private IModMetadata? Mod; /// Get the mod metadata for a content pack, if it's a valid content pack for the mod. private readonly Func GetOnBehalfOf; @@ -37,26 +37,31 @@ namespace StardewModdingAPI.Events public Type DataType => this.AssetInfo.DataType; /// The load operations requested by the event handler. - internal IList LoadOperations { get; } = new List(); + internal List LoadOperations { get; } = new(); /// The edit operations requested by the event handler. - internal IList EditOperations { get; } = new List(); + internal List EditOperations { get; } = new(); /********* ** Public methods *********/ /// Construct an instance. - /// The mod handling the event. /// The asset info being requested. /// Get the mod metadata for a content pack, if it's a valid content pack for the mod. - internal AssetRequestedEventArgs(IModMetadata mod, IAssetInfo assetInfo, Func getOnBehalfOf) + internal AssetRequestedEventArgs(IAssetInfo assetInfo, Func getOnBehalfOf) { - this.Mod = mod; this.AssetInfo = assetInfo; this.GetOnBehalfOf = getOnBehalfOf; } + /// Set the mod handling the event. + /// The mod handling the event. + internal void SetMod(IModMetadata mod) + { + this.Mod = mod; + } + /// Provide the initial instance for the asset, instead of trying to load it from the game's Content folder. /// Get the initial instance of an asset. /// If there are multiple loads that apply to the same asset, the priority with which this one should be applied. @@ -70,10 +75,11 @@ namespace StardewModdingAPI.Events /// public void LoadFrom(Func load, AssetLoadPriority priority, string? onBehalfOf = null) { + IModMetadata mod = this.GetMod(); this.LoadOperations.Add( new AssetLoadOperation( - Mod: this.Mod, - OnBehalfOf: this.GetOnBehalfOf(this.Mod, onBehalfOf, "load assets"), + Mod: mod, + OnBehalfOf: this.GetOnBehalfOf(mod, onBehalfOf, "load assets"), Priority: priority, GetData: _ => load() ) @@ -94,12 +100,13 @@ namespace StardewModdingAPI.Events public void LoadFromModFile(string relativePath, AssetLoadPriority priority) where TAsset : notnull { + IModMetadata mod = this.GetMod(); this.LoadOperations.Add( new AssetLoadOperation( - Mod: this.Mod, + Mod: mod, OnBehalfOf: null, Priority: priority, - GetData: _ => this.Mod.Mod!.Helper.ModContent.Load(relativePath) + GetData: _ => mod.Mod!.Helper.ModContent.Load(relativePath) ) ); } @@ -117,14 +124,26 @@ namespace StardewModdingAPI.Events /// public void Edit(Action apply, AssetEditPriority priority = AssetEditPriority.Default, string? onBehalfOf = null) { + IModMetadata mod = this.GetMod(); this.EditOperations.Add( new AssetEditOperation( - Mod: this.Mod, + Mod: mod, Priority: priority, - OnBehalfOf: this.GetOnBehalfOf(this.Mod, onBehalfOf, "edit assets"), + OnBehalfOf: this.GetOnBehalfOf(mod, onBehalfOf, "edit assets"), ApplyEdit: apply ) ); } + + + /********* + ** Private methods + *********/ + /// Get the mod handling the event. + /// This instance hasn't been initialized with the mod metadata yet. + private IModMetadata GetMod() + { + return this.Mod ?? throw new InvalidOperationException($"This {nameof(AssetRequestedEventArgs)} instance hasn't been initialized yet."); + } } } -- cgit