From 2ec0e0e26a16b94ba4a12d3bb4561d64a7411b34 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 16 Aug 2017 23:27:07 -0400 Subject: only invalidate cache entries matched by new interceptors --- .../Framework/ModHelpers/ContentHelper.cs | 2 +- src/StardewModdingAPI/Framework/SContentManager.cs | 94 ++++++++++++++-------- 2 files changed, 63 insertions(+), 33 deletions(-) (limited to 'src/StardewModdingAPI/Framework') diff --git a/src/StardewModdingAPI/Framework/ModHelpers/ContentHelper.cs b/src/StardewModdingAPI/Framework/ModHelpers/ContentHelper.cs index e94d309e..ffa78ff6 100644 --- a/src/StardewModdingAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/StardewModdingAPI/Framework/ModHelpers/ContentHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; diff --git a/src/StardewModdingAPI/Framework/SContentManager.cs b/src/StardewModdingAPI/Framework/SContentManager.cs index 0854c379..9e086870 100644 --- a/src/StardewModdingAPI/Framework/SContentManager.cs +++ b/src/StardewModdingAPI/Framework/SContentManager.cs @@ -1,8 +1,9 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using StardewModdingAPI.AssemblyRewriters; @@ -96,33 +97,6 @@ namespace StardewModdingAPI.Framework } - /// Get the locale codes (like ja-JP) used in asset keys. - /// Simplifies access to private game code. - private IDictionary GetKeyLocales(Reflector reflection) - { - // get the private code field directly to avoid changed-code logic - IPrivateField codeField = reflection.GetPrivateField(typeof(LocalizedContentManager), "_currentLangCode"); - - // remember previous settings - LanguageCode previousCode = codeField.GetValue(); - string previousOverride = this.LanguageCodeOverride; - - // create locale => code map - IDictionary map = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - this.LanguageCodeOverride = null; - foreach (LanguageCode code in Enum.GetValues(typeof(LanguageCode))) - { - codeField.SetValue(code); - map[this.GetKeyLocale.Invoke()] = code; - } - - // restore previous settings - codeField.SetValue(previousCode); - this.LanguageCodeOverride = previousOverride; - - return map; - } - /// Normalise path separators in a file path. For asset keys, see instead. /// The file path to normalise. public string NormalisePathSeparators(string path) @@ -209,10 +183,39 @@ namespace StardewModdingAPI.Framework return GetAllAssetKeys().Distinct(); } - /// Reset the asset cache and reload the game's static assets. + /// Purge assets from the cache that match one of the interceptors. + /// The asset editors for which to purge matching assets. + /// The asset loaders for which to purge matching assets. + /// Returns whether any cache entries were invalidated. + public bool InvalidateCacheFor(IAssetEditor[] editors, IAssetLoader[] loaders) + { + if (!editors.Any() && !loaders.Any()) + return false; + + // get CanEdit/Load methods + MethodInfo canEdit = typeof(IAssetEditor).GetMethod(nameof(IAssetEditor.CanEdit)); + MethodInfo canLoad = typeof(IAssetLoader).GetMethod(nameof(IAssetLoader.CanLoad)); + + // invalidate matching keys + return this.InvalidateCache((assetName, assetType) => + { + // get asset metadata + IAssetInfo info = new AssetInfo(this.GetLocale(), assetName, assetType, this.NormaliseAssetName); + + // check loaders + MethodInfo canLoadGeneric = canLoad.MakeGenericMethod(assetType); + if (loaders.Any(loader => (bool)canLoadGeneric.Invoke(loader, new object[] { info }))) + return true; + + // check editors + MethodInfo canEditGeneric = canEdit.MakeGenericMethod(assetType); + return editors.Any(editor => (bool)canEditGeneric.Invoke(editor, new object[] { info })); + }); + } + + /// Purge matched assets from the cache. /// Matches the asset keys to invalidate. /// Returns whether any cache entries were invalidated. - /// This implementation is derived from . public bool InvalidateCache(Func predicate) { // find matching asset keys @@ -220,7 +223,7 @@ namespace StardewModdingAPI.Framework HashSet purgeAssetKeys = new HashSet(StringComparer.InvariantCultureIgnoreCase); foreach (string cacheKey in this.Cache.Keys) { - this.ParseCacheKey(cacheKey, out string assetKey, out string localeCode); + this.ParseCacheKey(cacheKey, out string assetKey, out _); Type type = this.Cache[cacheKey].GetType(); if (predicate(assetKey, type)) { @@ -237,7 +240,7 @@ namespace StardewModdingAPI.Framework int reloaded = 0; foreach (string key in purgeAssetKeys) { - if(this.CoreAssets.ReloadForKey(this, key)) + if (this.CoreAssets.ReloadForKey(this, key)) reloaded++; } @@ -263,6 +266,33 @@ namespace StardewModdingAPI.Framework || this.Cache.ContainsKey($"{normalisedAssetName}.{this.GetKeyLocale.Invoke()}"); // translated asset } + /// Get the locale codes (like ja-JP) used in asset keys. + /// Simplifies access to private game code. + private IDictionary GetKeyLocales(Reflector reflection) + { + // get the private code field directly to avoid changed-code logic + IPrivateField codeField = reflection.GetPrivateField(typeof(LocalizedContentManager), "_currentLangCode"); + + // remember previous settings + LanguageCode previousCode = codeField.GetValue(); + string previousOverride = this.LanguageCodeOverride; + + // create locale => code map + IDictionary map = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + this.LanguageCodeOverride = null; + foreach (LanguageCode code in Enum.GetValues(typeof(LanguageCode))) + { + codeField.SetValue(code); + map[this.GetKeyLocale.Invoke()] = code; + } + + // restore previous settings + codeField.SetValue(previousCode); + this.LanguageCodeOverride = previousOverride; + + return map; + } + /// Parse a cache key into its component parts. /// The input cache key. /// The original asset key. -- cgit