summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs58
-rw-r--r--src/StardewModdingAPI/Framework/ModAssemblyLoader.cs8
2 files changed, 41 insertions, 25 deletions
diff --git a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs
index 2bfb43e4..7081df15 100644
--- a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs
+++ b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs
@@ -23,6 +23,9 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
/// <summary>An assembly => reference cache.</summary>
private readonly IDictionary<Assembly, AssemblyNameReference> AssemblyNameReferences;
+ /// <summary>Encapsulates monitoring and logging.</summary>
+ private readonly IMonitor Monitor;
+
/*********
** Public methods
@@ -30,11 +33,13 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
/// <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>
- public AssemblyTypeRewriter(Assembly[] targetAssemblies, string[] removeAssemblyNames)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ public AssemblyTypeRewriter(Assembly[] targetAssemblies, string[] removeAssemblyNames, IMonitor monitor)
{
// save config
this.TargetAssemblies = targetAssemblies;
this.RemoveAssemblyNames = removeAssemblyNames;
+ this.Monitor = monitor;
// cache assembly metadata
this.AssemblyNameReferences = targetAssemblies.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName));
@@ -62,31 +67,39 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
/// <param name="assembly">The assembly to rewrite.</param>
public void RewriteAssembly(AssemblyDefinition assembly)
{
- foreach (ModuleDefinition module in assembly.Modules)
+ 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
+ for (int i = 0; i < module.AssemblyReferences.Count; i++)
{
- // remove old assembly references
- bool shouldRewrite = false;
- for (int i = 0; i < module.AssemblyReferences.Count; i++)
+ bool shouldRemove = this.RemoveAssemblyNames.Any(name => module.AssemblyReferences[i].Name == name);
+ if (shouldRemove)
{
- bool shouldRemove = this.RemoveAssemblyNames.Any(name => module.AssemblyReferences[i].Name == name);
- if (shouldRemove)
- {
- shouldRewrite = true;
- module.AssemblyReferences.RemoveAt(i);
- i--;
- }
+ this.Monitor.Log($"removing reference to {module.AssemblyReferences[i]}", LogLevel.Trace);
+ shouldRewrite = true;
+ module.AssemblyReferences.RemoveAt(i);
+ i--;
}
+ }
- // replace references
- if (shouldRewrite)
+ // replace references
+ if (shouldRewrite)
+ {
+ // add target assembly references
+ foreach (AssemblyNameReference target in this.AssemblyNameReferences.Values)
{
- // add target assembly references
- foreach (AssemblyNameReference target in this.AssemblyNameReferences.Values)
- module.AssemblyReferences.Add(target);
+ this.Monitor.Log($" adding reference to {target}", LogLevel.Trace);
+ module.AssemblyReferences.Add(target);
+ }
- // rewrite type scopes to use target assemblies
- foreach (TypeReference type in module.GetTypeReferences())
- this.ChangeTypeScope(type);
+ // rewrite type scopes to use target assemblies
+ IEnumerable<TypeReference> 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;
}
}
}
@@ -97,7 +110,8 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
*********/
/// <summary>Get the correct reference to use for compatibility with the current platform.</summary>
/// <param name="type">The type reference to rewrite.</param>
- private void ChangeTypeScope(TypeReference type)
+ /// <param name="shouldLog">Whether to log a message.</param>
+ private void ChangeTypeScope(TypeReference type, bool shouldLog)
{
// check skip conditions
if (type == null || type.FullName.StartsWith("System."))
@@ -110,6 +124,8 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
// replace scope
AssemblyNameReference assemblyRef = this.AssemblyNameReferences[assembly];
+ if (shouldLog)
+ this.Monitor.Log($"redirecting {type.FullName} from {type.Scope.Name} to {assemblyRef.Name}", LogLevel.Trace);
type.Scope = assemblyRef;
}
}
diff --git a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs
index 54a111d3..7de48649 100644
--- a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs
+++ b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs
@@ -20,7 +20,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Rewrites assembly types to match the current platform.</summary>
private readonly AssemblyTypeRewriter AssemblyTypeRewriter;
- /// <summary>Encapsulates monitoring and logging for a given module.</summary>
+ /// <summary>Encapsulates monitoring and logging.</summary>
private readonly IMonitor Monitor;
@@ -30,7 +30,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Construct an instance.</summary>
/// <param name="cacheDirPath">The cache directory.</param>
/// <param name="targetPlatform">The current game platform.</param>
- /// <param name="monitor">Encapsulates monitoring and logging for a given module.</param>
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
public ModAssemblyLoader(string cacheDirPath, Platform targetPlatform, IMonitor monitor)
{
this.CacheDirPath = cacheDirPath;
@@ -55,7 +55,7 @@ namespace StardewModdingAPI.Framework
// process assembly if not cached
if (!canUseCache)
{
- this.Monitor.Log($"Preprocessing new assembly {assemblyFileName}...");
+ this.Monitor.Log($"Loading {assemblyFileName} for the first time; preprocessing...");
// read assembly definition
AssemblyDefinition assembly;
@@ -155,7 +155,7 @@ namespace StardewModdingAPI.Framework
throw new InvalidOperationException($"Unknown target platform '{targetPlatform}'.");
}
- return new AssemblyTypeRewriter(targetAssemblies, removeAssemblyReferences);
+ return new AssemblyTypeRewriter(targetAssemblies, removeAssemblyReferences, this.Monitor);
}
}
}