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.Installer/StardewModdingAPI.Installer.csproj | 1 + 1 file changed, 1 insertion(+) (limited to 'src/StardewModdingAPI.Installer') diff --git a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj index 6f9ed2eb..23e2d278 100644 --- a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj +++ b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj @@ -67,6 +67,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.Installer') 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 From cc4d3c1cf8755467acc4c72d25bf1e03fd8c4cba Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 29 Nov 2016 14:03:14 -0500 Subject: add framework for rewriting incompatible methods (#166) --- .../IMethodRewriter.cs | 21 +++++ .../PlatformAssemblyMap.cs | 24 ++++- .../StardewModdingAPI.AssemblyRewriters.csproj | 1 + .../StardewModdingAPI.Installer.csproj | 1 + src/StardewModdingAPI/Constants.cs | 9 +- .../AssemblyRewriting/AssemblyTypeRewriter.cs | 100 ++++++++++++++------- src/StardewModdingAPI/StardewModdingAPI.csproj | 1 + 7 files changed, 121 insertions(+), 36 deletions(-) create mode 100644 src/StardewModdingAPI.AssemblyRewriters/IMethodRewriter.cs (limited to 'src/StardewModdingAPI.Installer') diff --git a/src/StardewModdingAPI.AssemblyRewriters/IMethodRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/IMethodRewriter.cs new file mode 100644 index 00000000..5cbb7e0d --- /dev/null +++ b/src/StardewModdingAPI.AssemblyRewriters/IMethodRewriter.cs @@ -0,0 +1,21 @@ +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace StardewModdingAPI.AssemblyRewriters +{ + /// Rewrites a method for compatibility. + public interface IMethodRewriter + { + /// Get whether the given method reference can be rewritten. + /// The method reference. + bool ShouldRewrite(MethodReference methodRef); + + /// Rewrite a method for compatibility. + /// The module being rewritten. + /// The CIL rewriter. + /// The instruction which calls the method. + /// The method reference invoked by the . + /// Metadata for mapping assemblies to the current platform. + void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction callOp, MethodReference methodRef, PlatformAssemblyMap assemblyMap); + } +} diff --git a/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs b/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs index c0855719..f2826080 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs @@ -1,4 +1,7 @@ +using System.Collections.Generic; +using System.Linq; using System.Reflection; +using Mono.Cecil; namespace StardewModdingAPI.AssemblyRewriters { @@ -8,6 +11,9 @@ namespace StardewModdingAPI.AssemblyRewriters /********* ** Accessors *********/ + /**** + ** Data + ****/ /// The target game platform. public readonly Platform TargetPlatform; @@ -15,8 +21,19 @@ namespace StardewModdingAPI.AssemblyRewriters public readonly string[] RemoveNames; /// The assembly filenames to target. Equivalent types should be rewritten to use these assemblies. + + /**** + ** Metadata + ****/ + /// The assemblies to target. Equivalent types should be rewritten to use these assemblies. public readonly Assembly[] Targets; + /// An assembly => reference cache. + public readonly IDictionary TargetReferences; + + /// An assembly => module cache. + public readonly IDictionary TargetModules; + /********* ** Public methods @@ -27,9 +44,14 @@ namespace StardewModdingAPI.AssemblyRewriters /// The assemblies to target. public PlatformAssemblyMap(Platform targetPlatform, string[] removeAssemblyNames, Assembly[] targetAssemblies) { + // save data this.TargetPlatform = targetPlatform; this.RemoveNames = removeAssemblyNames; + + // cache assembly metadata this.Targets = targetAssemblies; + this.TargetReferences = this.Targets.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName)); + this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.Modules.Single().FullyQualifiedName)); } } -} \ No newline at end of file +} diff --git a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj index d87a48bc..b2533566 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj +++ b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj @@ -71,6 +71,7 @@ Properties\GlobalAssemblyInfo.cs + diff --git a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj index c19e5f55..8e4d38b3 100644 --- a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj +++ b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj @@ -68,6 +68,7 @@ + diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index b9074b6e..4f2f00a1 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; @@ -112,6 +113,12 @@ namespace StardewModdingAPI return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences, targetAssemblies); } + /// Get method rewriters which fix incompatible method calls in mod assemblies. + internal static IEnumerable GetMethodRewriters() + { + yield break; + } + /********* ** Private field @@ -123,4 +130,4 @@ namespace StardewModdingAPI return $"{prefix}_{Game1.uniqueIDForThisGame}"; } } -} \ No newline at end of file +} diff --git a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs index 43f6aa11..1e97bdcb 100644 --- a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs +++ b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs @@ -2,6 +2,8 @@ using System.Linq; using System.Reflection; using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; using StardewModdingAPI.AssemblyRewriters; namespace StardewModdingAPI.Framework.AssemblyRewriting @@ -18,9 +20,6 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting /// A type => assembly lookup for types which should be rewritten. private readonly IDictionary TypeAssemblies; - /// An assembly => reference cache. - private readonly IDictionary AssemblyNameReferences; - /// Encapsulates monitoring and logging. private readonly IMonitor Monitor; @@ -37,24 +36,18 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting this.AssemblyMap = assemblyMap; this.Monitor = monitor; - // cache assembly metadata - this.AssemblyNameReferences = assemblyMap.Targets.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName)); - // collect type => assembly lookup this.TypeAssemblies = new Dictionary(); foreach (Assembly assembly in assemblyMap.Targets) { - foreach (Module assemblyModule in assembly.Modules) + ModuleDefinition module = this.AssemblyMap.TargetModules[assembly]; + foreach (TypeDefinition type in module.GetTypes()) { - ModuleDefinition module = ModuleDefinition.ReadModule(assemblyModule.FullyQualifiedName); - foreach (TypeDefinition type in module.GetTypes()) - { - if (!type.IsPublic) - continue; // no need to rewrite - if (type.Namespace.Contains("<")) - continue; // ignore assembly metadata - this.TypeAssemblies[type.FullName] = assembly; - } + if (!type.IsPublic) + continue; // no need to rewrite + if (type.Namespace.Contains("<")) + continue; // ignore assembly metadata + this.TypeAssemblies[type.FullName] = assembly; } } } @@ -64,13 +57,12 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting public void RewriteAssembly(AssemblyDefinition assembly) { ModuleDefinition module = assembly.Modules.Single(); // technically an assembly can have multiple modules, but none of the build tools (including MSBuild) support it; simplify by assuming one module - bool shouldRewrite = false; // remove old assembly references + bool shouldRewrite = false; for (int i = 0; i < module.AssemblyReferences.Count; i++) { - bool shouldRemove = this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name); - if (shouldRemove) + if (this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name)) { this.Monitor.Log($"removing reference to {module.AssemblyReferences[i]}", LogLevel.Trace); shouldRewrite = true; @@ -78,25 +70,52 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting i--; } } + if (!shouldRewrite) + return; - // replace references - if (shouldRewrite) + // add target assembly references + foreach (AssemblyNameReference target in this.AssemblyMap.TargetReferences.Values) { - // add target assembly references - foreach (AssemblyNameReference target in this.AssemblyNameReferences.Values) - { - this.Monitor.Log($" adding reference to {target}", LogLevel.Trace); - module.AssemblyReferences.Add(target); - } + this.Monitor.Log($" adding reference to {target}", LogLevel.Trace); + module.AssemblyReferences.Add(target); + } - // rewrite type scopes to use target assemblies - IEnumerable typeReferences = module.GetTypeReferences().OrderBy(p => p.FullName); - string lastTypeLogged = null; - foreach (TypeReference type in typeReferences) + // rewrite type scopes to use target assemblies + IEnumerable typeReferences = module.GetTypeReferences().OrderBy(p => p.FullName); + string lastTypeLogged = null; + foreach (TypeReference type in typeReferences) + { + this.ChangeTypeScope(type, shouldLog: type.FullName != lastTypeLogged); + lastTypeLogged = type.FullName; + } + + // rewrite incompatible methods + IMethodRewriter[] methodRewriters = Constants.GetMethodRewriters().ToArray(); + foreach (MethodDefinition method in this.GetMethods(module)) + { + // skip methods with no rewritable method + bool hasMethodToRewrite = method.Body.Instructions.Any(op => (op.OpCode == OpCodes.Call || op.OpCode == OpCodes.Callvirt) && methodRewriters.Any(rewriter => rewriter.ShouldRewrite((MethodReference)op.Operand))); + if (!hasMethodToRewrite) + continue; + + // rewrite method references + method.Body.SimplifyMacros(); + ILProcessor cil = method.Body.GetILProcessor(); + Instruction[] instructions = cil.Body.Instructions.ToArray(); + foreach (Instruction op in instructions) { - this.ChangeTypeScope(type, shouldLog: type.FullName != lastTypeLogged); - lastTypeLogged = type.FullName; + if (op.OpCode == OpCodes.Call || op.OpCode == OpCodes.Callvirt) + { + IMethodRewriter rewriter = methodRewriters.FirstOrDefault(p => p.ShouldRewrite((MethodReference)op.Operand)); + if (rewriter != null) + { + MethodReference methodRef = (MethodReference)op.Operand; + this.Monitor.Log($"rewriting method reference {methodRef.DeclaringType.FullName}.{methodRef.Name}"); + rewriter.Rewrite(module, cil, op, methodRef, this.AssemblyMap); + } + } } + method.Body.OptimizeMacros(); } } @@ -119,10 +138,23 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting return; // replace scope - AssemblyNameReference assemblyRef = this.AssemblyNameReferences[assembly]; + AssemblyNameReference assemblyRef = this.AssemblyMap.TargetReferences[assembly]; if (shouldLog) this.Monitor.Log($"redirecting {type.FullName} from {type.Scope.Name} to {assemblyRef.Name}", LogLevel.Trace); type.Scope = assemblyRef; } + + /// Get all methods in a module. + /// The module to search. + private IEnumerable GetMethods(ModuleDefinition module) + { + return ( + from type in module.GetTypes() + where type.HasMethods + from method in type.Methods + where method.HasBody + select method + ); + } } } diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 6f3bcb4b..f57c1b6f 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -252,5 +252,6 @@ + \ No newline at end of file -- cgit From 7e17005c523a34a8d7c31e1945d2e96cb95e829a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 29 Nov 2016 19:41:58 -0500 Subject: update readme & installer for 1.3 (#166) --- README.md | 6 +++++- src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/StardewModdingAPI.Installer') diff --git a/README.md b/README.md index 1c36cd7e..1e4be986 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,17 @@ directory containing `src`). 3. If you did everything right so far, you should have a directory like this: ``` - SMAPI-1.0/ + SMAPI-1.x/ Mono/ Mods/* + Mono.Cecil.dll + Mono.Cecil.Rocks.dll Newtonsoft.Json.dll StardewModdingAPI StardewModdingAPI.exe StardewModdingAPI.exe.mdb StardewModdingAPI-settings.json + StardewModdingAPI.AssemblyRewriters.dll System.Numerics.dll steam_appid.txt Windows/ @@ -87,6 +90,7 @@ directory containing `src`). StardewModdingAPI.pdb StardewModdingAPI.xml StardewModdingAPI-settings.json + StardewModdingAPI.AssemblyRewriters.dll steam_appid.txt install.exe readme.txt diff --git a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj index 8e4d38b3..12657b52 100644 --- a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj +++ b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj @@ -66,8 +66,8 @@ - + @@ -78,9 +78,12 @@ + + + -- cgit From 5c11483b8ee7db1c2a8fbb8daae812a3c438d055 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 29 Nov 2016 19:42:27 -0500 Subject: rework uninstaller so it doesn't depend on install package For example, this avoids an issue where the normal SMAPI uninstaller didn't remove files added by the 'SMAPI for developers' installer. --- release-notes.md | 1 + .../InteractiveInstaller.cs | 27 +++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'src/StardewModdingAPI.Installer') diff --git a/release-notes.md b/release-notes.md index 8a3012ed..7d993986 100644 --- a/release-notes.md +++ b/release-notes.md @@ -5,6 +5,7 @@ See [log](https://github.com/CLxS/SMAPI/compare/stable...develop). For players: * You can now run most mods on any platform (e.g. run Windows mods on Linux/Mac). + * Fixed the normal uninstaller not removing files added by the 'SMAPI for developers' installer. ## 1.2 See [log](https://github.com/CLxS/SMAPI/compare/1.1.1...1.2). diff --git a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs index 5be9b14c..1d3802ab 100644 --- a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs +++ b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs @@ -27,6 +27,27 @@ namespace StardewModdingApi.Installer @"C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley" }; + /// The files to remove when uninstalling SMAPI. + private readonly string[] UninstallFiles = + { + // common + "StardewModdingAPI.exe", + "StardewModdingAPI-settings.json", + "StardewModdingAPI.AssemblyRewriters.dll", + "steam_appid.txt", + + // Linux/Mac only + "Mono.Cecil.dll", + "Mono.Cecil.Rocks.dll", + "Newtonsoft.Json.dll", + "StardewModdingAPI", + "StardewModdingAPI.exe.mdb", + "System.Numerics.dll", + + // Windows only + "StardewModdingAPI.pdb" + }; + /********* ** Public methods @@ -47,7 +68,7 @@ namespace StardewModdingApi.Installer /// /// Uninstall logic: /// 1. On Linux/Mac: if a backup of the launcher exists, delete the launcher and restore the backup. - /// 2. Delete all files in the game directory matching a file under package/Windows or package/Mono. + /// 2. Delete all files in the game directory matching one of the . /// public void Run(string[] args) { @@ -127,9 +148,9 @@ namespace StardewModdingApi.Installer // remove SMAPI files this.PrintDebug("Removing SMAPI files..."); - foreach (FileInfo sourceFile in packageDir.EnumerateFiles()) + foreach (string filename in this.UninstallFiles) { - string targetPath = Path.Combine(installDir.FullName, sourceFile.Name); + string targetPath = Path.Combine(installDir.FullName, filename); if (File.Exists(targetPath)) File.Delete(targetPath); } -- cgit From 67feb7e9a9ee057fdfb5b30840970b3952048b45 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 1 Dec 2016 01:48:39 -0500 Subject: remove Costura assembly weaving (#166) This didn't work on Linux or Mac, caused assembly resolution problems when rewritten mods referenced Json.NET, complicated debugging, and wasn't really needed since players use the installer to cleanly add or remove SMAPI. --- README.md | 3 +++ .../StardewModdingAPI.Installer.csproj | 3 ++- src/StardewModdingAPI/FodyWeavers.xml | 13 ------------- src/StardewModdingAPI/StardewModdingAPI.csproj | 9 --------- src/StardewModdingAPI/packages.config | 2 -- 5 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 src/StardewModdingAPI/FodyWeavers.xml (limited to 'src/StardewModdingAPI.Installer') diff --git a/README.md b/README.md index 1e4be986..9a0905b1 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,9 @@ directory containing `src`). steam_appid.txt Windows/ Mods/* + Mono.Cecil.dll + Mono.Cecil.Rocks.dll + Newtonsoft.Json.dll StardewModdingAPI.exe StardewModdingAPI.pdb StardewModdingAPI.xml diff --git a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj index 12657b52..0a33cd57 100644 --- a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj +++ b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj @@ -67,8 +67,8 @@ - + @@ -80,6 +80,7 @@ + diff --git a/src/StardewModdingAPI/FodyWeavers.xml b/src/StardewModdingAPI/FodyWeavers.xml deleted file mode 100644 index bd5a8e78..00000000 --- a/src/StardewModdingAPI/FodyWeavers.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - StardewModdingAPI.AssemblyRewriters - Stardew Valley - xTile - Steamworks.NET - Lidgren.Network - - - - \ No newline at end of file diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index e7ba06db..96eb038e 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -198,7 +198,6 @@ - Always @@ -227,14 +226,6 @@ - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - diff --git a/src/StardewModdingAPI/packages.config b/src/StardewModdingAPI/packages.config index dc07902b..e5fa3c3a 100644 --- a/src/StardewModdingAPI/packages.config +++ b/src/StardewModdingAPI/packages.config @@ -1,7 +1,5 @@  - - \ No newline at end of file -- cgit