diff options
Diffstat (limited to 'src/StardewModdingAPI/Framework')
-rw-r--r-- | src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs | 58 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/ModAssemblyLoader.cs | 8 |
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); } } } |