diff options
Diffstat (limited to 'src')
9 files changed, 119 insertions, 15 deletions
diff --git a/src/StardewModdingAPI.AssemblyRewriters/Finders/EventFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/Finders/EventFinder.cs index bcceee32..c0051469 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Finders/EventFinder.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Finders/EventFinder.cs @@ -37,6 +37,18 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{eventName} event"; } + /// <summary>Rewrite a method definition for compatibility.</summary> + /// <param name="module">The module being rewritten.</param> + /// <param name="method">The method definition to rewrite.</param> + /// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param> + /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> + /// <returns>Returns whether the instruction was rewritten.</returns> + /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> + public virtual bool Rewrite(ModuleDefinition module, MethodDefinition method, PlatformAssemblyMap assemblyMap, bool platformChanged) + { + return false; + } + /// <summary>Rewrite a CIL instruction for compatibility.</summary> /// <param name="module">The module being rewritten.</param> /// <param name="cil">The CIL rewriter.</param> @@ -45,9 +57,9 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> /// <returns>Returns whether the instruction was rewritten.</returns> /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> - public bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged) + public virtual bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged) { - if (!this.IsMatch(instruction, platformChanged)) + if (!this.IsMatch(instruction)) return false; throw new IncompatibleInstructionException(this.NounPhrase); @@ -59,8 +71,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders *********/ /// <summary>Get whether a CIL instruction matches.</summary> /// <param name="instruction">The IL instruction.</param> - /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> - protected bool IsMatch(Instruction instruction, bool platformChanged) + protected bool IsMatch(Instruction instruction) { MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); return diff --git a/src/StardewModdingAPI.AssemblyRewriters/Finders/FieldFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/Finders/FieldFinder.cs index cdfc3bd5..b44883e9 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Finders/FieldFinder.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Finders/FieldFinder.cs @@ -37,6 +37,18 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{fieldName} field"; } + /// <summary>Rewrite a method definition for compatibility.</summary> + /// <param name="module">The module being rewritten.</param> + /// <param name="method">The method definition to rewrite.</param> + /// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param> + /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> + /// <returns>Returns whether the instruction was rewritten.</returns> + /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> + public virtual bool Rewrite(ModuleDefinition module, MethodDefinition method, PlatformAssemblyMap assemblyMap, bool platformChanged) + { + return false; + } + /// <summary>Rewrite a CIL instruction for compatibility.</summary> /// <param name="module">The module being rewritten.</param> /// <param name="cil">The CIL rewriter.</param> @@ -47,7 +59,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> public virtual bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged) { - if (!this.IsMatch(instruction, platformChanged)) + if (!this.IsMatch(instruction)) return false; throw new IncompatibleInstructionException(this.NounPhrase); @@ -59,8 +71,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders *********/ /// <summary>Get whether a CIL instruction matches.</summary> /// <param name="instruction">The IL instruction.</param> - /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> - protected bool IsMatch(Instruction instruction, bool platformChanged) + protected bool IsMatch(Instruction instruction) { FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); return diff --git a/src/StardewModdingAPI.AssemblyRewriters/Finders/MethodFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/Finders/MethodFinder.cs index 2efcbb0f..19dda58a 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Finders/MethodFinder.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Finders/MethodFinder.cs @@ -37,6 +37,18 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{methodName} method"; } + /// <summary>Rewrite a method definition for compatibility.</summary> + /// <param name="module">The module being rewritten.</param> + /// <param name="method">The method definition to rewrite.</param> + /// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param> + /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> + /// <returns>Returns whether the instruction was rewritten.</returns> + /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> + public virtual bool Rewrite(ModuleDefinition module, MethodDefinition method, PlatformAssemblyMap assemblyMap, bool platformChanged) + { + return false; + } + /// <summary>Rewrite a CIL instruction for compatibility.</summary> /// <param name="module">The module being rewritten.</param> /// <param name="cil">The CIL rewriter.</param> @@ -47,7 +59,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> public bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged) { - if (!this.IsMatch(instruction, platformChanged)) + if (!this.IsMatch(instruction)) return false; throw new IncompatibleInstructionException(this.NounPhrase); @@ -59,8 +71,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders *********/ /// <summary>Get whether a CIL instruction matches.</summary> /// <param name="instruction">The IL instruction.</param> - /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> - protected bool IsMatch(Instruction instruction, bool platformChanged) + protected bool IsMatch(Instruction instruction) { MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); return diff --git a/src/StardewModdingAPI.AssemblyRewriters/Finders/TypeFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/Finders/TypeFinder.cs index 96cbb229..0e4d6824 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Finders/TypeFinder.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Finders/TypeFinder.cs @@ -33,6 +33,21 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders this.NounPhrase = nounPhrase ?? $"{fullTypeName} type"; } + /// <summary>Rewrite a method definition for compatibility.</summary> + /// <param name="module">The module being rewritten.</param> + /// <param name="method">The method definition to rewrite.</param> + /// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param> + /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> + /// <returns>Returns whether the instruction was rewritten.</returns> + /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> + public virtual bool Rewrite(ModuleDefinition module, MethodDefinition method, PlatformAssemblyMap assemblyMap, bool platformChanged) + { + if (!this.IsMatch(method)) + return false; + + throw new IncompatibleInstructionException(this.NounPhrase); + } + /// <summary>Rewrite a CIL instruction for compatibility.</summary> /// <param name="module">The module being rewritten.</param> /// <param name="cil">The CIL rewriter.</param> @@ -43,7 +58,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> public virtual bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged) { - if (!this.IsMatch(instruction, platformChanged)) + if (!this.IsMatch(instruction)) return false; throw new IncompatibleInstructionException(this.NounPhrase); @@ -54,9 +69,24 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders ** Protected methods *********/ /// <summary>Get whether a CIL instruction matches.</summary> + /// <param name="method">The method deifnition.</param> + protected bool IsMatch(MethodDefinition method) + { + if (method.ReturnType.FullName == this.FullTypeName) + return true; + + foreach (VariableDefinition variable in method.Body.Variables) + { + if (variable.VariableType.FullName == this.FullTypeName) + return true; + } + + return false; + } + + /// <summary>Get whether a CIL instruction matches.</summary> /// <param name="instruction">The IL instruction.</param> - /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> - protected bool IsMatch(Instruction instruction, bool platformChanged) + protected bool IsMatch(Instruction instruction) { string fullName = this.FullTypeName; diff --git a/src/StardewModdingAPI.AssemblyRewriters/IInstructionRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/IInstructionRewriter.cs index 3a7b1365..2f16b23d 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/IInstructionRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/IInstructionRewriter.cs @@ -16,6 +16,15 @@ namespace StardewModdingAPI.AssemblyRewriters /********* ** Methods *********/ + /// <summary>Rewrite a method definition for compatibility.</summary> + /// <param name="module">The module being rewritten.</param> + /// <param name="method">The method definition to rewrite.</param> + /// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param> + /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> + /// <returns>Returns whether the instruction was rewritten.</returns> + /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> + bool Rewrite(ModuleDefinition module, MethodDefinition method, PlatformAssemblyMap assemblyMap, bool platformChanged); + /// <summary>Rewrite a CIL instruction for compatibility.</summary> /// <param name="module">The module being rewritten.</param> /// <param name="cil">The CIL rewriter.</param> diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldReplaceRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldReplaceRewriter.cs index 95663c49..73844073 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldReplaceRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldReplaceRewriter.cs @@ -42,7 +42,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> public override bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged) { - if (!this.IsMatch(instruction, platformChanged)) + if (!this.IsMatch(instruction)) return false; FieldReference newRef = module.Import(this.ToField); diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldToPropertyRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldToPropertyRewriter.cs index a25f3fef..3f57042d 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldToPropertyRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldToPropertyRewriter.cs @@ -42,7 +42,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> public override bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged) { - if (!this.IsMatch(instruction, platformChanged)) + if (!this.IsMatch(instruction)) return false; string methodPrefix = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld ? "get" : "set"; diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/MethodParentRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/MethodParentRewriter.cs index 3ec8c704..035ef211 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/MethodParentRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/MethodParentRewriter.cs @@ -43,6 +43,18 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters this.OnlyIfPlatformChanged = onlyIfPlatformChanged; } + /// <summary>Rewrite a method definition for compatibility.</summary> + /// <param name="module">The module being rewritten.</param> + /// <param name="method">The method definition to rewrite.</param> + /// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param> + /// <param name="platformChanged">Whether the mod was compiled on a different platform.</param> + /// <returns>Returns whether the instruction was rewritten.</returns> + /// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception> + public bool Rewrite(ModuleDefinition module, MethodDefinition method, PlatformAssemblyMap assemblyMap, bool platformChanged) + { + return false; + } + /// <summary>Rewrite a CIL instruction for compatibility.</summary> /// <param name="module">The module being rewritten.</param> /// <param name="cil">The CIL rewriter.</param> diff --git a/src/StardewModdingAPI/Framework/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/AssemblyLoader.cs index 5d00c525..f6fe89f5 100644 --- a/src/StardewModdingAPI/Framework/AssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/AssemblyLoader.cs @@ -198,6 +198,26 @@ namespace StardewModdingAPI.Framework IInstructionRewriter[] rewriters = Constants.GetRewriters().ToArray(); foreach (MethodDefinition method in this.GetMethods(module)) { + // check method definition + foreach (IInstructionRewriter rewriter in rewriters) + { + try + { + if (rewriter.Rewrite(module, method, this.AssemblyMap, platformChanged)) + { + this.LogOnce(this.Monitor, loggedMessages, $"Rewrote {assembly.Name.Name} to fix {rewriter.NounPhrase}..."); + anyRewritten = true; + } + } + catch (IncompatibleInstructionException) + { + if (!assumeCompatible) + throw new IncompatibleInstructionException(rewriter.NounPhrase, $"Found an incompatible CIL instruction ({rewriter.NounPhrase}) while loading assembly {assembly.Name.Name}."); + this.LogOnce(this.Monitor, loggedMessages, $"Found an incompatible CIL instruction ({rewriter.NounPhrase}) while loading assembly {assembly.Name.Name}, but SMAPI is configured to allow it anyway. The mod may crash or behave unexpectedly.", LogLevel.Warn); + } + } + + // check CIL instructions ILProcessor cil = method.Body.GetILProcessor(); foreach (Instruction instruction in cil.Body.Instructions.ToArray()) { |