From 146456902a6893d67848c331e0e2797f7154667b Mon Sep 17 00:00:00 2001
From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com>
Date: Sat, 23 Mar 2024 23:35:54 -0700
Subject: [PATCH] feat: add `entireMethod` option to signature matching
---
Osu.Stubs/Color.cs | 3 +--
Osu.Stubs/Opcode/LazyMethod.cs | 5 +++--
Osu.Stubs/Opcode/OpCodeMatcher.cs | 14 +++++++++-----
3 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/Osu.Stubs/Color.cs b/Osu.Stubs/Color.cs
index 1116abf..c3cc923 100644
--- a/Osu.Stubs/Color.cs
+++ b/Osu.Stubs/Color.cs
@@ -1,9 +1,8 @@
-using System;
using Osu.Stubs.Opcode;
namespace Osu.Stubs;
-using XnaColor = Object;
+using XnaColor = object;
///
/// Original: Microsoft.Xna.Framework.Graphics.Color
diff --git a/Osu.Stubs/Opcode/LazyMethod.cs b/Osu.Stubs/Opcode/LazyMethod.cs
index 96cd5ff..9625a48 100644
--- a/Osu.Stubs/Opcode/LazyMethod.cs
+++ b/Osu.Stubs/Opcode/LazyMethod.cs
@@ -18,10 +18,11 @@ public class LazyMethod
///
/// Class#Method name of what this signature is matching.
/// Sequential opcodes to search the target method with.
- internal LazyMethod(string name, IReadOnlyList signature)
+ /// Whether the signature is the entire method.
+ internal LazyMethod(string name, IReadOnlyList signature, bool entireMethod = false)
{
_name = name;
- _lazy = new Lazy(() => OpCodeMatcher.FindMethodBySignature(signature));
+ _lazy = new Lazy(() => OpCodeMatcher.FindMethodBySignature(signature, entireMethod));
}
///
diff --git a/Osu.Stubs/Opcode/OpCodeMatcher.cs b/Osu.Stubs/Opcode/OpCodeMatcher.cs
index 40620ca..67f1a4b 100644
--- a/Osu.Stubs/Opcode/OpCodeMatcher.cs
+++ b/Osu.Stubs/Opcode/OpCodeMatcher.cs
@@ -10,8 +10,9 @@ public static class OpCodeMatcher
/// Search for a method inside the osu! assembly by an IL OpCode signature.
///
/// A set of sequential OpCodes to match.
+ /// Whether the signature is the entire method to search for.
/// The found method or null if none found.
- public static MethodInfo? FindMethodBySignature(IReadOnlyList signature)
+ public static MethodInfo? FindMethodBySignature(IReadOnlyList signature, bool entireMethod = false)
{
if (signature.Count <= 0) return null;
@@ -24,7 +25,7 @@ public static class OpCodeMatcher
var instructions = method.GetMethodBody()?.GetILAsByteArray();
if (instructions == null) continue;
- if (InstructionsMatchesSignature(instructions, signature))
+ if (InstructionsMatchesSignature(instructions, signature, entireMethod))
return method;
}
@@ -49,7 +50,7 @@ public static class OpCodeMatcher
var instructions = method.GetMethodBody()?.GetILAsByteArray();
if (instructions == null) continue;
- if (InstructionsMatchesSignature(instructions, signature))
+ if (InstructionsMatchesSignature(instructions, signature, false))
return method;
}
@@ -64,18 +65,21 @@ public static class OpCodeMatcher
/// for example.
///
/// A set of sequential OpCodes to search for in instructions.
+ /// Whether the signature should be the entire method.
///
private static bool InstructionsMatchesSignature(
IReadOnlyList ilInstructions,
- IReadOnlyList signature)
+ IReadOnlyList signature,
+ bool entireMethod)
{
var sequentialMatching = 0;
foreach (var instruction in new OpCodeReader(ilInstructions).GetOpCodes())
{
if (instruction == signature[sequentialMatching])
sequentialMatching++;
- else
+ else if (!entireMethod)
sequentialMatching = 0;
+ else return false;
if (sequentialMatching == signature.Count)
return true;