static void setEnabled(Type patchType, HarmonyPatch patch, bool enabled) { $"OptionalPatches: setEnabled {patchType} => {enabled}".logDbg(); var method = patch.info.getTargetMethod(); if (method == null) { "OptionalPatches: method is null!".logError(); return; } var prefix = patchType.method("Prefix"); var postfix = patchType.method("Postfix"); var transpiler = patchType.method("Transpiler"); var patches = HarmonyHelper.getPatchInfo(method); bool prefixActive = patches.isPatchedBy(prefix); bool postfixActive = patches.isPatchedBy(postfix); bool transpilerActive = patches.isPatchedBy(transpiler); if (enabled) { if (!prefixActive && !postfixActive && !transpilerActive) { HarmonyHelper.patch(method, prefix, postfix, transpiler); } } else { // need to check if this is actual patches to avoid unnecessary updates in harmony (with transpilers especially) if (prefixActive) { HarmonyHelper.unpatch(method, prefix); } if (postfixActive) { HarmonyHelper.unpatch(method, postfix); } if (transpilerActive) { HarmonyHelper.unpatch(method, transpiler); } } }
public void initDetours() { // TODO realize detouring with annotations if (!DetourInited) { Log.Info("Init detours"); bool detourFailed = false; try { Log.Info("Deploying Harmony patches"); #if DEBUG HarmonyInstance.DEBUG = true; #endif Assembly assembly = Assembly.GetExecutingAssembly(); HarmonyMethodStates.Clear(); // Harmony attribute-driven patching Log.Info($"Performing Harmony attribute-driven patching"); HarmonyInst = HarmonyInstance.Create(HARMONY_ID); HarmonyInst.PatchAll(assembly); foreach (Type type in assembly.GetTypes()) { object[] attributes = type.GetCustomAttributes(typeof(HarmonyPatch), true); if (attributes.Length <= 0) { continue; } foreach (object attr in attributes) { HarmonyPatch harmonyPatchAttr = (HarmonyPatch)attr; MethodBase info = HarmonyUtil.GetOriginalMethod(harmonyPatchAttr.info); IntPtr ptr = info.MethodHandle.GetFunctionPointer(); RedirectCallsState state = RedirectionHelper.GetState(ptr); HarmonyMethodStates[info] = state; } } // Harmony manual patching Log.Info($"Performing Harmony manual patching"); foreach (ManualHarmonyPatch manualPatch in ManualHarmonyPatches) { Log.Info($"Manually patching method {manualPatch.method.DeclaringType.FullName}.{manualPatch.method.Name}. Prefix: {manualPatch.prefix?.method}, Postfix: {manualPatch.postfix?.method}, Transpiler: {manualPatch.transpiler?.method}"); HarmonyInst.Patch(manualPatch.method, manualPatch.prefix, manualPatch.postfix, manualPatch.transpiler); IntPtr ptr = manualPatch.method.MethodHandle.GetFunctionPointer(); RedirectCallsState state = RedirectionHelper.GetState(ptr); HarmonyMethodStates[manualPatch.method] = state; } } catch (Exception e) { Log.Error("Could not deploy Harmony patches"); Log.Info(e.ToString()); Log.Info(e.StackTrace); detourFailed = true; } try { Log.Info("Deploying attribute-driven detours"); DetouredMethodStates = AssemblyRedirector.Deploy(); } catch (Exception e) { Log.Error("Could not deploy attribute-driven detours"); Log.Info(e.ToString()); Log.Info(e.StackTrace); detourFailed = true; } if (detourFailed) { Log.Info("Detours failed"); Singleton <SimulationManager> .instance.m_ThreadingWrapper.QueueMainThread(() => { UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("TM:PE failed to load", "Traffic Manager: President Edition failed to load. You can continue playing but it's NOT recommended. Traffic Manager will not work as expected.", true); }); } else { Log.Info("Detours successful"); } DetourInited = true; } }
public bool CanApplyPatches() { var conflict = new List <string>(new string[] { "Actor_cp", "Actor_hp", "Actor_Vp", "ActorDeadDropModule_Handler", "ItemBag_ChangeMoney", "Player_AddExp" }); foreach (var ass in UnityModManager.modEntries) { if (ass.Info.DisplayName == "Portia Helper") { continue; } string origin = ass.Info.DisplayName; foreach (var tp in ass.Assembly.GetTypes()) { if (!Attribute.IsDefined(tp, typeof(HarmonyPatch))) { continue; } object[] attrs = tp.GetCustomAttributes(true); string methodName = ""; string typeName = ""; foreach (var attr in attrs) { HarmonyPatch hpAttr = attr as HarmonyPatch; if (hpAttr is null) { continue; } if (methodName == "" && hpAttr.info.methodName != "") { methodName = hpAttr.info.methodName; } if (typeName == "" && hpAttr.info.declaringType.Name != "") { typeName = hpAttr.info.declaringType.Name; } if (methodName != "" && typeName != "") { break; } } if (methodName != "" && typeName != "") { string key = $"{typeName}_{methodName}"; if (conflict.IndexOf(key) < 0) { continue; } if (_takenPatches.ContainsKey(key)) { continue; } _takenPatches.Add(key, origin); } } } return(_takenPatches.Count == 0); }