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]); }
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); } }
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); }