Implement module patch abstraction and patch loader (#250)
* Implement patch abstractions and patch loader using an interface * remove patch loader * rename patch class
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace SPTarkov.Reflection.CodeWrapper;
|
||||
|
||||
public class Code
|
||||
{
|
||||
public OpCode OpCode { get; }
|
||||
public Type? CallerType { get; }
|
||||
public object? OperandTarget { get; }
|
||||
public Type[]? Parameters { get; }
|
||||
public bool HasOperand { get; }
|
||||
|
||||
public Code(OpCode opCode)
|
||||
{
|
||||
OpCode = opCode;
|
||||
HasOperand = false;
|
||||
}
|
||||
|
||||
public Code(OpCode opCode, object operandTarget)
|
||||
{
|
||||
OpCode = opCode;
|
||||
OperandTarget = operandTarget;
|
||||
HasOperand = true;
|
||||
}
|
||||
|
||||
public Code(OpCode opCode, Type callerType)
|
||||
{
|
||||
OpCode = opCode;
|
||||
CallerType = callerType;
|
||||
HasOperand = true;
|
||||
}
|
||||
|
||||
public Code(OpCode opCode, Type callerType, object operandTarget, Type[] parameters = null)
|
||||
{
|
||||
OpCode = opCode;
|
||||
CallerType = callerType;
|
||||
OperandTarget = operandTarget;
|
||||
Parameters = parameters;
|
||||
HasOperand = true;
|
||||
}
|
||||
|
||||
public virtual Label? GetLabel()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace SPTarkov.Reflection.CodeWrapper;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class to generate IL code for transpilers
|
||||
/// </summary>
|
||||
public class CodeGenerator
|
||||
{
|
||||
public static List<CodeInstruction> GenerateInstructions(List<Code> codes)
|
||||
{
|
||||
var list = new List<CodeInstruction>();
|
||||
|
||||
foreach (Code code in codes)
|
||||
{
|
||||
list.Add(ParseCode(code));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static CodeInstruction ParseCode(Code code)
|
||||
{
|
||||
if (!code.HasOperand)
|
||||
{
|
||||
return new CodeInstruction(code.OpCode) { labels = GetLabelList(code) };
|
||||
}
|
||||
|
||||
if (code.OpCode == OpCodes.Ldfld || code.OpCode == OpCodes.Ldflda || code.OpCode == OpCodes.Stfld)
|
||||
{
|
||||
return new CodeInstruction(code.OpCode, AccessTools.Field(code.CallerType, code.OperandTarget as string)) { labels = GetLabelList(code) };
|
||||
}
|
||||
|
||||
if (code.OpCode == OpCodes.Call || code.OpCode == OpCodes.Callvirt)
|
||||
{
|
||||
return new CodeInstruction(code.OpCode, AccessTools.Method(code.CallerType, code.OperandTarget as string, code.Parameters)) { labels = GetLabelList(code) };
|
||||
}
|
||||
|
||||
if (code.OpCode == OpCodes.Box)
|
||||
{
|
||||
return new CodeInstruction(code.OpCode, code.CallerType) { labels = GetLabelList(code) };
|
||||
}
|
||||
|
||||
if (code.OpCode == OpCodes.Br || code.OpCode == OpCodes.Brfalse || code.OpCode == OpCodes.Brtrue || code.OpCode == OpCodes.Brtrue_S
|
||||
|| code.OpCode == OpCodes.Brfalse_S || code.OpCode == OpCodes.Br_S)
|
||||
{
|
||||
return new CodeInstruction(code.OpCode, code.OperandTarget) { labels = GetLabelList(code) };
|
||||
}
|
||||
|
||||
if (code.OpCode == OpCodes.Ldftn)
|
||||
{
|
||||
return new CodeInstruction(code.OpCode, AccessTools.Method(code.CallerType, code.OperandTarget as string, code.Parameters)) { labels = GetLabelList(code) };
|
||||
}
|
||||
|
||||
if (code.OpCode == OpCodes.Newobj)
|
||||
{
|
||||
return new CodeInstruction(code.OpCode, code.CallerType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == code.Parameters.Length)) { labels = GetLabelList(code) };
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Code with OpCode {code.OpCode.ToString()} is not supported.");
|
||||
}
|
||||
|
||||
private static List<Label> GetLabelList(Code code)
|
||||
{
|
||||
if (code.GetLabel() == null)
|
||||
{
|
||||
return new List<Label>();
|
||||
}
|
||||
|
||||
return [ (Label)code.GetLabel() ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace SPTarkov.Reflection.CodeWrapper;
|
||||
|
||||
public class CodeWithLabel : Code
|
||||
{
|
||||
public Label Label { get; }
|
||||
|
||||
public CodeWithLabel(OpCode opCode, Label label) : base(opCode)
|
||||
{
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public CodeWithLabel(OpCode opCode, Label label, object operandTarget) : base(opCode, operandTarget)
|
||||
{
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public CodeWithLabel(OpCode opCode, Label label, Type callerType) : base(opCode, callerType)
|
||||
{
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public CodeWithLabel(OpCode opCode, Label label, Type callerType, object operandTarget, Type[] parameters = null) : base(opCode, callerType, operandTarget, parameters)
|
||||
{
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public override Label? GetLabel()
|
||||
{
|
||||
return Label;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user