diff options
author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2016-11-27 15:56:47 -0500 |
---|---|---|
committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2016-11-27 15:56:47 -0500 |
commit | f7b8879011873fa8f7a3d5dd7db27254bfc90469 (patch) | |
tree | 7c4e42901614ede42621fd4265c89e131eea4f19 /src | |
parent | 0d94c628bbc1d1ab098e0a90ee5758ee69694887 (diff) | |
download | SMAPI-f7b8879011873fa8f7a3d5dd7db27254bfc90469.tar.gz SMAPI-f7b8879011873fa8f7a3d5dd7db27254bfc90469.tar.bz2 SMAPI-f7b8879011873fa8f7a3d5dd7db27254bfc90469.zip |
supplement assembly resolution for Mono (#166)
Diffstat (limited to 'src')
5 files changed, 63 insertions, 18 deletions
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 *********/ - /// <summary>The assemblies to target. Equivalent types will be rewritten to use these assemblies.</summary> - private readonly Assembly[] TargetAssemblies; - - /// <summary>>The short assembly names to remove as assembly reference, and replace with the <see cref="TargetAssemblies"/>.</summary> - private readonly string[] RemoveAssemblyNames; + /// <summary>Metadata for mapping assemblies to the current <see cref="Platform"/>.</summary> + private readonly PlatformAssemblyMap AssemblyMap; /// <summary>A type => assembly lookup for types which should be rewritten.</summary> private readonly IDictionary<string, Assembly> TypeAssemblies; @@ -31,22 +28,20 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting ** Public methods *********/ /// <summary>Construct an instance.</summary> - /// <param name="targetAssemblies">The assembly filenames to target. Equivalent types will be rewritten to use these assemblies.</param> - /// <param name="removeAssemblyNames">The short assembly names to remove as assembly reference, and replace with the <paramref name="targetAssemblies"/>.</param> + /// <param name="assemblyMap">Metadata for mapping assemblies to the current <see cref="Platform"/>.</param> /// <param name="monitor">Encapsulates monitoring and logging.</param> - 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<string, Assembly>(); - 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 +{ + /// <summary>Metadata for mapping assemblies to the current <see cref="Platform"/>.</summary> + internal class PlatformAssemblyMap + { + /********* + ** Accessors + *********/ + /// <summary>The target game platform.</summary> + public readonly Platform TargetPlatform; + + /// <summary>The short assembly names to remove as assembly reference, and replace with the <see cref="Targets"/>. These should be short names (like "Stardew Valley").</summary> + public readonly string[] RemoveNames; + + /// <summary>The assembly filenames to target. Equivalent types should be rewritten to use these assemblies.</summary> + public readonly Assembly[] Targets; + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="targetPlatform">The target game platform.</param> + /// <param name="removeAssemblyNames">The assembly short names to remove (like <c>Stardew Valley</c>).</param> + /// <param name="targetAssemblies">The assemblies to target.</param> + 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 /// <summary>The directory in which to cache data.</summary> private readonly string CacheDirPath; + /// <summary>Metadata for mapping assemblies to the current <see cref="Platform"/>.</summary> + private readonly PlatformAssemblyMap AssemblyMap; + /// <summary>Rewrites assembly types to match the current platform.</summary> 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); } /// <summary>Preprocess an assembly and cache the modified version.</summary> @@ -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 } + /// <summary>Resolve an assembly from its name.</summary> + /// <param name="name">The assembly name.</param> + 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); } - /// <summary>Get an assembly rewriter for the target platform.</summary> + /// <summary>Get metadata for mapping assemblies to the current platform.</summary> /// <param name="targetPlatform">The target game platform.</param> - 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 @@ <Compile Include="Extensions.cs" /> <Compile Include="Framework\AssemblyRewriting\CachePaths.cs" /> <Compile Include="Framework\AssemblyRewriting\AssemblyTypeRewriter.cs" /> + <Compile Include="Framework\AssemblyRewriting\PlatformAssemblyMap.cs" /> <Compile Include="Framework\DeprecationLevel.cs" /> <Compile Include="Framework\DeprecationManager.cs" /> <Compile Include="Framework\InternalExtensions.cs" /> |