diff --git a/Harmony/Public/CodeInstruction.cs b/Harmony/Public/CodeInstruction.cs
index 7e782d86..6791235e 100644
--- a/Harmony/Public/CodeInstruction.cs
+++ b/Harmony/Public/CodeInstruction.cs
@@ -229,6 +229,80 @@ public static CodeInstruction StoreField(Type type, string name)
return new CodeInstruction(field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, field);
}
+ // --- LOCALS
+
+ /// Creates a CodeInstruction loading a local with the given index, using the shorter forms when possible
+ /// The index where the local is stored
+ /// Use address of local
+ ///
+ ///
+ public static CodeInstruction LoadLocal(int index, bool useAddress = false)
+ {
+ if (useAddress)
+ {
+ if (index < 256) return new CodeInstruction(OpCodes.Ldloca_S, Convert.ToByte(index));
+ else return new CodeInstruction(OpCodes.Ldloca, index);
+ }
+ else
+ {
+ if (index == 0) return new CodeInstruction(OpCodes.Ldloc_0);
+ else if (index == 1) return new CodeInstruction(OpCodes.Ldloc_1);
+ else if (index == 2) return new CodeInstruction(OpCodes.Ldloc_2);
+ else if (index == 3) return new CodeInstruction(OpCodes.Ldloc_3);
+ else if (index < 256) return new CodeInstruction(OpCodes.Ldloc_S, Convert.ToByte(index));
+ else return new CodeInstruction(OpCodes.Ldloc, index);
+ }
+ }
+
+ /// Creates a CodeInstruction storing to a local with the given index, using the shorter forms when possible
+ /// The index where the local is stored
+ ///
+ ///
+ public static CodeInstruction StoreLocal(int index)
+ {
+ if (index == 0) return new CodeInstruction(OpCodes.Stloc_0);
+ else if (index == 1) return new CodeInstruction(OpCodes.Stloc_1);
+ else if (index == 2) return new CodeInstruction(OpCodes.Stloc_2);
+ else if (index == 3) return new CodeInstruction(OpCodes.Stloc_3);
+ else if (index < 256) return new CodeInstruction(OpCodes.Stloc_S, Convert.ToByte(index));
+ else return new CodeInstruction(OpCodes.Stloc, index);
+ }
+
+ // --- ARGUMENTS
+
+ /// Creates a CodeInstruction loading an argument with the given index, using the shorter forms when possible
+ /// The index of the argument
+ /// Use address of argument
+ ///
+ ///
+ public static CodeInstruction LoadArgument(int index, bool useAddress = false)
+ {
+ if (useAddress)
+ {
+ if (index < 256) return new CodeInstruction(OpCodes.Ldarga_S, Convert.ToByte(index));
+ else return new CodeInstruction(OpCodes.Ldarga, index);
+ }
+ else
+ {
+ if (index == 0) return new CodeInstruction(OpCodes.Ldarg_0);
+ else if (index == 1) return new CodeInstruction(OpCodes.Ldarg_1);
+ else if (index == 2) return new CodeInstruction(OpCodes.Ldarg_2);
+ else if (index == 3) return new CodeInstruction(OpCodes.Ldarg_3);
+ else if (index < 256) return new CodeInstruction(OpCodes.Ldarg_S, Convert.ToByte(index));
+ else return new CodeInstruction(OpCodes.Ldarg, index);
+ }
+ }
+
+ /// Creates a CodeInstruction storing to an argument with the given index, using the shorter forms when possible
+ /// The index of the argument
+ ///
+ ///
+ public static CodeInstruction StoreArgument(int index)
+ {
+ if (index < 256) return new CodeInstruction(OpCodes.Starg_S, Convert.ToByte(index));
+ else return new CodeInstruction(OpCodes.Starg, index);
+ }
+
// --- TOSTRING
/// Returns a string representation of the code instruction
diff --git a/Harmony/Tools/CodeMatch.cs b/Harmony/Tools/CodeMatch.cs
index 364a6932..e15d8974 100644
--- a/Harmony/Tools/CodeMatch.cs
+++ b/Harmony/Tools/CodeMatch.cs
@@ -125,6 +125,106 @@ internal bool Matches(List codes, CodeInstruction instruction)
return true;
}
+ /// Creates a code match for local loads
+ /// Whether to match for address loads
+ /// An optional name
+ ///
+ public static CodeMatch LoadsLocal(bool useAddress = false, string name = null)
+ {
+ CodeMatch match = new CodeMatch(null, null, name);
+
+ if (useAddress)
+ {
+ match.opcodes.AddRange(new[]
+ {
+ OpCodes.Ldloca_S,
+ OpCodes.Ldloca
+ });
+ }
+ else
+ {
+ match.opcodes.AddRange(new[]
+ {
+ OpCodes.Ldloc_0,
+ OpCodes.Ldloc_1,
+ OpCodes.Ldloc_2,
+ OpCodes.Ldloc_3,
+ OpCodes.Ldloc_S,
+ OpCodes.Ldloc
+ });
+ }
+
+ return match;
+ }
+
+ /// Creates a code match for local stores
+ /// An optional name
+ ///
+ public static CodeMatch StoresLocal(string name = null)
+ {
+ CodeMatch match = new CodeMatch(null, null, name);
+
+ match.opcodes.AddRange(new[]
+ {
+ OpCodes.Stloc_0,
+ OpCodes.Stloc_1,
+ OpCodes.Stloc_2,
+ OpCodes.Stloc_3,
+ OpCodes.Stloc_S,
+ OpCodes.Stloc
+ });
+
+ return match;
+ }
+
+ /// Creates a code match for argument loads
+ /// Whether to match for address loads
+ /// An optional name
+ ///
+ public static CodeMatch LoadsArgument(bool useAddress = false, string name = null)
+ {
+ CodeMatch match = new CodeMatch(null, null, name);
+
+ if (useAddress)
+ {
+ match.opcodes.AddRange(new[]
+ {
+ OpCodes.Ldarga_S,
+ OpCodes.Ldarga
+ });
+ }
+ else
+ {
+ match.opcodes.AddRange(new[]
+ {
+ OpCodes.Ldarg_0,
+ OpCodes.Ldarg_1,
+ OpCodes.Ldarg_2,
+ OpCodes.Ldarg_3,
+ OpCodes.Ldarg_S,
+ OpCodes.Ldarg
+ });
+ }
+
+ return match;
+ }
+
+ /// Creates a code match for argument stores
+ /// An optional name
+ ///
+ public static CodeMatch StoresArgument(string name = null)
+ {
+ CodeMatch match = new CodeMatch(null, null, name);
+
+ match.opcodes.AddRange(new[]
+ {
+ OpCodes.Starg_S,
+ OpCodes.Starg
+ });
+
+ return match;
+ }
+
/// Returns a string that represents the match
/// A string representation
///
diff --git a/Harmony/Tools/Extensions.cs b/Harmony/Tools/Extensions.cs
index cc092c19..ecdb41ac 100644
--- a/Harmony/Tools/Extensions.cs
+++ b/Harmony/Tools/Extensions.cs
@@ -480,6 +480,40 @@ public static bool StoresField(this CodeInstruction code, FieldInfo field)
return code.opcode == stfldCode && Equals(code.operand, field);
}
+ /// Returns the index targeted by this ldloc, ldloca, or stloc
+ /// The
+ /// The index it targets
+ ///
+ ///
+ public static int LocalIndex(this CodeInstruction code)
+ {
+ if (code.opcode == OpCodes.Ldloc_0 || code.opcode == OpCodes.Stloc_0) return 0;
+ else if (code.opcode == OpCodes.Ldloc_1 || code.opcode == OpCodes.Stloc_1) return 1;
+ else if (code.opcode == OpCodes.Ldloc_2 || code.opcode == OpCodes.Stloc_2) return 2;
+ else if (code.opcode == OpCodes.Ldloc_3 || code.opcode == OpCodes.Stloc_3) return 3;
+ else if (code.opcode == OpCodes.Ldloc_S || code.opcode == OpCodes.Ldloc) return Convert.ToInt32(code.operand);
+ else if (code.opcode == OpCodes.Stloc_S || code.opcode == OpCodes.Stloc) return Convert.ToInt32(code.operand);
+ else if (code.opcode == OpCodes.Ldloca_S || code.opcode == OpCodes.Ldloca) return Convert.ToInt32(code.operand);
+ else throw new ArgumentException("Instruction is not a load or store", "code");
+ }
+
+ /// Returns the index targeted by this ldarg, ldarga, or starg
+ /// The
+ /// The index it targets
+ ///
+ ///
+ public static int ArgumentIndex(this CodeInstruction code)
+ {
+ if (code.opcode == OpCodes.Ldarg_0) return 0;
+ else if (code.opcode == OpCodes.Ldarg_1) return 1;
+ else if (code.opcode == OpCodes.Ldarg_2) return 2;
+ else if (code.opcode == OpCodes.Ldarg_3) return 3;
+ else if (code.opcode == OpCodes.Ldarg_S || code.opcode == OpCodes.Ldarg) return Convert.ToInt32(code.operand);
+ else if (code.opcode == OpCodes.Starg_S || code.opcode == OpCodes.Starg) return Convert.ToInt32(code.operand);
+ else if (code.opcode == OpCodes.Ldarga_S || code.opcode == OpCodes.Ldarga) return Convert.ToInt32(code.operand);
+ else throw new ArgumentException("Instruction is not a load or store", "code");
+ }
+
/// Adds labels to the code instruction and return it
/// The
/// One or several to add