tweak asset interception code to simplify future work (#255)
This commit is contained in:
parent
49c75de5fc
commit
271843d861
|
@ -111,28 +111,16 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
|
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
|
||||||
public override T Load<T>(string assetName)
|
public override T Load<T>(string assetName)
|
||||||
{
|
{
|
||||||
// get normalised metadata
|
|
||||||
assetName = this.NormaliseAssetName(assetName);
|
assetName = this.NormaliseAssetName(assetName);
|
||||||
string cacheLocale = this.GetCacheLocale(assetName);
|
|
||||||
|
|
||||||
// skip if already loaded
|
// skip if already loaded
|
||||||
if (this.IsNormalisedKeyLoaded(assetName))
|
if (this.IsNormalisedKeyLoaded(assetName))
|
||||||
return base.Load<T>(assetName);
|
return base.Load<T>(assetName);
|
||||||
|
|
||||||
// let mods intercept content
|
// load asset
|
||||||
IAssetInfo info = new AssetInfo(cacheLocale, assetName, typeof(T), this.NormaliseAssetName);
|
T asset = this.GetAssetWithInterceptors(this.GetLocale(), assetName, () => base.Load<T>(assetName));
|
||||||
Lazy<IAssetData> data = new Lazy<IAssetData>(() => new AssetDataForObject(info.Locale, info.AssetName, base.Load<T>(assetName), this.NormaliseAssetName));
|
this.Cache[assetName] = asset;
|
||||||
if (this.TryOverrideAssetLoad(info, data, out T result))
|
return asset;
|
||||||
{
|
|
||||||
if (result == null)
|
|
||||||
throw new InvalidCastException($"Can't override asset '{assetName}' with a null value.");
|
|
||||||
|
|
||||||
this.Cache[assetName] = result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback to default behavior
|
|
||||||
return base.Load<T>(assetName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Inject an asset into the cache.</summary>
|
/// <summary>Inject an asset into the cache.</summary>
|
||||||
|
@ -162,27 +150,21 @@ namespace StardewModdingAPI.Framework
|
||||||
|| this.Cache.ContainsKey($"{normalisedAssetName}.{this.GetKeyLocale.Invoke<string>()}"); // translated asset
|
|| this.Cache.ContainsKey($"{normalisedAssetName}.{this.GetKeyLocale.Invoke<string>()}"); // translated asset
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get the locale for which the asset name was saved, if any.</summary>
|
/// <summary>Read an asset with support for asset interceptors.</summary>
|
||||||
/// <param name="normalisedAssetName">The normalised asset name.</param>
|
|
||||||
private string GetCacheLocale(string normalisedAssetName)
|
|
||||||
{
|
|
||||||
string locale = this.GetKeyLocale.Invoke<string>();
|
|
||||||
return this.Cache.ContainsKey($"{normalisedAssetName}.{locale}")
|
|
||||||
? locale
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Try to override an asset being loaded.</summary>
|
|
||||||
/// <typeparam name="T">The asset type.</typeparam>
|
/// <typeparam name="T">The asset type.</typeparam>
|
||||||
/// <param name="info">The asset metadata.</param>
|
/// <param name="locale">The current content locale.</param>
|
||||||
/// <param name="data">The loaded asset data.</param>
|
/// <param name="normalisedKey">The normalised asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
|
||||||
/// <param name="result">The asset to use instead.</param>
|
/// <param name="getData">Get the asset from the underlying content manager.</param>
|
||||||
/// <returns>Returns whether the asset should be overridden by <paramref name="result"/>.</returns>
|
private T GetAssetWithInterceptors<T>(string locale, string normalisedKey, Func<T> getData)
|
||||||
private bool TryOverrideAssetLoad<T>(IAssetInfo info, Lazy<IAssetData> data, out T result)
|
|
||||||
{
|
{
|
||||||
bool edited = false;
|
// get metadata
|
||||||
|
IAssetInfo info = new AssetInfo(locale, normalisedKey, typeof(T), this.NormaliseAssetName);
|
||||||
|
|
||||||
// apply editors
|
// load asset
|
||||||
|
T asset = getData();
|
||||||
|
|
||||||
|
// edit asset
|
||||||
|
IAssetData data = new AssetDataForObject(info.Locale, info.AssetName, asset, this.NormaliseAssetName);
|
||||||
foreach (var modEditors in this.Editors)
|
foreach (var modEditors in this.Editors)
|
||||||
{
|
{
|
||||||
IModMetadata mod = modEditors.Key;
|
IModMetadata mod = modEditors.Key;
|
||||||
|
@ -192,14 +174,16 @@ namespace StardewModdingAPI.Framework
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
this.Monitor.Log($"{mod.DisplayName} intercepted {info.AssetName}.", LogLevel.Trace);
|
this.Monitor.Log($"{mod.DisplayName} intercepted {info.AssetName}.", LogLevel.Trace);
|
||||||
editor.Edit<T>(data.Value);
|
editor.Edit<T>(data);
|
||||||
edited = true;
|
if (data.Data == null)
|
||||||
|
throw new InvalidOperationException($"{mod.DisplayName} incorrectly set asset '{normalisedKey}' to a null value.");
|
||||||
|
if (!(data.Data is T))
|
||||||
|
throw new InvalidOperationException($"{mod.DisplayName} incorrectly set asset '{normalisedKey}' to incompatible type '{data.Data.GetType()}', expected '{typeof(T)}'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return result
|
// return result
|
||||||
result = edited ? (T)data.Value.Data : default(T);
|
return (T)data.Data;
|
||||||
return edited;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue