diff --git a/docs/release-notes.md b/docs/release-notes.md
index a0d8826b..eb30ef7c 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -3,8 +3,9 @@
# Release notes
## Upcoming release
* For players:
+ * Improved performance for many mods still using the older content API.
* Disabled case-insensitive file paths (introduced in 3.14.0) by default.
- _You can enable them by editing `smapi-internal/config.json` if needed. They'll be re-enabled in a later version after they're reworked to reduce performance impact._
+ _You can enable them by editing `smapi-internal/config.json` if needed. They'll be re-enabled in an upcoming version after they're reworked a bit._
* Removed experimental 'aggressive memory optimizations' option.
_This was disabled by default and is no longer needed in most cases. Memory usage will be better reduced by reworked asset propagation in the upcoming SMAPI 4.0.0._
* Fixed 'content file was not found' error when the game tries to load unlocalized text from a localizable mod data asset.
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index ef442fbe..8ce0dba1 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -81,6 +81,14 @@ namespace StardewModdingAPI.Framework
/// The cached asset load/edit operations to apply, indexed by asset name.
private readonly TickCacheDictionary AssetOperationsByKey = new();
+ /// A cache of asset operation groups created for legacy implementations.
+ [Obsolete]
+ private readonly Dictionary LegacyLoaderCache = new(ReferenceEqualityComparer.Instance);
+
+ /// A cache of asset operation groups created for legacy implementations.
+ [Obsolete]
+ private readonly Dictionary LegacyEditorCache = new(ReferenceEqualityComparer.Instance);
+
/*********
** Accessors
@@ -598,21 +606,26 @@ namespace StardewModdingAPI.Framework
}
// add operation
- yield return new AssetOperationGroup(
- mod: loader.Mod,
- loadOperations: new[]
- {
- new AssetLoadOperation(
- mod: loader.Mod,
- priority: AssetLoadPriority.Exclusive,
- onBehalfOf: null,
- getData: assetInfo => loader.Data.Load(
- this.GetLegacyAssetInfo(assetInfo)
+ if (!this.LegacyLoaderCache.TryGetValue(loader.Data, out AssetOperationGroup? group))
+ {
+ this.LegacyLoaderCache[loader.Data] = group = new AssetOperationGroup(
+ mod: loader.Mod,
+ loadOperations: new[]
+ {
+ new AssetLoadOperation(
+ mod: loader.Mod,
+ priority: AssetLoadPriority.Exclusive,
+ onBehalfOf: null,
+ getData: assetInfo => loader.Data.Load(
+ this.GetLegacyAssetInfo(assetInfo)
+ )
)
- )
- },
- editOperations: Array.Empty()
- );
+ },
+ editOperations: Array.Empty()
+ );
+ }
+
+ yield return group;
}
// legacy edit operations
@@ -652,21 +665,26 @@ namespace StardewModdingAPI.Framework
};
// add operation
- yield return new AssetOperationGroup(
- mod: editor.Mod,
- loadOperations: Array.Empty(),
- editOperations: new[]
- {
- new AssetEditOperation(
- mod: editor.Mod,
- priority: priority,
- onBehalfOf: null,
- applyEdit: assetData => editor.Data.Edit(
- this.GetLegacyAssetData(assetData)
+ if (!this.LegacyEditorCache.TryGetValue(editor.Data, out AssetOperationGroup? group))
+ {
+ this.LegacyEditorCache[editor.Data] = group = new AssetOperationGroup(
+ mod: editor.Mod,
+ loadOperations: Array.Empty(),
+ editOperations: new[]
+ {
+ new AssetEditOperation(
+ mod: editor.Mod,
+ priority: priority,
+ onBehalfOf: null,
+ applyEdit: assetData => editor.Data.Edit(
+ this.GetLegacyAssetData(assetData)
+ )
)
- )
- }
- );
+ }
+ );
+ }
+
+ yield return group;
}
#pragma warning restore CS0612, CS0618
}