Beispiel #1
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();
                }
            }
        }
        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);
        }
        public void Test_SimpleAttributes()
        {
            var type  = typeof(AllAttributesClass);
            var infos = HarmonyMethodExtensions.GetFromType(type);
            var info  = HarmonyMethod.Merge(infos);

            Assert.NotNull(info);
            Assert.AreEqual(typeof(string), info.GetDeclaringType());
            Assert.AreEqual("foobar", info.methodName);
            Assert.NotNull(info.argumentTypes);
            Assert.AreEqual(2, info.argumentTypes.Length);
            Assert.AreEqual(typeof(float), info.argumentTypes[0]);
            Assert.AreEqual(typeof(string), info.argumentTypes[1]);
        }
Beispiel #4
0
        internal static bool ApplyPatch(Type type, String featureName)
        {
            try
            {
                if (typesPatched.ContainsKey(type))
                {
                    return(typesPatched[type]);
                }

                var patchInfo = HarmonyMethodExtensions.GetHarmonyMethods(type);
                if (patchInfo == null || !patchInfo.Any())
                {
                    Log.Error($"Failed to apply patch {type}: could not find Harmony attributes");
                    failedPatches.Add(featureName);
                    typesPatched.Add(type, false);
                    return(false);
                }
                var processor = new PatchProcessor(harmonyInstance, type, HarmonyMethod.Merge(patchInfo));
                var patch     = Enumerable.FirstOrDefault(processor.Patch());
                if (patch == null)
                {
                    Log.Error($"Failed to apply patch {type}: no dynamic method generated");
                    failedPatches.Add(featureName);
                    typesPatched.Add(type, false);
                    return(false);
                }
                typesPatched.Add(type, true);
                return(true);
            }
            catch (Exception e)
            {
                Log.Error($"Failed to apply patch {type}: {e}");
                failedPatches.Add(featureName);
                typesPatched.Add(type, false);
                return(false);
            }
        }
