summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2018-02-17 16:38:45 -0500
committerJesse Plamondon-Willard <github@jplamondonw.com>2018-02-17 16:38:45 -0500
commite64326f9fe5a388e3a0638567bf4bdf8aab4b639 (patch)
treedbca53624a15a30186591ec4209f8f0eeb1ee0c7 /src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
parent754e356adc8fa23f4cecef588406f126a3e1a4a4 (diff)
downloadSMAPI-e64326f9fe5a388e3a0638567bf4bdf8aab4b639.tar.gz
SMAPI-e64326f9fe5a388e3a0638567bf4bdf8aab4b639.tar.bz2
SMAPI-e64326f9fe5a388e3a0638567bf4bdf8aab4b639.zip
Revert "rewrite all mod assemblies to let SMAPI proxy into their internal classes (#435)"
This reverts commit 032997650010a9b6cd3378cb1a2b8273fb3f56ff.
Diffstat (limited to 'src/SMAPI/Framework/ModLoading/AssemblyLoader.cs')
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoader.cs80
1 files changed, 42 insertions, 38 deletions
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
index ac849971..3a7b214a 100644
--- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
+++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
-using System.Runtime.CompilerServices;
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.Exceptions;
@@ -95,14 +94,23 @@ namespace StardewModdingAPI.Framework.ModLoading
if (assembly.Status == AssemblyLoadStatus.AlreadyLoaded)
continue;
- this.RewriteAssembly(mod, assembly.Definition, assumeCompatible, loggedMessages, logPrefix: " ");
- if (!oneAssembly)
- this.Monitor.Log($" Loading {assembly.File.Name}...", LogLevel.Trace);
- using (MemoryStream outStream = new MemoryStream())
+ bool changed = this.RewriteAssembly(mod, assembly.Definition, assumeCompatible, loggedMessages, logPrefix: " ");
+ if (changed)
{
- assembly.Definition.Write(outStream);
- byte[] bytes = outStream.ToArray();
- lastAssembly = Assembly.Load(bytes);
+ if (!oneAssembly)
+ this.Monitor.Log($" Loading {assembly.File.Name} (rewritten in memory)...", LogLevel.Trace);
+ using (MemoryStream outStream = new MemoryStream())
+ {
+ assembly.Definition.Write(outStream);
+ byte[] bytes = outStream.ToArray();
+ lastAssembly = Assembly.Load(bytes);
+ }
+ }
+ else
+ {
+ if (!oneAssembly)
+ this.Monitor.Log($" Loading {assembly.File.Name}...", LogLevel.Trace);
+ lastAssembly = Assembly.UnsafeLoadFrom(assembly.File.FullName);
}
}
@@ -184,48 +192,38 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <param name="logPrefix">A string to prefix to log messages.</param>
/// <returns>Returns whether the assembly was modified.</returns>
/// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
- private void RewriteAssembly(IModMetadata mod, AssemblyDefinition assembly, bool assumeCompatible, HashSet<string> loggedMessages, string logPrefix)
+ private bool RewriteAssembly(IModMetadata mod, AssemblyDefinition assembly, bool assumeCompatible, HashSet<string> loggedMessages, string logPrefix)
{
ModuleDefinition module = assembly.MainModule;
string filename = $"{assembly.Name.Name}.dll";
- // let SMAPI proxy mod internals for mod-provided APIs
- {
- MethodReference attributeConstructor = module.Import(typeof(InternalsVisibleToAttribute).GetConstructor(new[] { typeof(string) }));
- CustomAttribute attribute = new CustomAttribute(attributeConstructor);
- attribute.ConstructorArguments.Add(new CustomAttributeArgument(module.TypeSystem.String, "StardewModdingAPI.Proxies"));
- assembly.CustomAttributes.Add(attribute);
- }
-
// swap assembly references if needed (e.g. XNA => MonoGame)
bool platformChanged = false;
+ for (int i = 0; i < module.AssemblyReferences.Count; i++)
{
- for (int i = 0; i < module.AssemblyReferences.Count; i++)
+ // remove old assembly reference
+ if (this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name))
{
- // remove old assembly reference
- if (this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name))
- {
- this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Rewriting {filename} for OS...");
- platformChanged = true;
- module.AssemblyReferences.RemoveAt(i);
- i--;
- }
- }
-
- if (platformChanged)
- {
- // add target assembly references
- foreach (AssemblyNameReference target in this.AssemblyMap.TargetReferences.Values)
- module.AssemblyReferences.Add(target);
-
- // rewrite type scopes to use target assemblies
- IEnumerable<TypeReference> typeReferences = module.GetTypeReferences().OrderBy(p => p.FullName);
- foreach (TypeReference type in typeReferences)
- this.ChangeTypeScope(type);
+ this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Rewriting {filename} for OS...");
+ platformChanged = true;
+ module.AssemblyReferences.RemoveAt(i);
+ i--;
}
}
+ if (platformChanged)
+ {
+ // add target assembly references
+ foreach (AssemblyNameReference target in this.AssemblyMap.TargetReferences.Values)
+ module.AssemblyReferences.Add(target);
+
+ // rewrite type scopes to use target assemblies
+ IEnumerable<TypeReference> typeReferences = module.GetTypeReferences().OrderBy(p => p.FullName);
+ foreach (TypeReference type in typeReferences)
+ this.ChangeTypeScope(type);
+ }
// find (and optionally rewrite) incompatible instructions
+ bool anyRewritten = false;
IInstructionHandler[] handlers = new InstructionMetadata().GetHandlers().ToArray();
foreach (MethodDefinition method in this.GetMethods(module))
{
@@ -234,6 +232,8 @@ namespace StardewModdingAPI.Framework.ModLoading
{
InstructionHandleResult result = handler.Handle(module, method, this.AssemblyMap, platformChanged);
this.ProcessInstructionHandleResult(mod, handler, result, loggedMessages, logPrefix, assumeCompatible, filename);
+ if (result == InstructionHandleResult.Rewritten)
+ anyRewritten = true;
}
// check CIL instructions
@@ -244,9 +244,13 @@ namespace StardewModdingAPI.Framework.ModLoading
{
InstructionHandleResult result = handler.Handle(module, cil, instruction, this.AssemblyMap, platformChanged);
this.ProcessInstructionHandleResult(mod, handler, result, loggedMessages, logPrefix, assumeCompatible, filename);
+ if (result == InstructionHandleResult.Rewritten)
+ anyRewritten = true;
}
}
}
+
+ return platformChanged || anyRewritten;
}
/// <summary>Process the result from an instruction handler.</summary>