add DoesAssetExist to support the upcoming Stardew Valley 1.6 (#766)

This commit is contained in:
Jesse Plamondon-Willard 2022-03-05 15:38:05 -05:00
parent b0d8b23c2c
commit b68b301b71
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
5 changed files with 80 additions and 14 deletions

View File

@ -296,6 +296,22 @@ namespace StardewModdingAPI.Framework
return Path.Combine(this.ManagedPrefix, modID.ToLower());
}
/// <summary>Get whether an asset from a mod folder exists.</summary>
/// <param name="contentManagerID">The unique name for the content manager which should load this asset.</param>
/// <param name="assetName">The asset name within the mod folder.</param>
public bool DoesManagedAssetExist(string contentManagerID, IAssetName assetName)
{
// get content manager
IContentManager contentManager = this.ContentManagerLock.InReadLock(() =>
this.ContentManagers.FirstOrDefault(p => p.IsNamespaced && p.Name == contentManagerID)
);
if (contentManager == null)
throw new InvalidOperationException($"The '{contentManagerID}' prefix isn't handled by any mod.");
// get whether the asset exists
return contentManager.DoesAssetExist(assetName);
}
/// <summary>Get a copy of an asset from a mod folder.</summary>
/// <typeparam name="T">The asset type.</typeparam>
/// <param name="contentManagerID">The unique name for the content manager which should load this asset.</param>

View File

@ -92,6 +92,12 @@ namespace StardewModdingAPI.Framework.ContentManagers
this.BaseDisposableReferences = reflection.GetField<List<IDisposable>>(this, "disposableAssets").GetValue();
}
/// <inheritdoc />
public virtual bool DoesAssetExist(IAssetName assetName)
{
return this.Cache.ContainsKey(assetName.Name);
}
/// <inheritdoc />
[Obsolete("This method is implemented for the base game and should not be used directly. To load an asset from the underlying content manager directly, use " + nameof(BaseContentManager.RawLoad) + " instead.")]
public override T LoadBase<T>(string assetName)

View File

@ -62,6 +62,29 @@ namespace StardewModdingAPI.Framework.ContentManagers
this.OnLoadingFirstAsset = onLoadingFirstAsset;
}
/// <inheritdoc />
public override bool DoesAssetExist(IAssetName assetName)
{
if (base.DoesAssetExist(assetName))
return true;
// managed asset
if (this.Coordinator.TryParseManagedAssetKey(assetName.Name, out string contentManagerID, out IAssetName relativePath))
return this.Coordinator.DoesManagedAssetExist(contentManagerID, relativePath);
// else check for loaders
string locale = this.GetLocale();
IAssetInfo info = new AssetInfo(locale, assetName, typeof(object), this.AssertAndNormalizeAssetName);
ModLinked<IAssetLoader>[] loaders = this.GetLoaders<object>(info).ToArray();
if (loaders.Length > 1)
{
string[] loaderNames = loaders.Select(p => p.Mod.DisplayName).ToArray();
this.Monitor.Log($"Multiple mods want to provide the '{info.Name}' asset ({string.Join(", ", loaderNames)}), but an asset can't be loaded multiple times. SMAPI will use the default asset instead; uninstall one of the mods to fix this. (Message for modders: you should usually use {typeof(IAssetEditor)} instead to avoid conflicts.)", LogLevel.Warn);
}
return loaders.Length == 1;
}
/// <inheritdoc />
public override T Load<T>(IAssetName assetName, LanguageCode language, bool useCache)
{
@ -246,20 +269,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
private IAssetData ApplyLoader<T>(IAssetInfo info)
{
// find matching loaders
var loaders = this.Loaders
.Where(entry =>
{
try
{
return entry.Data.CanLoad<T>(info);
}
catch (Exception ex)
{
entry.Mod.LogAsMod($"Mod failed when checking whether it could load asset '{info.Name}', and will be ignored. Error details:\n{ex.GetLogSummary()}", LogLevel.Error);
return false;
}
})
.ToArray();
var loaders = this.GetLoaders<T>(info).ToArray();
// validate loaders
if (!loaders.Any())
@ -360,6 +370,26 @@ namespace StardewModdingAPI.Framework.ContentManagers
return asset;
}
/// <summary>Get the asset loaders which handle the asset.</summary>
/// <typeparam name="T">The asset type.</typeparam>
/// <param name="info">The basic asset metadata.</param>
private IEnumerable<ModLinked<IAssetLoader>> GetLoaders<T>(IAssetInfo info)
{
return this.Loaders
.Where(entry =>
{
try
{
return entry.Data.CanLoad<T>(info);
}
catch (Exception ex)
{
entry.Mod.LogAsMod($"Mod failed when checking whether it could load asset '{info.Name}', and will be ignored. Error details:\n{ex.GetLogSummary()}", LogLevel.Error);
return false;
}
});
}
/// <summary>Validate that an asset loaded by a mod is valid and won't cause issues, and fix issues if possible.</summary>
/// <typeparam name="T">The asset type.</typeparam>
/// <param name="info">The basic asset metadata.</param>

View File

@ -28,6 +28,10 @@ namespace StardewModdingAPI.Framework.ContentManagers
/*********
** Methods
*********/
/// <summary>Get whether an asset exists and can be loaded.</summary>
/// <param name="assetName">The normalized asset name.</param>
bool DoesAssetExist(IAssetName assetName);
/// <summary>Load an asset that has been processed by the content pipeline.</summary>
/// <typeparam name="T">The type of asset to load.</typeparam>
/// <param name="assetName">The asset name relative to the loader root directory.</param>

View File

@ -63,6 +63,16 @@ namespace StardewModdingAPI.Framework.ContentManagers
this.ModName = modName;
}
/// <inheritdoc />
public override bool DoesAssetExist(IAssetName assetName)
{
if (base.DoesAssetExist(assetName))
return true;
FileInfo file = this.GetModFile(assetName.Name);
return file.Exists;
}
/// <inheritdoc />
public override T Load<T>(string assetName)
{