Пример #1
0
        static Main()
        {
            var harmony = new Harmony("Garthor.More_Traits");

            harmony.PatchAll();

            // Get all types in the Compatibility namespace
            var types = from x in Assembly.GetExecutingAssembly().GetTypes()
                        where x.IsClass && x.Namespace == "Garthor_More_Traits.Compatibility"
                        select x;

            // Iterate through types tagged with the PatchIfMod attribute
            foreach (var t in types)
            {
                var attr = t.GetCustomAttribute <Compatibility.PatchIfModAttribute>();
                if (attr != null && attr.IsModLoaded())
                {
                    Dictionary <MethodBase, PatchProcessor> patches = new Dictionary <MethodBase, PatchProcessor>();
                    foreach (var method in t.GetMethods())
                    {
                        foreach (var harmonyPatch in method.GetCustomAttributes <HarmonyPatch>())
                        {
                            // First add a PatchProcessor for the method we're targeting to the patches list, if not already present
                            MethodBase mb = harmonyPatch.info.declaringType.GetMethod(harmonyPatch.info.methodName);
                            if (!patches.ContainsKey(mb))
                            {
                                patches.Add(mb, new PatchProcessor(harmony, mb));
                            }
                            PatchProcessor patch = patches[mb];
                            // Next add this method to the prefix, postfix, transpiler, or finalizer lists, as appropriate
                            // (bit repetitive, but it's short and would be a bit convoluted to improve it)
                            if (method.GetCustomAttributes <HarmonyPrefix>().Any())
                            {
                                patch.AddPrefix(new HarmonyMethod(method));
                            }
                            if (method.GetCustomAttributes <HarmonyPostfix>().Any())
                            {
                                patch.AddPostfix(new HarmonyMethod(method));
                            }
                            if (method.GetCustomAttributes <HarmonyTranspiler>().Any())
                            {
                                patch.AddTranspiler(new HarmonyMethod(method));
                            }
                            if (method.GetCustomAttributes <HarmonyFinalizer>().Any())
                            {
                                patch.AddFinalizer(new HarmonyMethod(method));
                            }
                        }
                    }
                    // Apply the patches for this mod
                    foreach (PatchProcessor processor in patches.Values)
                    {
                        processor.Patch();
                    }
                }
            }
        }
Пример #2
0
        static HarmonyLoader()
        {
            // load directly embedded patches

            var harmony = new Harmony("harmony-loader-" + Guid.NewGuid().ToString("N"));

            var assembly = Assembly.GetExecutingAssembly();

            foreach (var type in assembly.GetTypes())
            {
                foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
                {
                    var harmonyMethods = HarmonyMethodExtensions.GetFromMethod(method);
                    if (harmonyMethods is null || !harmonyMethods.Any())
                    {
                        continue;
                    }
                    var merged = new HarmonyMethod()
                    {
                        methodType = MethodType.Normal
                    }.Merge(HarmonyMethod.Merge(harmonyMethods));

                    Logger.LogDebug($"found method: {method} / {merged}");

#if BepInEx
                    var proc = new PatchProcessor(harmony);
                    proc.AddOriginal(PatchProcessor.GetOriginalMethod(merged));
#elif UMM
                    var proc = new PatchProcessor(harmony, merged.GetOriginalMethod());
#endif

                    if (method.GetCustomAttributes <HarmonyTranspiler>().Any())
                    {
                        proc.AddTranspiler(method);
                    }
                    if (method.GetCustomAttributes <HarmonyPrefix>().Any())
                    {
                        proc.AddPrefix(method);
                    }
                    if (method.GetCustomAttributes <HarmonyPostfix>().Any())
                    {
                        proc.AddPostfix(method);
                    }
                    if (method.GetCustomAttributes <HarmonyFinalizer>().Any())
                    {
                        proc.AddFinalizer(method);
                    }

                    proc.Patch();
                }
            }
        }
