public void Import(IFile file, IMod mod) { if (file.GetType() != typeof(LdstrFile)) { return; } var module = HookEndpointManager.GenerateCecilModule(mod.Code.GetName()); var entryDict = (file as LdstrFile).LdstrEntries; foreach (var entryPair in entryDict) { var md = module.FindMethod(entryPair.Key); if (md == null) { continue; } var method = MethodBase.GetMethodFromHandle(md.ResolveReflection().MethodHandle); var e = entryPair.Value; if (!HaveTranslation(e)) { continue; } var modification = new ILContext.Manipulator(il => { foreach (var instruction in il.Instrs) { var ins = e.Instructions.FirstOrDefault(i => instruction.MatchLdstr(i.Origin)); if (ins == null || string.IsNullOrEmpty(ins.Translation)) { continue; } instruction.Operand = ins.Translation; foreach (var label in il.Labels) { if (label.Target.MatchLdstr(ins.Origin)) { label.Target = instruction; } } } }); if (!modifications.ContainsKey(method)) { HookEndpointManager.Modify(method, modification); modifications.Add(method, modification); } } }
internal bool RegisterILHook(ILHook _detour, MethodBase from, ILContext.Manipulator manipulator) { Assembly owner = GetHookOwner(); if (owner == null) { return(true); // continue with default detour creation, we just don't track it } OnILHook?.Invoke(owner, from, manipulator); TrackDetour(owner, _detour); return(true); }
protected override void ImportInternal(LdstrFile file, IMod mod, CultureInfo culture) { Terraria.ModLoader.ContentInstance.Register(Utils.GetModByName(mod.Name)); var module = mod.Code.ManifestModule; var entryDict = file.LdstrEntries; foreach (var entryPair in entryDict) { var method = Utils.FindMethodByID(module, entryPair.Key); if (method == null) { continue; } var e = entryPair.Value; if (!HaveTranslation(e)) { continue; } var modification = new ILContext.Manipulator(il => { foreach (var instruction in il.Instrs) { var ins = e.Instructions.FirstOrDefault(i => instruction.MatchLdstr(i.Origin)); if (ins == null || string.IsNullOrEmpty(ins.Translation)) { continue; } instruction.Operand = ins.Translation; foreach (var label in il.Labels) { if (label.Target.MatchLdstr(ins.Origin)) { label.Target = instruction; } } } }); if (!modifications.ContainsKey(method)) { HookEndpointManager.Modify(method, modification); modifications.Add(method, modification); } } }
/// <summary> /// /// The following method is written by max480. Thanks max! /// /// Utility method to patch "coroutine" kinds of methods with IL. /// Those methods' code reside in a compiler-generated method, and IL.Celeste.* do not allow manipulating them directly. /// </summary> /// <param name="manipulator">Method taking care of the patching</param> /// <returns>The IL hook if the actual code was found, null otherwise</returns> public static ILHook HookCoroutine(string typeName, string methodName, ILContext.Manipulator manipulator) { // get the Celeste.exe module definition Everest loaded for us ModuleDefinition celeste = Everest.Relinker.SharedRelinkModuleMap["Celeste.Mod.mm"]; // get the type TypeDefinition type = celeste.GetType(typeName); if (type == null) { return(null); } // the "coroutine" method is actually a nested type tracking the coroutine's state // (to make it restart from where it stopped when MoveNext() is called). // what we see in ILSpy and what we want to hook is actually the MoveNext() method in this nested type. foreach (TypeDefinition nest in type.NestedTypes) { if (nest.Name.StartsWith("<" + methodName + ">d__")) { // check that this nested type contains a MoveNext() method MethodDefinition method = nest.FindMethod("System.Boolean MoveNext()"); if (method == null) { return(null); } // we found it! let's convert it into basic System.Reflection stuff and hook it. //Logger.Log("ExtendedVariantMode/ExtendedVariantsModule", $"Building IL hook for method {method.FullName} in order to mod {typeName}.{methodName}()"); Type reflectionType = typeof(Player).Assembly.GetType(typeName); Type reflectionNestedType = reflectionType.GetNestedType(nest.Name, BindingFlags.NonPublic); MethodBase moveNextMethod = reflectionNestedType.GetMethod("MoveNext", BindingFlags.NonPublic | BindingFlags.Instance); return(new ILHook(moveNextMethod, manipulator)); } } return(null); }
public void TestDynamicHookGen() { Assert.Equal(42, TestMethod(1, 2)); On.MonoMod.UnitTest.DynamicHookGenTest.TestMethod += (Func <Func <int, int, int>, int, int, int>)TestMethodHook; Assert.Equal(42 + 1, TestMethod(1, 2)); Func <Func <int, int, int>, int, int, int> hook = (orig, a, b) => { return(orig(a, b) + b); }; On.MonoMod.UnitTest.DynamicHookGenTest.TestMethod += hook; Assert.Equal(42 + 1 + 2, TestMethod(1, 2)); ILContext.Manipulator manip = ctx => { ILCursor c = new ILCursor(ctx).GotoNext(i => i.MatchRet()); c.Emit(OpCodes.Ldc_I4_3); c.Emit(OpCodes.Add); }; IL.MonoMod.UnitTest.DynamicHookGenTest.TestMethod += manip; Assert.Equal(42 + 1 + 2 + 3, TestMethod(1, 2)); On(typeof(DynamicHookGenTest)).TestMethod -= (Func <Func <int, int, int>, int, int, int>)TestMethodHook; Assert.Equal(42 + 2 + 3, TestMethod(1, 2)); OnOrIL(typeof(DynamicHookGenTest)).TestMethod -= hook; Assert.Equal(42 + 3, TestMethod(1, 2)); OnOrIL(typeof(DynamicHookGenTest)).TestMethod -= manip; Assert.Equal(42, TestMethod(1, 2)); }
public void Remove_IL(ILContext.Manipulator hook) => HookEndpointManager.Unmodify(this.method, hook);
public void Add_IL(ILContext.Manipulator hook) => HookEndpointManager.Modify(this.method, hook);
private static IDetour _NewILHook(MethodBase from, ILContext.Manipulator to) => new ILHook(from, to);