Beispiel #5
0
        public void Enable(UnityModManager.ModEntry modEntry, Assembly assembly)
        {
            _logger = modEntry.Logger;

            if (Enabled)
            {
                Debug("Already enabled.");
                return;
            }

            using ProcessLogger process = new(_logger);
            try {
                process.Log("Enabling.");
                var dict = Harmony.VersionInfo(out var myVersion);
                process.Log($"Harmony version: {myVersion}");
                foreach (var entry in dict)
                {
                    process.Log($"Mod {entry.Key} loaded with Harmony version {entry.Value}");
                }

                process.Log("Loading settings.");
                modEntry.OnSaveGUI += HandleSaveGUI;
                Version             = modEntry.Version;
                Settings            = UnityModManager.ModSettings.Load <TSettings>(modEntry);
                Core = new TCore();

                var types = assembly.GetTypes();

                if (!Patched)
                {
                    Harmony harmonyInstance = new(modEntry.Info.Id);
                    foreach (var type in types)
                    {
                        var harmonyMethods = HarmonyMethodExtensions.GetFromType(type);
                        if (harmonyMethods != null && harmonyMethods.Count() > 0)
                        {
                            process.Log($"Patching: {type.FullName}");
                            try {
                                var patchProcessor = harmonyInstance.CreateClassProcessor(type);
                                patchProcessor.Patch();
                            }
                            catch (Exception e) {
                                Error(e);
                            }
                        }
                    }
                    Patched = true;
                }

                Enabled = true;

                process.Log("Registering events.");
                _eventHandlers = types.Where(type => type != typeof(TCore) &&
                                             !type.IsInterface && !type.IsAbstract && typeof(IModEventHandler).IsAssignableFrom(type))
                                 .Select(type => Activator.CreateInstance(type, true) as IModEventHandler).ToList();
                if (Core is IModEventHandler core)
                {
                    _eventHandlers.Add(core);
                }
                _eventHandlers.Sort((x, y) => x.Priority - y.Priority);

                process.Log("Raising events: OnEnable()");
                for (var i = 0; i < _eventHandlers.Count; i++)
                {
                    _eventHandlers[i].HandleModEnable();
                }
            }
            catch (Exception e) {
                Error(e);
                Disable(modEntry, true);
                throw;
            }

            process.Log("Enabled.");
        }
        /// <summary>
        /// Applies all patches specified in the type.
        /// </summary>
        /// <param name="type">The type to scan.</param>
        /// <param name="harmonyInstance">The HarmonyInstance to use.</param>
        public static HarmonyLib.Harmony PatchAll(Type type, HarmonyLib.Harmony harmonyInstance = null)
        {
            HarmonyLib.Harmony instance = harmonyInstance ?? new HarmonyLib.Harmony($"harmonywrapper-auto-{Guid.NewGuid()}");

            type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Do(method =>
            {
                List <HarmonyMethod> patchAttributeMethods = HarmonyMethodExtensions.GetFromMethod(method);
                if (patchAttributeMethods != null && patchAttributeMethods.Any())
                {
                    object[] attributes = method.GetCustomAttributes(true);

                    HarmonyMethod combinedInfo = HarmonyMethod.Merge(patchAttributeMethods);

                    if (attributes.Any(x => x is ParameterByRefAttribute))
                    {
                        ParameterByRefAttribute byRefAttribute = (ParameterByRefAttribute)attributes.First(x => x is ParameterByRefAttribute);

                        foreach (int index in byRefAttribute.ParameterIndices)
                        {
                            combinedInfo.argumentTypes[index] = combinedInfo.argumentTypes[index].MakeByRefType();
                        }
                    }

                    HarmonyMethod prefix     = null;
                    HarmonyMethod transpiler = null;
                    HarmonyMethod postfix    = null;

                    if (attributes.Any(x => x is HarmonyPrefix))
                    {
                        prefix = new HarmonyMethod(method);
                    }

                    if (attributes.Any(x => x is HarmonyTranspiler))
                    {
                        transpiler = new HarmonyMethod(method);
                    }

                    if (attributes.Any(x => x is HarmonyPostfix))
                    {
                        postfix = new HarmonyMethod(method);
                    }


                    List <HarmonyMethod> completeMethods = patchAttributeMethods.Where(x => x.declaringType != null && x.methodName != null).ToList();

                    if (patchAttributeMethods.All(x => x.declaringType != combinedInfo.declaringType && x.methodName != combinedInfo.methodName))
                    {
                        completeMethods.Add(combinedInfo);
                    }

                    List <MethodBase> originalMethods = new List <MethodBase>();

                    foreach (HarmonyMethod methodToPatch in completeMethods)
                    {
                        if (!methodToPatch.methodType.HasValue)
                        {
                            methodToPatch.methodType = MethodType.Normal;
                        }

                        MethodBase originalMethod = GetOriginalMethod(methodToPatch);

                        if (originalMethod == null)
                        {
                            throw new ArgumentException($"Null method for attribute: \n" +
                                                        $"Type={methodToPatch.declaringType.FullName ?? "<null>"}\n" +
                                                        $"Name={methodToPatch.methodName ?? "<null>"}\n" +
                                                        $"MethodType={(methodToPatch.methodType.HasValue ? methodToPatch.methodType.Value.ToString() : "<null>")}\n" +
                                                        $"Args={(methodToPatch.argumentTypes == null ? "<null>" : string.Join(",", methodToPatch.argumentTypes.Select(x => x.FullName).ToArray()))}");
                        }

                        originalMethods.Add(originalMethod);
                    }

                    PatchProcessor processor = new PatchProcessor(instance)
                                               .SetOriginals(originalMethods)
                                               .AddPrefix(prefix)
                                               .AddPostfix(postfix)
                                               .AddTranspiler(transpiler);
                    processor.Patch();
                }
            });

            return(instance);
        }