Пример #3
0
        static HarmonyLoader()
        {
            // load directly embedded patches

            var harmony = new Harmony("harmony-loader-" + Guid.NewGuid().ToString("N"));

            var assembly = Assembly.GetExecutingAssembly();

            foreach (var type in assembly.GetTypes())
            {
                foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
                {
                    var harmonyMethods = HarmonyMethodExtensions.GetFromMethod(method);
                    if (harmonyMethods is null || !harmonyMethods.Any())
                    {
                        continue;
                    }
                    var merged = new HarmonyMethod()
                    {
                        methodType = MethodType.Normal
                    }.Merge(HarmonyMethod.Merge(harmonyMethods));

                    Logger.LogDebug($"found method: {method} / {merged}");

                    var proc = new PatchProcessor(harmony);

                    proc.AddOriginal(PatchProcessor.GetOriginalMethod(merged) /*(MethodBase) Info.OfMethod<PatchProcessor>("GetOriginalMethod").Invoke(null, new[] {merged})*/);

                    if (method.GetCustomAttributes <HarmonyTranspiler>().Any())
                    {
                        proc.AddTranspiler(method);
                    }
                    if (method.GetCustomAttributes <HarmonyPrefix>().Any())
                    {
                        proc.AddPrefix(method);
                    }
                    if (method.GetCustomAttributes <HarmonyPostfix>().Any())
                    {
                        proc.AddPostfix(method);
                    }
                    if (method.GetCustomAttributes <HarmonyFinalizer>().Any())
                    {
                        proc.AddFinalizer(method);
                    }

                    proc.Patch();
                }
            }

            // load the normal style of patches
            Harmony.CreateAndPatchAll(typeof(AutoLoadManager).Assembly);
        }
Пример #4
0
        public void TestMethod2()
        {
            var originalClass = typeof(Class2);

            Assert.IsNotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method2");

            Assert.IsNotNull(originalMethod);

            var patchClass = typeof(Class2Patch);
            var prefix     = patchClass.GetMethod("Prefix");
            var postfix    = patchClass.GetMethod("Postfix");
            var transpiler = patchClass.GetMethod("Transpiler");

            Assert.IsNotNull(prefix);
            Assert.IsNotNull(postfix);
            Assert.IsNotNull(transpiler);

            Class2Patch.ResetTest();

            var instance = new Harmony("test");

            Assert.IsNotNull(instance);

            var patcher = new PatchProcessor(instance, originalMethod);

            Assert.IsNotNull(patcher);
            patcher.AddPrefix(prefix);
            patcher.AddPostfix(postfix);
            patcher.AddTranspiler(transpiler);

            patcher.Patch();
            // unsafe
            // {
            //     var patchedCode = *(byte*) originalMethodStartPre;
            //     if (IntPtr.Size == sizeof(long))
            //         Assert.IsTrue(patchedCode == 0x48);
            //     else
            //         Assert.IsTrue(patchedCode == 0x68);
            // }

            new Class2().Method2();
            Assert.IsTrue(Class2Patch.prefixed, "Prefix was not executed");
            Assert.IsTrue(Class2Patch.originalExecuted, "Original was not executed");
            Assert.IsTrue(Class2Patch.postfixed, "Postfix was not executed");
        }
