diff --git a/1.2/Assemblies/1Fishery.dll b/1.2/Assemblies/1Fishery.dll index 12560b0..fb8a78a 100644 Binary files a/1.2/Assemblies/1Fishery.dll and b/1.2/Assemblies/1Fishery.dll differ diff --git a/1.2/Assemblies/1Fishery.pdb b/1.2/Assemblies/1Fishery.pdb index 1e840e8..2311bc9 100644 Binary files a/1.2/Assemblies/1Fishery.pdb and b/1.2/Assemblies/1Fishery.pdb differ diff --git a/1.3/Assemblies/1Fishery.dll b/1.3/Assemblies/1Fishery.dll index 1a95631..b710a1d 100644 Binary files a/1.3/Assemblies/1Fishery.dll and b/1.3/Assemblies/1Fishery.dll differ diff --git a/1.3/Assemblies/1Fishery.pdb b/1.3/Assemblies/1Fishery.pdb index cf8368f..1149983 100644 Binary files a/1.3/Assemblies/1Fishery.pdb and b/1.3/Assemblies/1Fishery.pdb differ diff --git a/1.4/Assemblies/1Fishery.dll b/1.4/Assemblies/1Fishery.dll index 1fe91b2..bbb3bb1 100644 Binary files a/1.4/Assemblies/1Fishery.dll and b/1.4/Assemblies/1Fishery.dll differ diff --git a/1.4/Assemblies/1Fishery.pdb b/1.4/Assemblies/1Fishery.pdb index 7b727fa..fef27a7 100644 Binary files a/1.4/Assemblies/1Fishery.pdb and b/1.4/Assemblies/1Fishery.pdb differ diff --git a/1.5/Assemblies/1Fishery.dll b/1.5/Assemblies/1Fishery.dll index 6e2b833..fb79dd2 100644 Binary files a/1.5/Assemblies/1Fishery.dll and b/1.5/Assemblies/1Fishery.dll differ diff --git a/1.5/Assemblies/1Fishery.pdb b/1.5/Assemblies/1Fishery.pdb index 3611429..d1e75e1 100644 Binary files a/1.5/Assemblies/1Fishery.pdb and b/1.5/Assemblies/1Fishery.pdb differ diff --git a/Source/FisheryLib/Cecil/CecilExtensions.cs b/Source/FisheryLib/Cecil/CecilExtensions.cs index cb6a432..1c2579b 100644 --- a/Source/FisheryLib/Cecil/CecilExtensions.cs +++ b/Source/FisheryLib/Cecil/CecilExtensions.cs @@ -10,6 +10,7 @@ using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; using Mono.Collections.Generic; +using MonoMod.Utils; using Verse; using CallSite = Mono.Cecil.CallSite; @@ -100,6 +101,81 @@ public static class CecilExtensions return variableDefinition; } + public static Collection GetLocalVariables(this ILProcessor ilProcessor) + => ilProcessor.Body.Variables; + + public static VariableDefinition FirstLocalVariable(this ILProcessor ilProcessor, Type type) + => ilProcessor.FirstLocalVariableOrDefault(type) ?? ThrowForNoMatchingLocalVariable(ilProcessor, type); + + public static VariableDefinition? FirstLocalVariableOrDefault(this ILProcessor ilProcessor, Type type) + { + Guard.IsNotNull(ilProcessor); + Guard.IsNotNull(type); + + var variables = ilProcessor.GetLocalVariables(); + for (var i = 0; i < variables.Count; i++) + { + if (variables[i].VariableType.Is(type)) + return variables[i]; + } + + return null; + } + + [DoesNotReturn] + private static VariableDefinition ThrowForNoMatchingLocalVariable(ILProcessor ilProcessor, Type type) + => ThrowHelper.ThrowInvalidOperationException( + $"No local variable of type '{type.FullName}' found in method '{ilProcessor.Body.Method.FullName}'."); + + public static Collection GetParameters(this ILProcessor ilProcessor) + => ilProcessor.Body.Method.Parameters; + + public static ParameterDefinition GetParameter(this ILProcessor ilProcessor, string name) + => ilProcessor.GetParameterOrDefault(name) ?? ThrowForNoMatchingParameter(ilProcessor, name); + + public static ParameterDefinition? GetParameterOrDefault(this ILProcessor ilProcessor, string name) + { + Guard.IsNotNull(ilProcessor); + Guard.IsNotNull(name); + + var parameters = ilProcessor.GetParameters(); + for (var i = 0; i < parameters.Count; i++) + { + if (parameters[i].Name == name) + return parameters[i]; + } + + return null; + } + + [DoesNotReturn] + private static ParameterDefinition ThrowForNoMatchingParameter(ILProcessor ilProcessor, string name) + => ThrowHelper.ThrowInvalidOperationException( + $"No parameter named '{name}' found in method '{ilProcessor.Body.Method.FullName}'."); + + public static ParameterDefinition FirstParameter(this ILProcessor ilProcessor, Type type) + => ilProcessor.FirstParameterOrDefault(type) ?? ThrowForNoMatchingParameter(ilProcessor, type); + + public static ParameterDefinition? FirstParameterOrDefault(this ILProcessor ilProcessor, Type type) + { + Guard.IsNotNull(ilProcessor); + Guard.IsNotNull(type); + + var parameters = ilProcessor.GetParameters(); + for (var i = 0; i < parameters.Count; i++) + { + if (parameters[i].ParameterType.Is(type)) + return parameters[i]; + } + + return null; + } + + [DoesNotReturn] + private static ParameterDefinition ThrowForNoMatchingParameter(ILProcessor ilProcessor, Type type) + => ThrowHelper.ThrowInvalidOperationException( + $"No parameter of type '{type}' found in method '{ilProcessor.Body.Method.FullName}'."); + public static void InsertAt(this ILProcessor ilProcessor, int index, Instruction instruction) => ilProcessor.instructions.Insert(index, instruction); @@ -349,23 +425,32 @@ public static class CecilExtensions replacement.Name, replacement.GetParameters().GetTypes()); } - var newMethodReference = module.ImportReference(replacement); - var newBody = newMethodReference.Resolve().Body; + var replacementMethodReference = module.ImportReference(replacement); + var replacementBody = replacementMethodReference.Resolve().Body; - newBody.SimplifyMacros(); - MethodBodyRocks.ComputeOffsets(newBody); + replacementBody.SimplifyMacros(); + MethodBodyRocks.ComputeOffsets(replacementBody); + + var targetVariables = targetBody.Variables; + var replacementVariables = replacementBody.Variables; + targetVariables.Clear(); + + foreach (var variable in replacementVariables) + targetVariables.Add(new(module.ImportReference(variable.VariableType, replacementMethodReference))); var targetInstructions = targetBody.instructions; targetInstructions.Clear(); - - foreach (var instruction in newBody.instructions) + + var replacementInstructions = replacementBody.instructions; + foreach (var instruction in replacementInstructions) { targetInstructions.Add(new(instruction.OpCode, instruction.Operand switch { - FieldReference field => module.ImportReference(field, newMethodReference), - MethodReference method => module.ImportReference(method, newMethodReference), - TypeReference type => module.ImportReference(type, newMethodReference), + FieldReference field => module.ImportReference(field, replacementMethodReference), + MethodReference method => module.ImportReference(method, replacementMethodReference), + TypeReference type => module.ImportReference(type, replacementMethodReference), ParameterReference parameter => targetBody.GetParameter(parameter.Index), + VariableDefinition variable => targetBody.GetVariable(replacementVariables.IndexOf(variable)), _ => instruction.Operand })); } @@ -378,34 +463,39 @@ public static class CecilExtensions instruction.Operand = targetInstructions.First(ti => ti.Offset == operand.Offset); } - targetBody.Variables.Clear(); - foreach (var variable in newBody.Variables) - targetBody.Variables.Add(new(module.ImportReference(variable.VariableType, newMethodReference))); - - targetBody.MaxStackSize = newBody.MaxStackSize; + targetBody.MaxStackSize = replacementBody.MaxStackSize; targetBody.ExceptionHandlers.Clear(); - foreach (var exceptionHandler in newBody.ExceptionHandlers) + foreach (var exceptionHandler in replacementBody.ExceptionHandlers) { var handler = new ExceptionHandler(exceptionHandler.HandlerType) { - TryStart = exceptionHandler.TryStart, - TryEnd = exceptionHandler.TryEnd, - FilterStart = exceptionHandler.FilterStart, - HandlerStart = exceptionHandler.HandlerStart, - HandlerEnd = exceptionHandler.HandlerEnd + TryStart = FindInTarget(exceptionHandler.TryStart), + TryEnd = FindInTarget(exceptionHandler.TryEnd), + FilterStart = FindInTarget(exceptionHandler.FilterStart), + HandlerStart = FindInTarget(exceptionHandler.HandlerStart), + HandlerEnd = FindInTarget(exceptionHandler.HandlerEnd) }; if (exceptionHandler.CatchType is { } catchType) - handler.CatchType = module.ImportReference(catchType, newMethodReference); + handler.CatchType = module.ImportReference(catchType, replacementMethodReference); targetBody.ExceptionHandlers.Add(handler); } - targetBody.Method.ImplAttributes = newBody.Method.ImplAttributes; + targetBody.Method.ImplAttributes = replacementBody.Method.ImplAttributes; targetBody.OptimizeMacros(); - newBody.OptimizeMacros(); + replacementBody.OptimizeMacros(); + + Instruction? FindInTarget(Instruction? replacementInstruction) + { + if (replacementInstruction is null) + return replacementInstruction; + + var index = replacementInstructions.IndexOf(replacementInstruction); + return (uint)index > (uint)targetInstructions.Count ? replacementInstruction : targetInstructions[index]; + } } public static MethodDefinition GetMethod(this ILProcessor ilProcessor) => ilProcessor.Body.Method; diff --git a/Source/FisheryLib/Fishery.cs b/Source/FisheryLib/Fishery.cs index c9576b7..74126ab 100644 --- a/Source/FisheryLib/Fishery.cs +++ b/Source/FisheryLib/Fishery.cs @@ -29,11 +29,11 @@ namespace FisheryLib; [PublicAPI] public static class FisheryLib { - public const decimal VERSION = 0.512M; + public const decimal VERSION = 0.6M; public static decimal CurrentlyLoadedVersion { get; } = VERSION; - public const string VERSION_STRING = "0.5.1.2"; + public const string VERSION_STRING = "0.6"; // public static string GetVersion() // {