diff options
author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2016-12-05 23:51:09 -0500 |
---|---|---|
committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2016-12-05 23:51:09 -0500 |
commit | 315943614573f0e1973bafc761c27207b8ea2b45 (patch) | |
tree | 80678aded464bc3b6b6414d688b180986886aa83 /src/StardewModdingAPI/Program.cs | |
parent | 31301988e97a9460ea2cb4898eb263a4e6c297d2 (diff) | |
download | SMAPI-315943614573f0e1973bafc761c27207b8ea2b45.tar.gz SMAPI-315943614573f0e1973bafc761c27207b8ea2b45.tar.bz2 SMAPI-315943614573f0e1973bafc761c27207b8ea2b45.zip |
reimplement assembly caching (#187)
This commit ensures DLLs are copied to the cache directory only if they changed, to avoid breaking debugging support unless necessary. To support this change, the assembly hash file has been replaced with a more detailed JSON structure, which is used to determine whether the cache is up-to-date and whether to use the cached or original assembly. Some mods contain multiple DLLs, which must be kept together to prevent assembly resolution issues; to simplify that (and avoid orphaned cache entries), each mod now has its own separate cache.
Diffstat (limited to 'src/StardewModdingAPI/Program.cs')
-rw-r--r-- | src/StardewModdingAPI/Program.cs | 34 |
1 files changed, 25 insertions, 9 deletions
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index e648ed64..a46f7a3e 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; @@ -12,6 +13,7 @@ using Newtonsoft.Json; using StardewModdingAPI.AssemblyRewriters; using StardewModdingAPI.Events; using StardewModdingAPI.Framework; +using StardewModdingAPI.Framework.AssemblyRewriting; using StardewModdingAPI.Inheritance; using StardewValley; using Monitor = StardewModdingAPI.Framework.Monitor; @@ -38,8 +40,8 @@ namespace StardewModdingAPI /// <summary>The full path to the folder containing mods.</summary> private static readonly string ModPath = Path.Combine(Constants.ExecutionPath, "Mods"); - /// <summary>The full path to the folder containing cached SMAPI data.</summary> - private static readonly string CachePath = Path.Combine(Program.ModPath, ".cache"); + /// <summary>The name of the folder containing a mod's cached assembly data.</summary> + private static readonly string CacheDirName = ".cache"; /// <summary>The log file to which to write messages.</summary> private static readonly LogFileManager LogFile = new LogFileManager(Constants.LogPath); @@ -134,7 +136,6 @@ namespace StardewModdingAPI Program.Monitor.Log("Loading SMAPI..."); Console.Title = Constants.ConsoleTitle; Program.VerifyPath(Program.ModPath); - Program.VerifyPath(Program.CachePath); Program.VerifyPath(Constants.LogDir); if (!File.Exists(Program.GameExecutablePath)) { @@ -304,7 +305,7 @@ namespace StardewModdingAPI Program.Monitor.Log("Loading mods..."); // get assembly loader - ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath, Program.TargetPlatform, Program.Monitor); + ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CacheDirName, Program.TargetPlatform, Program.Monitor); AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => modAssemblyLoader.ResolveAssembly(e.Name); // load mods @@ -401,14 +402,15 @@ namespace StardewModdingAPI } } - // preprocess mod assemblies + // preprocess mod assemblies for compatibility + var processedAssemblies = new List<RewriteResult>(); { bool succeeded = true; foreach (string assemblyPath in Directory.GetFiles(directory, "*.dll")) { try { - modAssemblyLoader.ProcessAssembly(assemblyPath); + processedAssemblies.Add(modAssemblyLoader.ProcessAssemblyUnlessCached(assemblyPath)); } catch (Exception ex) { @@ -420,13 +422,27 @@ namespace StardewModdingAPI if (!succeeded) continue; } + bool forceUseCachedAssembly = processedAssemblies.Any(p => p.UseCachedAssembly); // make sure DLLs are kept together for dependency resolution + if (processedAssemblies.Any(p => p.IsNewerThanCache)) + modAssemblyLoader.WriteCache(processedAssemblies, forceUseCachedAssembly); - // load assembly + // get entry assembly path + string mainAssemblyPath; + { + RewriteResult mainProcessedAssembly = processedAssemblies.FirstOrDefault(p => p.OriginalAssemblyPath == Path.Combine(directory, manifest.EntryDll)); + if (mainProcessedAssembly == null) + { + Program.Monitor.Log($"{errorPrefix}: the specified mod DLL does not exist.", LogLevel.Error); + continue; + } + mainAssemblyPath = forceUseCachedAssembly ? mainProcessedAssembly.CachePaths.Assembly : mainProcessedAssembly.OriginalAssemblyPath; + } + + // load entry assembly Assembly modAssembly; try { - string assemblyPath = Path.Combine(directory, manifest.EntryDll); - modAssembly = modAssemblyLoader.LoadCachedAssembly(assemblyPath); + modAssembly = Assembly.UnsafeLoadFrom(mainAssemblyPath); // unsafe load allows downloaded DLLs if (modAssembly.DefinedTypes.Count(x => x.BaseType == typeof(Mod)) == 0) { Program.Monitor.Log($"{errorPrefix}: the mod DLL does not contain an implementation of the 'Mod' class.", LogLevel.Error); |