Пример #5
0
        public void TestNativePatch()
        {
            // Currently NativeDetours don't work properly on .NET Core (except when running in debug mode)
            // ¯\_(ツ)_/¯
#if NETCOREAPP3_0
            return;
#endif
            var originalClass = typeof(NativeClass);
            Assert.IsNotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Rand");
            Assert.IsNotNull(originalMethod);

            var patchClass = typeof(NativeClassPatch);
            var prefix     = patchClass.GetMethod("Prefix");
            Assert.IsNotNull(prefix);
            var postfix = patchClass.GetMethod("Postfix");
            Assert.IsNotNull(postfix);
            var transpiler = patchClass.GetMethod("Transpiler");
            Assert.IsNotNull(transpiler);

            var instance = new Harmony("test-native");
            Assert.IsNotNull(instance);

            var patcher = new PatchProcessor(instance, originalMethod);
            Assert.IsNotNull(patcher);
            patcher.AddPrefix(prefix);
            patcher.AddPostfix(postfix);
            patcher.AddTranspiler(transpiler);
            patcher.Patch();

            var result = NativeClass.Rand();
            Assert.AreEqual(-1, result);
            Assert.IsTrue(NativeClassPatch.prefixCalled, "Prefix wasn't run");
            Assert.IsTrue(NativeClassPatch.postfixCalled, "Postfix wasn't run");
            Assert.IsTrue(NativeClassPatch.transpilerCalled, "Transpiler wasn't run");
        }
Пример #6
0
        public bool CompileAndGenerateProcessor(string patchSource)
        {
            Unpatch();

            try
            {
                patchProcessor = ExplorerCore.Harmony.CreateProcessor(TargetMethod);

                // Dynamically compile the patch method

                var codeBuilder = new StringBuilder();

                codeBuilder.AppendLine($"public class DynamicPatch_{DateTime.Now.Ticks}");
                codeBuilder.AppendLine("{");
                codeBuilder.AppendLine(patchSource);
                codeBuilder.AppendLine("}");

                scriptEvaluator.Run(codeBuilder.ToString());

                if (ScriptEvaluator._reportPrinter.ErrorsCount > 0)
                {
                    throw new FormatException($"Unable to compile the generated patch!");
                }

                // TODO: Publicize MCS to avoid this reflection
                // Get the most recent Patch type in the source file
                var typeContainer = ((CompilationSourceFile)fi_sourceFile.GetValue(scriptEvaluator))
                                    .Containers
                                    .Last(it => it.MemberName.Name.StartsWith("DynamicPatch_"));
                // Get the TypeSpec from the TypeDefinition, then get its "MetaInfo" (System.Type)
                var patchClass = ((TypeSpec)pi_Definition.GetValue((Class)typeContainer, null)).GetMetaInfo();

                // Create the harmony patches as defined

                postfix = patchClass.GetMethod("Postfix", ReflectionUtility.FLAGS);
                if (postfix != null)
                {
                    patchProcessor.AddPostfix(new HarmonyMethod(postfix));
                }

                prefix = patchClass.GetMethod("Prefix", ReflectionUtility.FLAGS);
                if (prefix != null)
                {
                    patchProcessor.AddPrefix(new HarmonyMethod(prefix));
                }

                finalizer = patchClass.GetMethod("Finalizer", ReflectionUtility.FLAGS);
                if (finalizer != null)
                {
                    patchProcessor.AddFinalizer(new HarmonyMethod(finalizer));
                }

                transpiler = patchClass.GetMethod("Transpiler", ReflectionUtility.FLAGS);
                if (transpiler != null)
                {
                    patchProcessor.AddTranspiler(new HarmonyMethod(transpiler));
                }

                return(true);
            }
            catch (Exception ex)
            {
                ExplorerCore.LogWarning($"Exception creating patch processor for target method {TargetMethod.FullDescription()}!\r\n{ex}");
                return(false);
            }
        }
Пример #7
0
 /// <summary>
 ///     Apply a transpiler to the original method
 /// </summary>
 /// <param name="action">Transpiler to apply</param>
 /// <typeparam name="T">Transpiler delegate type</typeparam>
 /// <returns>Current patch processor</returns>
 public PatchComposer Transpiler <T>(T action) where T : Delegate
 {
     processor.AddTranspiler(GetPatchMethod(action));
     return(this);
 }
Пример #8
0
 public ProcessorInfo AddTranspiler(HarmonyMethod transpiler)
 {
     processor.AddTranspiler(transpiler);
     return(this);
 }