private static MethodInfo GetPatchMethod <T>(T action) where T : Delegate { if (action.Method.IsStatic && action.Target == null) { return(action.Method); } if (MethodCache.TryGetValue(action, out var method)) { return(method); } var actionParams = action.Method.GetParameters(); var dmd = new DynamicMethodDefinition($"ActionWrapper_{action.Method.Name}", action.Method.ReturnType, actionParams.Select(p => p.ParameterType).ToArray()); for (var i = 0; i < dmd.Definition.Parameters.Count; i++) { var paramInfo = actionParams[i]; var paramDef = dmd.Definition.Parameters[i]; paramDef.Name = paramInfo.Name; } var il = dmd.GetILGenerator(); var preserveCtx = action.Target != null && action.Target.GetType().GetFields().Any(x => !x.IsStatic); if (preserveCtx) { var currentCounter = delegateCounter++; DelegateCache[currentCounter] = action; var cacheField = AccessTools.Field(typeof(HarmonyDelegatePatchingExtensions), nameof(DelegateCache)); var getMethod = AccessTools.Method(typeof(Dictionary <int, Delegate>), "get_Item"); il.Emit(OpCodes.Ldsfld, cacheField); il.Emit(OpCodes.Ldc_I4, currentCounter); il.Emit(OpCodes.Callvirt, getMethod); } else { if (action.Target == null) { il.Emit(OpCodes.Ldnull); } else { il.Emit(OpCodes.Newobj, AccessTools.FirstConstructor(action.Target.GetType(), x => x.GetParameters().Length == 0 && !x.IsStatic)); } il.Emit(OpCodes.Ldftn, action.Method); il.Emit(OpCodes.Newobj, AccessTools.Constructor(typeof(T), new[] { typeof(object), typeof(IntPtr) })); } for (var i = 0; i < actionParams.Length; i++) { il.Emit(OpCodes.Ldarg_S, (short)i); } il.Emit(OpCodes.Callvirt, AccessTools.Method(typeof(T), "Invoke")); il.Emit(OpCodes.Ret); // Generate with cecil to ensure it's usable with Harmony (Harmony blocks DynamicMethods by default) var result = DMDGenerator <DMDCecilGenerator> .Generate(dmd); MethodCache[action] = result; return(result); }
public static MethodInfo GenerateWith <T>(this DynamicMethodDefinition dmd, object context = null) where T : DMDGenerator <T>, new() { return(DMDGenerator <T> .Generate(dmd, context)); }