From e9fee3f6fe18927192b1dd676cd420507af2e389 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 22 Nov 2016 00:36:48 -0500 Subject: preprocess all mod assemblies for compatibility with multi-assembly mods (#166) --- .../Framework/ModAssemblyLoader.cs | 82 ++++++++++++++++++---- 1 file changed, 69 insertions(+), 13 deletions(-) (limited to 'src/StardewModdingAPI/Framework') diff --git a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs index 2615e1f7..6c0f0cdf 100644 --- a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using System.Reflection; using System.Security.Cryptography; @@ -6,7 +7,7 @@ using Mono.Cecil; namespace StardewModdingAPI.Framework { - /// Loads mod assemblies. + /// Preprocesses and loads mod assemblies. internal class ModAssemblyLoader { /********* @@ -26,19 +27,17 @@ namespace StardewModdingAPI.Framework this.CacheDirPath = cacheDirPath; } - /// Read an assembly from the given path. + /// Preprocess an assembly and cache the modified version. /// The assembly file path. - public Assembly ProcessAssembly(string assemblyPath) + public void ProcessAssembly(string assemblyPath) { // read assembly data byte[] assemblyBytes = File.ReadAllBytes(assemblyPath); byte[] hash = MD5.Create().ComputeHash(assemblyBytes); - // get cache data - string key = Path.GetFileNameWithoutExtension(assemblyPath); - string cachePath = Path.Combine(this.CacheDirPath, $"{key}.dll"); - string cacheHashPath = Path.Combine(this.CacheDirPath, $"{key}-hash.txt"); - bool canUseCache = File.Exists(cachePath) && File.Exists(cacheHashPath) && hash.SequenceEqual(File.ReadAllBytes(cacheHashPath)); + // check cache + CachePaths cachePaths = this.GetCacheInfo(assemblyPath); + bool canUseCache = File.Exists(cachePaths.Assembly) && File.Exists(cachePaths.Hash) && hash.SequenceEqual(File.ReadAllBytes(cachePaths.Hash)); // process assembly if not cached if (!canUseCache) @@ -53,13 +52,70 @@ namespace StardewModdingAPI.Framework { definition.Write(outStream); byte[] outBytes = outStream.ToArray(); - File.WriteAllBytes(cachePath, outBytes); - File.WriteAllBytes(cacheHashPath, hash); + Directory.CreateDirectory(cachePaths.Directory); + File.WriteAllBytes(cachePaths.Assembly, outBytes); + File.WriteAllBytes(cachePaths.Hash, hash); } } + } + + /// Load a preprocessed assembly. + /// The assembly file path. + public Assembly LoadCachedAssembly(string assemblyPath) + { + CachePaths cachePaths = this.GetCacheInfo(assemblyPath); + if (!File.Exists(cachePaths.Assembly)) + throw new InvalidOperationException($"The assembly {assemblyPath} doesn't exist in the preprocessed cache."); + return Assembly.UnsafeLoadFrom(cachePaths.Assembly); + } - // load assembly - return Assembly.UnsafeLoadFrom(cachePath); + + /********* + ** Private methods + *********/ + /// Get the cache details for an assembly. + /// The assembly file path. + private CachePaths GetCacheInfo(string assemblyPath) + { + string key = Path.GetFileNameWithoutExtension(assemblyPath); + string dirPath = Path.Combine(this.CacheDirPath, new DirectoryInfo(Path.GetDirectoryName(assemblyPath)).Name); + string cacheAssemblyPath = Path.Combine(dirPath, $"{key}.dll"); + string cacheHashPath = Path.Combine(dirPath, $"{key}.hash"); + return new CachePaths(dirPath, cacheAssemblyPath, cacheHashPath); + } + + /********* + ** Private objects + *********/ + /// Contains the paths for an assembly's cached data. + private struct CachePaths + { + /********* + ** Accessors + *********/ + /// The directory path which contains the assembly. + public string Directory { get; } + + /// The file path of the assembly file. + public string Assembly { get; } + + /// The file path containing the MD5 hash for the assembly. + public string Hash { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The directory path which contains the assembly. + /// The file path of the assembly file. + /// The file path containing the MD5 hash for the assembly. + public CachePaths(string directory, string assembly, string hash) + { + this.Directory = directory; + this.Assembly = assembly; + this.Hash = hash; + } } } } -- cgit