81 lines
2.8 KiB
C#
81 lines
2.8 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using HarmonyLib;
|
|
using NitroxModel.Helper;
|
|
|
|
namespace NitroxPatcher.PatternMatching;
|
|
|
|
public readonly struct InstructionPattern
|
|
{
|
|
public bool Equals(InstructionPattern other) => OpCode.Equals(other.OpCode) && Operand.Equals(other.Operand) && Label == other.Label;
|
|
|
|
public override bool Equals(object obj) => obj is InstructionPattern other && Equals(other);
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
int hashCode = OpCode.GetHashCode();
|
|
hashCode = (hashCode * 397) ^ Operand.GetHashCode();
|
|
hashCode = (hashCode * 397) ^ (Label != null ? Label.GetHashCode() : 0);
|
|
return hashCode;
|
|
}
|
|
}
|
|
|
|
public OpCodePattern OpCode { get; init; }
|
|
public OperandPattern Operand { get; init; }
|
|
public string Label { get; init; }
|
|
|
|
public static implicit operator InstructionPattern(OpCode opCode) => new() { OpCode = opCode };
|
|
public static implicit operator InstructionPattern(OperandPattern operand) => new() { Operand = operand };
|
|
public static implicit operator InstructionPattern(MethodInfo method) => Call(method, true);
|
|
|
|
public static InstructionPattern Call(string className, string methodName) => new() { OpCode = OpCodes.Call, Operand = new(className, methodName) };
|
|
|
|
public static InstructionPattern Call(MethodInfo method) => Call(method, false);
|
|
|
|
private static InstructionPattern Call(MethodInfo method, bool matchAnyCallOpcode)
|
|
{
|
|
Type methodDeclaringType = method.DeclaringType;
|
|
Validate.NotNull(methodDeclaringType);
|
|
|
|
return new()
|
|
{
|
|
OpCode = new OpCodePattern
|
|
{
|
|
OpCode = OpCodes.Call,
|
|
WeakMatch = matchAnyCallOpcode
|
|
},
|
|
Operand = new(methodDeclaringType.FullName, method.Name, method.GetParameters().Select(p => p.ParameterType).ToArray())
|
|
};
|
|
}
|
|
|
|
public static bool operator ==(InstructionPattern pattern, CodeInstruction instruction)
|
|
{
|
|
if (instruction == null)
|
|
{
|
|
return false;
|
|
}
|
|
return pattern.OpCode == instruction.opcode && pattern.Operand == instruction.operand;
|
|
}
|
|
|
|
public static bool operator ==(CodeInstruction instruction, InstructionPattern pattern)
|
|
{
|
|
return pattern == instruction;
|
|
}
|
|
|
|
public static bool operator !=(CodeInstruction instruction, InstructionPattern pattern)
|
|
{
|
|
return !(instruction == pattern);
|
|
}
|
|
|
|
public static bool operator !=(InstructionPattern pattern, CodeInstruction instruction)
|
|
{
|
|
return !(pattern == instruction);
|
|
}
|
|
|
|
public override string ToString() => $"{OpCode.OpCode}{(Operand != default ? $" {Operand}" : "")}{(Label != null ? $" '{Label}'" : "")}";
|
|
}
|