Added a couple extension methods for Mono.Cecil, fixed bug in ReplaceBodyWith
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,6 +10,7 @@ using Mono.Cecil;
|
|||||||
using Mono.Cecil.Cil;
|
using Mono.Cecil.Cil;
|
||||||
using Mono.Cecil.Rocks;
|
using Mono.Cecil.Rocks;
|
||||||
using Mono.Collections.Generic;
|
using Mono.Collections.Generic;
|
||||||
|
using MonoMod.Utils;
|
||||||
using Verse;
|
using Verse;
|
||||||
using CallSite = Mono.Cecil.CallSite;
|
using CallSite = Mono.Cecil.CallSite;
|
||||||
|
|
||||||
@@ -100,6 +101,81 @@ public static class CecilExtensions
|
|||||||
return variableDefinition;
|
return variableDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Collection<VariableDefinition> 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<VariableDefinition>(
|
||||||
|
$"No local variable of type '{type.FullName}' found in method '{ilProcessor.Body.Method.FullName}'.");
|
||||||
|
|
||||||
|
public static Collection<ParameterDefinition> 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<ParameterDefinition>(
|
||||||
|
$"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<ParameterDefinition>(
|
||||||
|
$"No parameter of type '{type}' found in method '{ilProcessor.Body.Method.FullName}'.");
|
||||||
|
|
||||||
public static void InsertAt(this ILProcessor ilProcessor, int index, Instruction instruction)
|
public static void InsertAt(this ILProcessor ilProcessor, int index, Instruction instruction)
|
||||||
=> ilProcessor.instructions.Insert(index, instruction);
|
=> ilProcessor.instructions.Insert(index, instruction);
|
||||||
|
|
||||||
@@ -349,23 +425,32 @@ public static class CecilExtensions
|
|||||||
replacement.Name, replacement.GetParameters().GetTypes());
|
replacement.Name, replacement.GetParameters().GetTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
var newMethodReference = module.ImportReference(replacement);
|
var replacementMethodReference = module.ImportReference(replacement);
|
||||||
var newBody = newMethodReference.Resolve().Body;
|
var replacementBody = replacementMethodReference.Resolve().Body;
|
||||||
|
|
||||||
newBody.SimplifyMacros();
|
replacementBody.SimplifyMacros();
|
||||||
MethodBodyRocks.ComputeOffsets(newBody);
|
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;
|
var targetInstructions = targetBody.instructions;
|
||||||
targetInstructions.Clear();
|
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
|
targetInstructions.Add(new(instruction.OpCode, instruction.Operand switch
|
||||||
{
|
{
|
||||||
FieldReference field => module.ImportReference(field, newMethodReference),
|
FieldReference field => module.ImportReference(field, replacementMethodReference),
|
||||||
MethodReference method => module.ImportReference(method, newMethodReference),
|
MethodReference method => module.ImportReference(method, replacementMethodReference),
|
||||||
TypeReference type => module.ImportReference(type, newMethodReference),
|
TypeReference type => module.ImportReference(type, replacementMethodReference),
|
||||||
ParameterReference parameter => targetBody.GetParameter(parameter.Index),
|
ParameterReference parameter => targetBody.GetParameter(parameter.Index),
|
||||||
|
VariableDefinition variable => targetBody.GetVariable(replacementVariables.IndexOf(variable)),
|
||||||
_ => instruction.Operand
|
_ => instruction.Operand
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -378,34 +463,39 @@ public static class CecilExtensions
|
|||||||
instruction.Operand = targetInstructions.First(ti => ti.Offset == operand.Offset);
|
instruction.Operand = targetInstructions.First(ti => ti.Offset == operand.Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetBody.Variables.Clear();
|
targetBody.MaxStackSize = replacementBody.MaxStackSize;
|
||||||
foreach (var variable in newBody.Variables)
|
|
||||||
targetBody.Variables.Add(new(module.ImportReference(variable.VariableType, newMethodReference)));
|
|
||||||
|
|
||||||
targetBody.MaxStackSize = newBody.MaxStackSize;
|
|
||||||
|
|
||||||
targetBody.ExceptionHandlers.Clear();
|
targetBody.ExceptionHandlers.Clear();
|
||||||
foreach (var exceptionHandler in newBody.ExceptionHandlers)
|
foreach (var exceptionHandler in replacementBody.ExceptionHandlers)
|
||||||
{
|
{
|
||||||
var handler = new ExceptionHandler(exceptionHandler.HandlerType)
|
var handler = new ExceptionHandler(exceptionHandler.HandlerType)
|
||||||
{
|
{
|
||||||
TryStart = exceptionHandler.TryStart,
|
TryStart = FindInTarget(exceptionHandler.TryStart),
|
||||||
TryEnd = exceptionHandler.TryEnd,
|
TryEnd = FindInTarget(exceptionHandler.TryEnd),
|
||||||
FilterStart = exceptionHandler.FilterStart,
|
FilterStart = FindInTarget(exceptionHandler.FilterStart),
|
||||||
HandlerStart = exceptionHandler.HandlerStart,
|
HandlerStart = FindInTarget(exceptionHandler.HandlerStart),
|
||||||
HandlerEnd = exceptionHandler.HandlerEnd
|
HandlerEnd = FindInTarget(exceptionHandler.HandlerEnd)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (exceptionHandler.CatchType is { } catchType)
|
if (exceptionHandler.CatchType is { } catchType)
|
||||||
handler.CatchType = module.ImportReference(catchType, newMethodReference);
|
handler.CatchType = module.ImportReference(catchType, replacementMethodReference);
|
||||||
|
|
||||||
targetBody.ExceptionHandlers.Add(handler);
|
targetBody.ExceptionHandlers.Add(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetBody.Method.ImplAttributes = newBody.Method.ImplAttributes;
|
targetBody.Method.ImplAttributes = replacementBody.Method.ImplAttributes;
|
||||||
|
|
||||||
targetBody.OptimizeMacros();
|
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;
|
public static MethodDefinition GetMethod(this ILProcessor ilProcessor) => ilProcessor.Body.Method;
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ namespace FisheryLib;
|
|||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public static class FisheryLib
|
public static class FisheryLib
|
||||||
{
|
{
|
||||||
public const decimal VERSION = 0.512M;
|
public const decimal VERSION = 0.6M;
|
||||||
|
|
||||||
public static decimal CurrentlyLoadedVersion { get; } = VERSION;
|
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()
|
// public static string GetVersion()
|
||||||
// {
|
// {
|
||||||
|
|||||||
Reference in New Issue
Block a user