make EntryDll manifest field case-insensitive

This commit is contained in:
Jesse Plamondon-Willard 2022-04-16 13:41:37 -04:00
parent e7fd95aafd
commit 1974324c43
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
4 changed files with 30 additions and 36 deletions

View File

@ -80,9 +80,6 @@ namespace StardewModdingAPI.Framework
/// <summary>The cached asset load/edit operations to apply, indexed by asset name.</summary>
private readonly TickCacheDictionary<IAssetName, AssetOperationGroup[]> AssetOperationsByKey = new();
/// <summary>The previously created case-insensitive path caches by root path.</summary>
private readonly Dictionary<string, CaseInsensitivePathCache> CaseInsensitivePathCaches = new(StringComparer.OrdinalIgnoreCase);
/*********
** Accessors
@ -211,7 +208,7 @@ namespace StardewModdingAPI.Framework
jsonHelper: this.JsonHelper,
onDisposing: this.OnDisposing,
aggressiveMemoryOptimizations: this.AggressiveMemoryOptimizations,
relativePathCache: this.GetCaseInsensitivePathCache(rootDirectory)
relativePathCache: CaseInsensitivePathCache.GetFor(rootDirectory)
);
this.ContentManagers.Add(manager);
return manager;
@ -486,18 +483,6 @@ namespace StardewModdingAPI.Framework
});
}
/// <summary>Get a dictionary of relative paths within a root path, for case-insensitive file lookups.</summary>
/// <param name="rootPath">The root path to scan.</param>
public CaseInsensitivePathCache GetCaseInsensitivePathCache(string rootPath)
{
rootPath = PathUtilities.NormalizePath(rootPath);
if (!this.CaseInsensitivePathCaches.TryGetValue(rootPath, out CaseInsensitivePathCache? cache))
this.CaseInsensitivePathCaches[rootPath] = cache = new CaseInsensitivePathCache(rootPath);
return cache;
}
/// <summary>Get the tilesheet ID order used by the unmodified version of a map asset.</summary>
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
public TilesheetReference[] GetVanillaTilesheetIds(string assetName)

View File

@ -8,7 +8,7 @@ using StardewModdingAPI.Toolkit.Framework.ModData;
using StardewModdingAPI.Toolkit.Framework.ModScanning;
using StardewModdingAPI.Toolkit.Framework.UpdateData;
using StardewModdingAPI.Toolkit.Serialization.Models;
using StardewModdingAPI.Toolkit.Utilities;
using StardewModdingAPI.Utilities;
namespace StardewModdingAPI.Framework.ModLoading
{
@ -140,20 +140,13 @@ namespace StardewModdingAPI.Framework.ModLoading
continue;
}
// invalid path
if (!File.Exists(Path.Combine(mod.DirectoryPath, mod.Manifest.EntryDll!)))
// file doesn't exist
string fileName = CaseInsensitivePathCache.GetFor(mod.DirectoryPath).GetFilePath(mod.Manifest.EntryDll!);
if (!File.Exists(Path.Combine(mod.DirectoryPath, fileName)))
{
mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its DLL '{mod.Manifest.EntryDll}' doesn't exist.");
continue;
}
// invalid capitalization
string? actualFilename = new DirectoryInfo(mod.DirectoryPath).GetFiles(mod.Manifest.EntryDll!).FirstOrDefault()?.Name;
if (actualFilename != mod.Manifest.EntryDll)
{
mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its {nameof(IManifest.EntryDll)} value '{mod.Manifest.EntryDll}' doesn't match the actual file capitalization '{actualFilename}'. The capitalization must match for crossplatform compatibility.");
continue;
}
}
// validate content pack

View File

@ -1748,7 +1748,7 @@ namespace StardewModdingAPI.Framework
if (mod.IsContentPack)
{
IMonitor monitor = this.LogManager.GetMonitor(mod.DisplayName);
CaseInsensitivePathCache relativePathCache = this.ContentCore.GetCaseInsensitivePathCache(mod.DirectoryPath);
CaseInsensitivePathCache relativePathCache = CaseInsensitivePathCache.GetFor(mod.DirectoryPath);
GameContentHelper gameContentHelper = new(this.ContentCore, mod, mod.DisplayName, monitor, this.Reflection);
IModContentHelper modContentHelper = new ModContentHelper(this.ContentCore, mod.DirectoryPath, mod, mod.DisplayName, gameContentHelper.GetUnderlyingContentManager(), relativePathCache, this.Reflection);
TranslationHelper translationHelper = new(mod, contentCore.GetLocale(), contentCore.Language);
@ -1765,7 +1765,10 @@ namespace StardewModdingAPI.Framework
else
{
// get mod info
string assemblyPath = Path.Combine(mod.DirectoryPath, manifest.EntryDll!);
string assemblyPath = Path.Combine(
mod.DirectoryPath,
CaseInsensitivePathCache.GetFor(mod.DirectoryPath).GetFilePath(manifest.EntryDll!)
);
// load mod
Assembly modAssembly;
@ -1830,7 +1833,7 @@ namespace StardewModdingAPI.Framework
{
IMonitor packMonitor = this.LogManager.GetMonitor(packManifest.Name);
CaseInsensitivePathCache relativePathCache = this.ContentCore.GetCaseInsensitivePathCache(packDirPath);
CaseInsensitivePathCache relativePathCache = CaseInsensitivePathCache.GetFor(packDirPath);
GameContentHelper gameContentHelper = new(contentCore, mod, packManifest.Name, packMonitor, this.Reflection);
IModContentHelper packContentHelper = new ModContentHelper(contentCore, packDirPath, mod, packManifest.Name, gameContentHelper.GetUnderlyingContentManager(), relativePathCache, this.Reflection);
@ -1844,7 +1847,7 @@ namespace StardewModdingAPI.Framework
IModEvents events = new ModEvents(mod, this.EventManager);
ICommandHelper commandHelper = new CommandHelper(mod, this.CommandManager);
CaseInsensitivePathCache relativePathCache = this.ContentCore.GetCaseInsensitivePathCache(mod.DirectoryPath);
CaseInsensitivePathCache relativePathCache = CaseInsensitivePathCache.GetFor(mod.DirectoryPath);
#pragma warning disable CS0612 // deprecated code
ContentHelper contentHelper = new(contentCore, mod.DirectoryPath, mod, monitor, this.Reflection);
#pragma warning restore CS0612

View File

@ -16,6 +16,9 @@ namespace StardewModdingAPI.Utilities
/// <summary>A case-insensitive lookup of file paths within the <see cref="RootPath"/>. Each path is listed in both file path and asset name format, so it's usable in both contexts without needing to re-parse paths.</summary>
private readonly Lazy<Dictionary<string, string>> RelativePathCache;
/// <summary>The case-insensitive path caches by root path.</summary>
private static readonly Dictionary<string, CaseInsensitivePathCache> CachesByRootPath = new(StringComparer.OrdinalIgnoreCase);
/*********
** Public methods
@ -65,6 +68,18 @@ namespace StardewModdingAPI.Utilities
this.CacheRawPath(this.RelativePathCache.Value, relativePath);
}
/// <summary>Get a cached dictionary of relative paths within a root path, for case-insensitive file lookups.</summary>
/// <param name="rootPath">The root path to scan.</param>
public static CaseInsensitivePathCache GetFor(string rootPath)
{
rootPath = PathUtilities.NormalizePath(rootPath);
if (!CaseInsensitivePathCache.CachesByRootPath.TryGetValue(rootPath, out CaseInsensitivePathCache? cache))
CaseInsensitivePathCache.CachesByRootPath[rootPath] = cache = new CaseInsensitivePathCache(rootPath);
return cache;
}
/*********
** Private methods
@ -82,15 +97,13 @@ namespace StardewModdingAPI.Utilities
if (this.RelativePathCache.Value.TryGetValue(relativePath, out string? resolved))
return resolved;
// file exists but isn't cached for some reason
// cache it now so any later references to it are case-insensitive
// keep capitalization as-is
if (File.Exists(Path.Combine(this.RootPath, relativePath)))
{
// file exists but isn't cached for some reason
// cache it now so any later references to it are case-insensitive
this.CacheRawPath(this.RelativePathCache.Value, relativePath);
return relativePath;
}
// no such file, keep capitalization as-is
return relativePath;
}