From 517a9d82fc1234b6c6ae6f1e45ef7c0f160ee6c5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 21 Nov 2016 19:25:53 -0500 Subject: preprocess mods through Mono.Cecil to allow rewriting later (#166) --- src/StardewModdingAPI/Program.cs | 77 +++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 29 deletions(-) (limited to 'src/StardewModdingAPI/Program.cs') diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index d31a1d39..12b6cad4 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -33,6 +33,9 @@ namespace StardewModdingAPI /// The full path to the folder containing mods. private static readonly string ModPath = Path.Combine(Constants.ExecutionPath, "Mods"); + /// The full path to the folder containing cached SMAPI data. + private static readonly string CachePath = Path.Combine(Program.ModPath, ".cache"); + /// The log file to which to write messages. private static readonly LogFileManager LogFile = new LogFileManager(Constants.LogPath); @@ -126,6 +129,7 @@ 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)) { @@ -293,6 +297,8 @@ namespace StardewModdingAPI private static void LoadMods() { Program.Monitor.Log("Loading mods..."); + + ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath); foreach (string directory in Directory.GetDirectories(Program.ModPath)) { foreach (string manifestPath in Directory.GetFiles(directory, "manifest.json")) @@ -382,9 +388,11 @@ namespace StardewModdingAPI } } - // load DLL & hook up mod + // load assembly + Assembly modAssembly; try { + // get assembly path string assemblyPath = Path.Combine(directory, manifest.EntryDll); if (!File.Exists(assemblyPath)) { @@ -392,36 +400,47 @@ namespace StardewModdingAPI continue; } - Assembly modAssembly = Assembly.UnsafeLoadFrom(assemblyPath); - if (modAssembly.DefinedTypes.Count(x => x.BaseType == typeof(Mod)) > 0) + // read assembly + modAssembly = modAssemblyLoader.ProcessAssembly(assemblyPath); + if (modAssembly.DefinedTypes.Count(x => x.BaseType == typeof(Mod)) == 0) { - TypeInfo modEntryType = modAssembly.DefinedTypes.First(x => x.BaseType == typeof(Mod)); - Mod modEntry = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); - if (modEntry != null) - { - // track mod - Program.ModRegistry.Add(manifest, modAssembly); - - // hook up mod - modEntry.Manifest = manifest; - modEntry.Helper = helper; - modEntry.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; - modEntry.PathOnDisk = directory; - Program.Monitor.Log($"Loaded mod: {modEntry.Manifest.Name} by {modEntry.Manifest.Author}, v{modEntry.Manifest.Version} | {modEntry.Manifest.Description}", LogLevel.Info); - Program.ModsLoaded += 1; - modEntry.Entry(); // deprecated since 1.0 - modEntry.Entry((ModHelper)modEntry.Helper); // deprecated since 1.1 - modEntry.Entry(modEntry.Helper); // deprecated since 1.1 - - // raise deprecation warning for old Entry() method - if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); - if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); - } - } - else Program.Monitor.Log($"{errorPrefix}: the mod DLL does not contain an implementation of the 'Mod' class.", LogLevel.Error); + continue; + } + } + catch (Exception ex) + { + Program.Monitor.Log($"{errorPrefix}: an error occurred while optimising the target DLL.\n{ex}", LogLevel.Error); + continue; + } + + // hook up mod + try + { + TypeInfo modEntryType = modAssembly.DefinedTypes.First(x => x.BaseType == typeof(Mod)); + Mod modEntry = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); + if (modEntry != null) + { + // track mod + Program.ModRegistry.Add(manifest, modAssembly); + + // hook up mod + modEntry.Manifest = manifest; + modEntry.Helper = helper; + modEntry.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; + modEntry.PathOnDisk = directory; + Program.Monitor.Log($"Loaded mod: {modEntry.Manifest.Name} by {modEntry.Manifest.Author}, v{modEntry.Manifest.Version} | {modEntry.Manifest.Description}", LogLevel.Info); + Program.ModsLoaded += 1; + modEntry.Entry(); // deprecated since 1.0 + modEntry.Entry((ModHelper)modEntry.Helper); // deprecated since 1.1 + modEntry.Entry(modEntry.Helper); // deprecated since 1.1 + + // raise deprecation warning for old Entry() method + if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) + Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); + if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) + Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); + } } catch (Exception ex) { -- cgit From 08d5ee293ffc001dff3e866bd45954ef306e81ac Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 22 Nov 2016 00:03:14 -0500 Subject: simplify manifest.json path check --- src/StardewModdingAPI/Program.cs | 223 +++++++++++++++++++-------------------- 1 file changed, 111 insertions(+), 112 deletions(-) (limited to 'src/StardewModdingAPI/Program.cs') diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 12b6cad4..255ad365 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -301,152 +301,151 @@ namespace StardewModdingAPI ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath); foreach (string directory in Directory.GetDirectories(Program.ModPath)) { - foreach (string manifestPath in Directory.GetFiles(directory, "manifest.json")) + // check for cancellation + if (Program.CancellationTokenSource.IsCancellationRequested) { - // check for cancellation - if (Program.CancellationTokenSource.IsCancellationRequested) - { - Program.Monitor.Log("Shutdown requested; interrupting mod loading.", LogLevel.Error); - return; - } + Program.Monitor.Log("Shutdown requested; interrupting mod loading.", LogLevel.Error); + return; + } - IModHelper helper = new ModHelper(directory); - string errorPrefix = $"Couldn't load mod for manifest '{manifestPath}'"; + // get helper + IModHelper helper = new ModHelper(directory); - // read manifest - Manifest manifest; - try + // get manifest path + string manifestPath = Path.Combine(directory, "manifest.json"); + string errorPrefix = $"Couldn't load mod for manifest '{manifestPath}'"; + Manifest manifest; + try + { + // read manifest text + string json = File.ReadAllText(manifestPath); + if (string.IsNullOrEmpty(json)) { - // read manifest text - string json = File.ReadAllText(manifestPath); - if (string.IsNullOrEmpty(json)) - { - Program.Monitor.Log($"{errorPrefix}: manifest is empty.", LogLevel.Error); - continue; - } - - // deserialise manifest - manifest = helper.ReadJsonFile("manifest.json"); - if (manifest == null) - { - Program.Monitor.Log($"{errorPrefix}: the manifest file does not exist.", LogLevel.Error); - continue; - } - if (string.IsNullOrEmpty(manifest.EntryDll)) - { - Program.Monitor.Log($"{errorPrefix}: manifest doesn't specify an entry DLL.", LogLevel.Error); - continue; - } + Program.Monitor.Log($"{errorPrefix}: manifest is empty.", LogLevel.Error); + continue; + } - // log deprecated fields - if (manifest.UsedAuthourField) - Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Manifest)}.{nameof(Manifest.Authour)}", "1.0", DeprecationLevel.Notice); + // deserialise manifest + manifest = helper.ReadJsonFile("manifest.json"); + if (manifest == null) + { + Program.Monitor.Log($"{errorPrefix}: the manifest file does not exist.", LogLevel.Error); + continue; } - catch (Exception ex) + if (string.IsNullOrEmpty(manifest.EntryDll)) { - Program.Monitor.Log($"{errorPrefix}: manifest parsing failed.\n{ex.GetLogSummary()}", LogLevel.Error); + Program.Monitor.Log($"{errorPrefix}: manifest doesn't specify an entry DLL.", LogLevel.Error); continue; } - // validate version - if (!string.IsNullOrWhiteSpace(manifest.MinimumApiVersion)) + // log deprecated fields + if (manifest.UsedAuthourField) + Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Manifest)}.{nameof(Manifest.Authour)}", "1.0", DeprecationLevel.Notice); + } + catch (Exception ex) + { + Program.Monitor.Log($"{errorPrefix}: manifest parsing failed.\n{ex.GetLogSummary()}", LogLevel.Error); + continue; + } + + // validate version + if (!string.IsNullOrWhiteSpace(manifest.MinimumApiVersion)) + { + try { - try + Version minVersion = new Version(manifest.MinimumApiVersion); + if (minVersion.IsNewerThan(Constants.Version)) { - Version minVersion = new Version(manifest.MinimumApiVersion); - if (minVersion.IsNewerThan(Constants.Version)) - { - Program.Monitor.Log($"{errorPrefix}: this mod requires SMAPI {minVersion} or later. Please update SMAPI to the latest version to use this mod.", LogLevel.Error); - continue; - } - } - catch (FormatException ex) when (ex.Message.Contains("not a semantic version")) - { - Program.Monitor.Log($"{errorPrefix}: the mod specified an invalid minimum SMAPI version '{manifest.MinimumApiVersion}'. This should be a semantic version number like {Constants.Version}.", LogLevel.Error); + Program.Monitor.Log($"{errorPrefix}: this mod requires SMAPI {minVersion} or later. Please update SMAPI to the latest version to use this mod.", LogLevel.Error); continue; } } - - // create per-save directory - if (manifest.PerSaveConfigs) + catch (FormatException ex) when (ex.Message.Contains("not a semantic version")) { - Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Manifest)}.{nameof(Manifest.PerSaveConfigs)}", "1.0", DeprecationLevel.Notice); - try - { - string psDir = Path.Combine(directory, "psconfigs"); - Directory.CreateDirectory(psDir); - if (!Directory.Exists(psDir)) - { - Program.Monitor.Log($"{errorPrefix}: couldn't create the per-save configuration directory ('psconfigs') requested by this mod. The failure reason is unknown.", LogLevel.Error); - continue; - } - } - catch (Exception ex) - { - Program.Monitor.Log($"{errorPrefix}: couldm't create the per-save configuration directory ('psconfigs') requested by this mod.\n{ex.GetLogSummary()}", LogLevel.Error); - continue; - } + Program.Monitor.Log($"{errorPrefix}: the mod specified an invalid minimum SMAPI version '{manifest.MinimumApiVersion}'. This should be a semantic version number like {Constants.Version}.", LogLevel.Error); + continue; } + } - // load assembly - Assembly modAssembly; + // create per-save directory + if (manifest.PerSaveConfigs) + { + Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Manifest)}.{nameof(Manifest.PerSaveConfigs)}", "1.0", DeprecationLevel.Notice); try { - // get assembly path - string assemblyPath = Path.Combine(directory, manifest.EntryDll); - if (!File.Exists(assemblyPath)) + string psDir = Path.Combine(directory, "psconfigs"); + Directory.CreateDirectory(psDir); + if (!Directory.Exists(psDir)) { - Program.Monitor.Log($"{errorPrefix}: target DLL '{assemblyPath}' does not exist.", LogLevel.Error); - continue; - } - - // read assembly - modAssembly = modAssemblyLoader.ProcessAssembly(assemblyPath); - 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); + Program.Monitor.Log($"{errorPrefix}: couldn't create the per-save configuration directory ('psconfigs') requested by this mod. The failure reason is unknown.", LogLevel.Error); continue; } } catch (Exception ex) { - Program.Monitor.Log($"{errorPrefix}: an error occurred while optimising the target DLL.\n{ex}", LogLevel.Error); + Program.Monitor.Log($"{errorPrefix}: couldm't create the per-save configuration directory ('psconfigs') requested by this mod.\n{ex.GetLogSummary()}", LogLevel.Error); continue; } + } - // hook up mod - try + // load assembly + Assembly modAssembly; + try + { + // get assembly path + string assemblyPath = Path.Combine(directory, manifest.EntryDll); + if (!File.Exists(assemblyPath)) { - TypeInfo modEntryType = modAssembly.DefinedTypes.First(x => x.BaseType == typeof(Mod)); - Mod modEntry = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); - if (modEntry != null) - { - // track mod - Program.ModRegistry.Add(manifest, modAssembly); - - // hook up mod - modEntry.Manifest = manifest; - modEntry.Helper = helper; - modEntry.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; - modEntry.PathOnDisk = directory; - Program.Monitor.Log($"Loaded mod: {modEntry.Manifest.Name} by {modEntry.Manifest.Author}, v{modEntry.Manifest.Version} | {modEntry.Manifest.Description}", LogLevel.Info); - Program.ModsLoaded += 1; - modEntry.Entry(); // deprecated since 1.0 - modEntry.Entry((ModHelper)modEntry.Helper); // deprecated since 1.1 - modEntry.Entry(modEntry.Helper); // deprecated since 1.1 - - // raise deprecation warning for old Entry() method - if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); - if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); - } + Program.Monitor.Log($"{errorPrefix}: target DLL '{assemblyPath}' does not exist.", LogLevel.Error); + continue; } - catch (Exception ex) + + // read assembly + modAssembly = modAssemblyLoader.ProcessAssembly(assemblyPath); + 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); + continue; + } + } + catch (Exception ex) + { + Program.Monitor.Log($"{errorPrefix}: an error occurred while optimising the target DLL.\n{ex}", LogLevel.Error); + continue; + } + + // hook up mod + try + { + TypeInfo modEntryType = modAssembly.DefinedTypes.First(x => x.BaseType == typeof(Mod)); + Mod modEntry = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); + if (modEntry != null) { - Program.Monitor.Log($"{errorPrefix}: an error occurred while loading the target DLL.\n{ex.GetLogSummary()}", LogLevel.Error); + // track mod + Program.ModRegistry.Add(manifest, modAssembly); + + // hook up mod + modEntry.Manifest = manifest; + modEntry.Helper = helper; + modEntry.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; + modEntry.PathOnDisk = directory; + Program.Monitor.Log($"Loaded mod: {modEntry.Manifest.Name} by {modEntry.Manifest.Author}, v{modEntry.Manifest.Version} | {modEntry.Manifest.Description}", LogLevel.Info); + Program.ModsLoaded += 1; + modEntry.Entry(); // deprecated since 1.0 + modEntry.Entry((ModHelper)modEntry.Helper); // deprecated since 1.1 + modEntry.Entry(modEntry.Helper); // deprecated since 1.1 + + // raise deprecation warning for old Entry() method + if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) + Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); + if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) + Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); } } + catch (Exception ex) + { + Program.Monitor.Log($"{errorPrefix}: an error occurred while loading the target DLL.\n{ex.GetLogSummary()}", LogLevel.Error); + } } // print result -- cgit 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 ++++++++++++++++++---- src/StardewModdingAPI/Program.cs | 34 ++++++--- 2 files changed, 94 insertions(+), 22 deletions(-) (limited to 'src/StardewModdingAPI/Program.cs') 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; + } } } } diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 255ad365..f8920896 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -301,6 +301,10 @@ namespace StardewModdingAPI ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath); foreach (string directory in Directory.GetDirectories(Program.ModPath)) { + // ignore internal directory + if (new DirectoryInfo(directory).Name == ".cache") + continue; + // check for cancellation if (Program.CancellationTokenSource.IsCancellationRequested) { @@ -388,20 +392,32 @@ namespace StardewModdingAPI } } + // preprocess mod assemblies + { + bool succeeded = true; + foreach (string assemblyPath in Directory.GetFiles(directory, "*.dll")) + { + try + { + modAssemblyLoader.ProcessAssembly(assemblyPath); + } + catch (Exception ex) + { + Program.Monitor.Log($"{errorPrefix}: an error occurred while preprocessing '{assemblyPath}'.\n{ex}", LogLevel.Error); + succeeded = false; + break; + } + } + if (!succeeded) + continue; + } + // load assembly Assembly modAssembly; try { - // get assembly path string assemblyPath = Path.Combine(directory, manifest.EntryDll); - if (!File.Exists(assemblyPath)) - { - Program.Monitor.Log($"{errorPrefix}: target DLL '{assemblyPath}' does not exist.", LogLevel.Error); - continue; - } - - // read assembly - modAssembly = modAssemblyLoader.ProcessAssembly(assemblyPath); + modAssembly = modAssemblyLoader.LoadCachedAssembly(assemblyPath); 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); -- cgit From 7bea3c2ba00789a38ae71035548c2c6b5c298d5b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 26 Nov 2016 16:00:02 -0500 Subject: add log entry when preprocessing an assembly (#166) --- src/StardewModdingAPI/Framework/ModAssemblyLoader.cs | 9 ++++++++- src/StardewModdingAPI/Program.cs | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src/StardewModdingAPI/Program.cs') diff --git a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs index 6c0f0cdf..f367c6a0 100644 --- a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs @@ -16,15 +16,20 @@ namespace StardewModdingAPI.Framework /// The directory in which to cache data. private readonly string CacheDirPath; + /// Encapsulates monitoring and logging for a given module. + private readonly IMonitor Monitor; + /********* ** Public methods *********/ /// Construct an instance. /// The cache directory. - public ModAssemblyLoader(string cacheDirPath) + /// Encapsulates monitoring and logging for a given module. + public ModAssemblyLoader(string cacheDirPath, IMonitor monitor) { this.CacheDirPath = cacheDirPath; + this.Monitor = monitor; } /// Preprocess an assembly and cache the modified version. @@ -42,6 +47,8 @@ namespace StardewModdingAPI.Framework // process assembly if not cached if (!canUseCache) { + this.Monitor.Log($"Preprocessing new assembly {assemblyPath}..."); + // read assembly definition AssemblyDefinition definition; using (Stream readStream = new MemoryStream(assemblyBytes)) diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index f8920896..e364ef03 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -298,7 +298,7 @@ namespace StardewModdingAPI { Program.Monitor.Log("Loading mods..."); - ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath); + ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath, Program.Monitor); foreach (string directory in Directory.GetDirectories(Program.ModPath)) { // ignore internal directory @@ -403,7 +403,7 @@ namespace StardewModdingAPI } catch (Exception ex) { - Program.Monitor.Log($"{errorPrefix}: an error occurred while preprocessing '{assemblyPath}'.\n{ex}", LogLevel.Error); + Program.Monitor.Log($"{errorPrefix}: an error occurred while preprocessing '{Path.GetFileName(assemblyPath)}'.\n{ex.GetLogSummary()}", LogLevel.Error); succeeded = false; break; } @@ -426,7 +426,7 @@ namespace StardewModdingAPI } catch (Exception ex) { - Program.Monitor.Log($"{errorPrefix}: an error occurred while optimising the target DLL.\n{ex}", LogLevel.Error); + Program.Monitor.Log($"{errorPrefix}: an error occurred while optimising the target DLL.\n{ex.GetLogSummary()}", LogLevel.Error); continue; } -- cgit From 1de8dc1b0f58991f9d15fa343e849bd6a2023ecc Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 26 Nov 2016 16:07:21 -0500 Subject: pass target platform to assembly rewriter for later use (#166) --- src/StardewModdingAPI/Framework/ModAssemblyLoader.cs | 3 ++- src/StardewModdingAPI/Framework/Platform.cs | 12 ++++++++++++ src/StardewModdingAPI/Program.cs | 12 ++++++++---- src/StardewModdingAPI/StardewModdingAPI.csproj | 1 + 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 src/StardewModdingAPI/Framework/Platform.cs (limited to 'src/StardewModdingAPI/Program.cs') diff --git a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs index f367c6a0..e5a73a8b 100644 --- a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs @@ -25,8 +25,9 @@ namespace StardewModdingAPI.Framework *********/ /// Construct an instance. /// The cache directory. + /// The current game platform. /// Encapsulates monitoring and logging for a given module. - public ModAssemblyLoader(string cacheDirPath, IMonitor monitor) + public ModAssemblyLoader(string cacheDirPath, Platform targetPlatform, IMonitor monitor) { this.CacheDirPath = cacheDirPath; this.Monitor = monitor; diff --git a/src/StardewModdingAPI/Framework/Platform.cs b/src/StardewModdingAPI/Framework/Platform.cs new file mode 100644 index 00000000..cab81e06 --- /dev/null +++ b/src/StardewModdingAPI/Framework/Platform.cs @@ -0,0 +1,12 @@ +namespace StardewModdingAPI.Framework +{ + /// The game's platform version. + internal enum Platform + { + /// The Linux/Mac version of the game. + Mono, + + /// The Windows version of the game. + Windows + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index e364ef03..eba89981 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -23,13 +23,17 @@ namespace StardewModdingAPI /********* ** Properties *********/ - /// The full path to the Stardew Valley executable. + /// The target game platform. + private static readonly Platform TargetPlatform = #if SMAPI_FOR_WINDOWS - private static readonly string GameExecutablePath = Path.Combine(Constants.ExecutionPath, "Stardew Valley.exe"); + Platform.Windows; #else - private static readonly string GameExecutablePath = Path.Combine(Constants.ExecutionPath, "StardewValley.exe"); + Platform.Mono; #endif + /// The full path to the Stardew Valley executable. + private static readonly string GameExecutablePath = Path.Combine(Constants.ExecutionPath, Program.TargetPlatform == Platform.Windows ? "Stardew Valley.exe" : "StardewValley.exe"); + /// The full path to the folder containing mods. private static readonly string ModPath = Path.Combine(Constants.ExecutionPath, "Mods"); @@ -298,7 +302,7 @@ namespace StardewModdingAPI { Program.Monitor.Log("Loading mods..."); - ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath, Program.Monitor); + ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath, Program.TargetPlatform, Program.Monitor); foreach (string directory in Directory.GetDirectories(Program.ModPath)) { // ignore internal directory diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index f3dbc45a..01be9a68 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -217,6 +217,7 @@ + -- cgit From f7b8879011873fa8f7a3d5dd7db27254bfc90469 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 27 Nov 2016 15:56:47 -0500 Subject: supplement assembly resolution for Mono (#166) --- .../AssemblyRewriting/AssemblyTypeRewriter.cs | 21 +++++-------- .../AssemblyRewriting/PlatformAssemblyMap.cs | 35 ++++++++++++++++++++++ .../Framework/ModAssemblyLoader.cs | 20 ++++++++++--- src/StardewModdingAPI/Program.cs | 4 ++- src/StardewModdingAPI/StardewModdingAPI.csproj | 1 + 5 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 src/StardewModdingAPI/Framework/AssemblyRewriting/PlatformAssemblyMap.cs (limited to 'src/StardewModdingAPI/Program.cs') diff --git a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs index 7081df15..66c36c03 100644 --- a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs +++ b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs @@ -11,11 +11,8 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting /********* ** Properties *********/ - /// The assemblies to target. Equivalent types will be rewritten to use these assemblies. - private readonly Assembly[] TargetAssemblies; - - /// >The short assembly names to remove as assembly reference, and replace with the . - private readonly string[] RemoveAssemblyNames; + /// Metadata for mapping assemblies to the current . + private readonly PlatformAssemblyMap AssemblyMap; /// A type => assembly lookup for types which should be rewritten. private readonly IDictionary TypeAssemblies; @@ -31,22 +28,20 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting ** Public methods *********/ /// Construct an instance. - /// The assembly filenames to target. Equivalent types will be rewritten to use these assemblies. - /// The short assembly names to remove as assembly reference, and replace with the . + /// Metadata for mapping assemblies to the current . /// Encapsulates monitoring and logging. - public AssemblyTypeRewriter(Assembly[] targetAssemblies, string[] removeAssemblyNames, IMonitor monitor) + public AssemblyTypeRewriter(PlatformAssemblyMap assemblyMap, IMonitor monitor) { // save config - this.TargetAssemblies = targetAssemblies; - this.RemoveAssemblyNames = removeAssemblyNames; + this.AssemblyMap = assemblyMap; this.Monitor = monitor; // cache assembly metadata - this.AssemblyNameReferences = targetAssemblies.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName)); + this.AssemblyNameReferences = assemblyMap.Targets.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName)); // collect type => assembly lookup this.TypeAssemblies = new Dictionary(); - foreach (Assembly assembly in targetAssemblies) + foreach (Assembly assembly in assemblyMap.Targets) { foreach (Module assemblyModule in assembly.Modules) { @@ -73,7 +68,7 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting // remove old assembly references for (int i = 0; i < module.AssemblyReferences.Count; i++) { - bool shouldRemove = this.RemoveAssemblyNames.Any(name => module.AssemblyReferences[i].Name == name); + bool shouldRemove = this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name); if (shouldRemove) { this.Monitor.Log($"removing reference to {module.AssemblyReferences[i]}", LogLevel.Trace); diff --git a/src/StardewModdingAPI/Framework/AssemblyRewriting/PlatformAssemblyMap.cs b/src/StardewModdingAPI/Framework/AssemblyRewriting/PlatformAssemblyMap.cs new file mode 100644 index 00000000..3e6cec8a --- /dev/null +++ b/src/StardewModdingAPI/Framework/AssemblyRewriting/PlatformAssemblyMap.cs @@ -0,0 +1,35 @@ +using System.Reflection; + +namespace StardewModdingAPI.Framework.AssemblyRewriting +{ + /// Metadata for mapping assemblies to the current . + internal class PlatformAssemblyMap + { + /********* + ** Accessors + *********/ + /// The target game platform. + public readonly Platform TargetPlatform; + + /// The short assembly names to remove as assembly reference, and replace with the . These should be short names (like "Stardew Valley"). + public readonly string[] RemoveNames; + + /// The assembly filenames to target. Equivalent types should be rewritten to use these assemblies. + public readonly Assembly[] Targets; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The target game platform. + /// The assembly short names to remove (like Stardew Valley). + /// The assemblies to target. + public PlatformAssemblyMap(Platform targetPlatform, string[] removeAssemblyNames, Assembly[] targetAssemblies) + { + this.TargetPlatform = targetPlatform; + this.RemoveNames = removeAssemblyNames; + this.Targets = targetAssemblies; + } + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs index 7de48649..3d08ec64 100644 --- a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs @@ -17,6 +17,9 @@ namespace StardewModdingAPI.Framework /// The directory in which to cache data. private readonly string CacheDirPath; + /// Metadata for mapping assemblies to the current . + private readonly PlatformAssemblyMap AssemblyMap; + /// Rewrites assembly types to match the current platform. private readonly AssemblyTypeRewriter AssemblyTypeRewriter; @@ -35,7 +38,8 @@ namespace StardewModdingAPI.Framework { this.CacheDirPath = cacheDirPath; this.Monitor = monitor; - this.AssemblyTypeRewriter = this.GetAssemblyRewriter(targetPlatform); + this.AssemblyMap = this.GetAssemblyMap(targetPlatform); + this.AssemblyTypeRewriter = new AssemblyTypeRewriter(this.AssemblyMap, monitor); } /// Preprocess an assembly and cache the modified version. @@ -97,6 +101,14 @@ namespace StardewModdingAPI.Framework return Assembly.UnsafeLoadFrom(cachePaths.Assembly); // unsafe load allows DLLs downloaded from the Internet without the user needing to 'unblock' them } + /// Resolve an assembly from its name. + /// The assembly name. + public Assembly ResolveAssembly(string name) + { + string shortName = name.Split(new[] { ',' }, 2).First(); + return this.AssemblyMap.Targets.FirstOrDefault(p => p.GetName().Name == shortName); + } + /********* ** Private methods @@ -112,9 +124,9 @@ namespace StardewModdingAPI.Framework return new CachePaths(dirPath, cacheAssemblyPath, cacheHashPath); } - /// Get an assembly rewriter for the target platform. + /// Get metadata for mapping assemblies to the current platform. /// The target game platform. - private AssemblyTypeRewriter GetAssemblyRewriter(Platform targetPlatform) + private PlatformAssemblyMap GetAssemblyMap(Platform targetPlatform) { // get assembly changes needed for platform string[] removeAssemblyReferences; @@ -155,7 +167,7 @@ namespace StardewModdingAPI.Framework throw new InvalidOperationException($"Unknown target platform '{targetPlatform}'."); } - return new AssemblyTypeRewriter(targetAssemblies, removeAssemblyReferences, this.Monitor); + return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences, targetAssemblies); } } } diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index eba89981..bed4cafc 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -303,6 +303,8 @@ namespace StardewModdingAPI Program.Monitor.Log("Loading mods..."); ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CachePath, Program.TargetPlatform, Program.Monitor); + AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => modAssemblyLoader.ResolveAssembly(e.Name); // supplement Mono's assembly resolution which doesn't handle assembly rewrites very well + foreach (string directory in Directory.GetDirectories(Program.ModPath)) { // ignore internal directory @@ -391,7 +393,7 @@ namespace StardewModdingAPI } catch (Exception ex) { - Program.Monitor.Log($"{errorPrefix}: couldm't create the per-save configuration directory ('psconfigs') requested by this mod.\n{ex.GetLogSummary()}", LogLevel.Error); + Program.Monitor.Log($"{errorPrefix}: couldn't create the per-save configuration directory ('psconfigs') requested by this mod.\n{ex.GetLogSummary()}", LogLevel.Error); continue; } } diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 2abcdc23..fd02f802 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -215,6 +215,7 @@ + -- cgit From 5470e95bf59e5e3bae249ead6909163390fb2af3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 29 Nov 2016 14:02:59 -0500 Subject: add separate project to support upcoming IL rewriting (#166) --- .../Platform.cs | 12 +++ .../PlatformAssemblyMap.cs | 35 +++++++++ .../Properties/AssemblyInfo.cs | 7 ++ .../StardewModdingAPI.AssemblyRewriters.csproj | 90 ++++++++++++++++++++++ .../packages.config | 4 + .../StardewModdingAPI.Installer.csproj | 1 + src/StardewModdingAPI.sln | 14 ++++ src/StardewModdingAPI/Constants.cs | 3 +- .../AssemblyRewriting/AssemblyTypeRewriter.cs | 1 + .../AssemblyRewriting/PlatformAssemblyMap.cs | 35 --------- .../Framework/ModAssemblyLoader.cs | 1 + src/StardewModdingAPI/Framework/Platform.cs | 12 --- src/StardewModdingAPI/Program.cs | 1 + src/StardewModdingAPI/StardewModdingAPI.csproj | 9 ++- 14 files changed, 174 insertions(+), 51 deletions(-) create mode 100644 src/StardewModdingAPI.AssemblyRewriters/Platform.cs create mode 100644 src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs create mode 100644 src/StardewModdingAPI.AssemblyRewriters/Properties/AssemblyInfo.cs create mode 100644 src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj create mode 100644 src/StardewModdingAPI.AssemblyRewriters/packages.config delete mode 100644 src/StardewModdingAPI/Framework/AssemblyRewriting/PlatformAssemblyMap.cs delete mode 100644 src/StardewModdingAPI/Framework/Platform.cs (limited to 'src/StardewModdingAPI/Program.cs') diff --git a/src/StardewModdingAPI.AssemblyRewriters/Platform.cs b/src/StardewModdingAPI.AssemblyRewriters/Platform.cs new file mode 100644 index 00000000..8888a9a8 --- /dev/null +++ b/src/StardewModdingAPI.AssemblyRewriters/Platform.cs @@ -0,0 +1,12 @@ +namespace StardewModdingAPI.AssemblyRewriters +{ + /// The game's platform version. + public enum Platform + { + /// The Linux/Mac version of the game. + Mono, + + /// The Windows version of the game. + Windows + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs b/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs new file mode 100644 index 00000000..c0855719 --- /dev/null +++ b/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs @@ -0,0 +1,35 @@ +using System.Reflection; + +namespace StardewModdingAPI.AssemblyRewriters +{ + /// Metadata for mapping assemblies to the current . + public class PlatformAssemblyMap + { + /********* + ** Accessors + *********/ + /// The target game platform. + public readonly Platform TargetPlatform; + + /// The short assembly names to remove as assembly reference, and replace with the . These should be short names (like "Stardew Valley"). + public readonly string[] RemoveNames; + + /// The assembly filenames to target. Equivalent types should be rewritten to use these assemblies. + public readonly Assembly[] Targets; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The target game platform. + /// The assembly short names to remove (like Stardew Valley). + /// The assemblies to target. + public PlatformAssemblyMap(Platform targetPlatform, string[] removeAssemblyNames, Assembly[] targetAssemblies) + { + this.TargetPlatform = targetPlatform; + this.RemoveNames = removeAssemblyNames; + this.Targets = targetAssemblies; + } + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI.AssemblyRewriters/Properties/AssemblyInfo.cs b/src/StardewModdingAPI.AssemblyRewriters/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..25fbfef9 --- /dev/null +++ b/src/StardewModdingAPI.AssemblyRewriters/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("StardewModdingAPI.AssemblyRewriters")] +[assembly: AssemblyDescription("Contains internal SMAPI code for converting mods between Linux/Mac and Windows. This assembly is used by SMAPI internally and shouldn't be referenced directly by mods.")] +[assembly: AssemblyProduct("StardewModdingAPI.CrossplatformRewriters")] +[assembly: Guid("10db0676-9fc1-4771-a2c8-e2519f091e49")] diff --git a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj new file mode 100644 index 00000000..d87a48bc --- /dev/null +++ b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj @@ -0,0 +1,90 @@ + + + + + Debug + AnyCPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49} + Library + Properties + StardewModdingAPI.AssemblyRewriters + StardewModdingAPI.AssemblyRewriters + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x86\Debug\ + DEBUG;TRACE;SMAPI_FOR_WINDOWS + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE;SMAPI_FOR_WINDOWS + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll + True + + + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll + True + + + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll + True + + + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll + True + + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + + + \ No newline at end of file diff --git a/src/StardewModdingAPI.AssemblyRewriters/packages.config b/src/StardewModdingAPI.AssemblyRewriters/packages.config new file mode 100644 index 00000000..88fbc79d --- /dev/null +++ b/src/StardewModdingAPI.AssemblyRewriters/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj index 23e2d278..c19e5f55 100644 --- a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj +++ b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj @@ -70,6 +70,7 @@ + diff --git a/src/StardewModdingAPI.sln b/src/StardewModdingAPI.sln index 31bf5f2f..d97e4645 100644 --- a/src/StardewModdingAPI.sln +++ b/src/StardewModdingAPI.sln @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI.Installer {F1A573B0-F436-472C-AE29-0B91EA6B9F8F} = {F1A573B0-F436-472C-AE29-0B91EA6B9F8F} EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI.AssemblyRewriters", "StardewModdingAPI.AssemblyRewriters\StardewModdingAPI.AssemblyRewriters.csproj", "{10DB0676-9FC1-4771-A2C8-E2519F091E49}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +69,18 @@ Global {443DDF81-6AAF-420A-A610-3459F37E5575}.Release|Mixed Platforms.Build.0 = Release|Any CPU {443DDF81-6AAF-420A-A610-3459F37E5575}.Release|x86.ActiveCfg = Release|Any CPU {443DDF81-6AAF-420A-A610-3459F37E5575}.Release|x86.Build.0 = Release|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Debug|x86.ActiveCfg = Debug|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Debug|x86.Build.0 = Debug|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Release|Any CPU.Build.0 = Release|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Release|x86.ActiveCfg = Release|Any CPU + {10DB0676-9FC1-4771-A2C8-E2519F091E49}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index 66eb1336..b9074b6e 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -2,8 +2,7 @@ using System.IO; using System.Linq; using System.Reflection; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.AssemblyRewriting; +using StardewModdingAPI.AssemblyRewriters; using StardewValley; namespace StardewModdingAPI diff --git a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs index 66c36c03..43f6aa11 100644 --- a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs +++ b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Reflection; using Mono.Cecil; +using StardewModdingAPI.AssemblyRewriters; namespace StardewModdingAPI.Framework.AssemblyRewriting { diff --git a/src/StardewModdingAPI/Framework/AssemblyRewriting/PlatformAssemblyMap.cs b/src/StardewModdingAPI/Framework/AssemblyRewriting/PlatformAssemblyMap.cs deleted file mode 100644 index 3e6cec8a..00000000 --- a/src/StardewModdingAPI/Framework/AssemblyRewriting/PlatformAssemblyMap.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; - -namespace StardewModdingAPI.Framework.AssemblyRewriting -{ - /// Metadata for mapping assemblies to the current . - internal class PlatformAssemblyMap - { - /********* - ** Accessors - *********/ - /// The target game platform. - public readonly Platform TargetPlatform; - - /// The short assembly names to remove as assembly reference, and replace with the . These should be short names (like "Stardew Valley"). - public readonly string[] RemoveNames; - - /// The assembly filenames to target. Equivalent types should be rewritten to use these assemblies. - public readonly Assembly[] Targets; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The target game platform. - /// The assembly short names to remove (like Stardew Valley). - /// The assemblies to target. - public PlatformAssemblyMap(Platform targetPlatform, string[] removeAssemblyNames, Assembly[] targetAssemblies) - { - this.TargetPlatform = targetPlatform; - this.RemoveNames = removeAssemblyNames; - this.Targets = targetAssemblies; - } - } -} \ No newline at end of file diff --git a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs index b6d98bde..e095cde8 100644 --- a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using System.Security.Cryptography; using Mono.Cecil; +using StardewModdingAPI.AssemblyRewriters; using StardewModdingAPI.Framework.AssemblyRewriting; namespace StardewModdingAPI.Framework diff --git a/src/StardewModdingAPI/Framework/Platform.cs b/src/StardewModdingAPI/Framework/Platform.cs deleted file mode 100644 index cab81e06..00000000 --- a/src/StardewModdingAPI/Framework/Platform.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace StardewModdingAPI.Framework -{ - /// The game's platform version. - internal enum Platform - { - /// The Linux/Mac version of the game. - Mono, - - /// The Windows version of the game. - Windows - } -} \ No newline at end of file diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index bed4cafc..f0686039 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -9,6 +9,7 @@ using System.Windows.Forms; #endif using Microsoft.Xna.Framework.Graphics; using Newtonsoft.Json; +using StardewModdingAPI.AssemblyRewriters; using StardewModdingAPI.Events; using StardewModdingAPI.Framework; using StardewModdingAPI.Inheritance; diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index efd760f2..6f3bcb4b 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -156,12 +156,10 @@ - - @@ -218,6 +216,12 @@ false + + + {10db0676-9fc1-4771-a2c8-e2519f091e49} + StardewModdingAPI.AssemblyRewriters + + @@ -243,6 +247,7 @@ + -- cgit