diff --git a/SMAPI b/SMAPI deleted file mode 160000 index 9e521091..00000000 --- a/SMAPI +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9e521091fe4b13a9091bcb30c9f73ef210ace2dd diff --git a/src/Harmony/Attributes.cs b/src/Harmony/Attributes.cs new file mode 100644 index 00000000..14e4f513 --- /dev/null +++ b/src/Harmony/Attributes.cs @@ -0,0 +1,325 @@ +using System; +using System.Collections.Generic; + +namespace Harmony +{ + public enum MethodType + { + Normal, + Getter, + Setter, + Constructor, + StaticConstructor + } + + [Obsolete("This enum will be removed in the next major version. To define special methods, use MethodType")] + public enum PropertyMethod + { + Getter, + Setter + } + + public enum ArgumentType + { + Normal, + Ref, + Out, + Pointer + } + + public enum HarmonyPatchType + { + All, + Prefix, + Postfix, + Transpiler + } + + public class HarmonyAttribute : Attribute + { + public HarmonyMethod info = new HarmonyMethod(); + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class HarmonyPatch : HarmonyAttribute + { + // no argument (for use with TargetMethod) + + public HarmonyPatch() + { + } + + // starting with 'Type' + + public HarmonyPatch(Type declaringType) + { + info.declaringType = declaringType; + } + + public HarmonyPatch(Type declaringType, Type[] argumentTypes) + { + info.declaringType = declaringType; + info.argumentTypes = argumentTypes; + } + + public HarmonyPatch(Type declaringType, string methodName) + { + info.declaringType = declaringType; + info.methodName = methodName; + } + + public HarmonyPatch(Type declaringType, string methodName, params Type[] argumentTypes) + { + info.declaringType = declaringType; + info.methodName = methodName; + info.argumentTypes = argumentTypes; + } + + public HarmonyPatch(Type declaringType, string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations) + { + info.declaringType = declaringType; + info.methodName = methodName; + ParseSpecialArguments(argumentTypes, argumentVariations); + } + + public HarmonyPatch(Type declaringType, MethodType methodType) + { + info.declaringType = declaringType; + info.methodType = methodType; + } + + public HarmonyPatch(Type declaringType, MethodType methodType, params Type[] argumentTypes) + { + info.declaringType = declaringType; + info.methodType = methodType; + info.argumentTypes = argumentTypes; + } + + public HarmonyPatch(Type declaringType, MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations) + { + info.declaringType = declaringType; + info.methodType = methodType; + ParseSpecialArguments(argumentTypes, argumentVariations); + } + + public HarmonyPatch(Type declaringType, string propertyName, MethodType methodType) + { + info.declaringType = declaringType; + info.methodName = propertyName; + info.methodType = methodType; + } + + // starting with 'string' + + public HarmonyPatch(string methodName) + { + info.methodName = methodName; + } + + public HarmonyPatch(string methodName, params Type[] argumentTypes) + { + info.methodName = methodName; + info.argumentTypes = argumentTypes; + } + + public HarmonyPatch(string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations) + { + info.methodName = methodName; + ParseSpecialArguments(argumentTypes, argumentVariations); + } + + public HarmonyPatch(string propertyName, MethodType methodType) + { + info.methodName = propertyName; + info.methodType = methodType; + } + + // starting with 'MethodType' + + public HarmonyPatch(MethodType methodType) + { + info.methodType = methodType; + } + + public HarmonyPatch(MethodType methodType, params Type[] argumentTypes) + { + info.methodType = methodType; + info.argumentTypes = argumentTypes; + } + + public HarmonyPatch(MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations) + { + info.methodType = methodType; + ParseSpecialArguments(argumentTypes, argumentVariations); + } + + // starting with 'Type[]' + + public HarmonyPatch(Type[] argumentTypes) + { + info.argumentTypes = argumentTypes; + } + + public HarmonyPatch(Type[] argumentTypes, ArgumentType[] argumentVariations) + { + ParseSpecialArguments(argumentTypes, argumentVariations); + } + + // Obsolete attributes + + [Obsolete("This attribute will be removed in the next major version. Use HarmonyPatch together with MethodType.Getter or MethodType.Setter instead")] + public HarmonyPatch(string propertyName, PropertyMethod type) + { + info.methodName = propertyName; + info.methodType = type == PropertyMethod.Getter ? MethodType.Getter : MethodType.Setter; + } + + // + + private void ParseSpecialArguments(Type[] argumentTypes, ArgumentType[] argumentVariations) + { + if (argumentVariations == null || argumentVariations.Length == 0) + { + info.argumentTypes = argumentTypes; + return; + } + + if (argumentTypes.Length < argumentVariations.Length) + throw new ArgumentException("argumentVariations contains more elements than argumentTypes", nameof(argumentVariations)); + + var types = new List(); + for (var i = 0; i < argumentTypes.Length; i++) + { + var type = argumentTypes[i]; + switch (argumentVariations[i]) + { + case ArgumentType.Ref: + case ArgumentType.Out: + type = type.MakeByRefType(); + break; + case ArgumentType.Pointer: + type = type.MakePointerType(); + break; + } + types.Add(type); + } + info.argumentTypes = types.ToArray(); + } + } + + [AttributeUsage(AttributeTargets.Class)] + public class HarmonyPatchAll : HarmonyAttribute + { + public HarmonyPatchAll() + { + } + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public class HarmonyPriority : HarmonyAttribute + { + public HarmonyPriority(int prioritiy) + { + info.prioritiy = prioritiy; + } + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public class HarmonyBefore : HarmonyAttribute + { + public HarmonyBefore(params string[] before) + { + info.before = before; + } + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public class HarmonyAfter : HarmonyAttribute + { + public HarmonyAfter(params string[] after) + { + info.after = after; + } + } + + // If you don't want to use the special method names you can annotate + // using the following attributes: + + [AttributeUsage(AttributeTargets.Method)] + public class HarmonyPrepare : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method)] + public class HarmonyCleanup : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method)] + public class HarmonyTargetMethod : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method)] + public class HarmonyTargetMethods : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method)] + public class HarmonyPrefix : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method)] + public class HarmonyPostfix : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method)] + public class HarmonyTranspiler : Attribute + { + } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)] + public class HarmonyArgument : Attribute + { + public string OriginalName { get; private set; } + public int Index { get; private set; } + public string NewName { get; private set; } + + public HarmonyArgument(string originalName) : this(originalName, null) + { + } + + public HarmonyArgument(int index) : this(index, null) + { + } + + public HarmonyArgument(string originalName, string newName) + { + OriginalName = originalName; + Index = -1; + NewName = newName; + } + + public HarmonyArgument(int index, string name) + { + OriginalName = null; + Index = index; + NewName = name; + } + } + + // This attribute is for Harmony patching itself to the latest + // + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor)] + internal class UpgradeToLatestVersion : Attribute + { + public int version; + + public UpgradeToLatestVersion(int version) + { + this.version = version; + } + } +} \ No newline at end of file diff --git a/src/Harmony/CodeInstruction.cs b/src/Harmony/CodeInstruction.cs new file mode 100644 index 00000000..a6d89726 --- /dev/null +++ b/src/Harmony/CodeInstruction.cs @@ -0,0 +1,62 @@ +using Harmony.ILCopying; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; + +namespace Harmony +{ + public class CodeInstruction + { + public OpCode opcode; + public object operand; + public List