public override void OnBeforeSimulationFrame() { base.OnBeforeSimulationFrame(); if (firstFrame) { firstFrame = false; Log.Info($"ThreadingExtension.OnBeforeSimulationFrame: First frame detected. Checking detours."); List <string> missingDetours = new List <string>(); foreach (Detour detour in LoadingExtension.Detours) { if (!RedirectionHelper.IsRedirected(detour.OriginalMethod, detour.CustomMethod)) { missingDetours.Add($"<Manual> {detour.OriginalMethod.DeclaringType.Name}.{detour.OriginalMethod.Name} with {detour.OriginalMethod.GetParameters().Length} parameters ({detour.OriginalMethod.DeclaringType.AssemblyQualifiedName})"); } } foreach (KeyValuePair <MethodBase, RedirectCallsState> entry in LoadingExtension.HarmonyMethodStates) { MethodBase method = entry.Key; RedirectCallsState oldState = entry.Value; RedirectCallsState newState = RedirectionHelper.GetState(method.MethodHandle.GetFunctionPointer()); if (!oldState.Equals(newState)) { missingDetours.Add($"<Harmony> {method.DeclaringType.Name}.{method.Name} with {method.GetParameters().Length} parameters ({method.DeclaringType.AssemblyQualifiedName})"); } } Log.Info($"ThreadingExtension.OnBeforeSimulationFrame: First frame detected. Detours checked. Result: {missingDetours.Count} missing detours"); if (missingDetours.Count > 0) { string error = "Traffic Manager: President Edition detected an incompatibility with another mod! You can continue playing but it's NOT recommended. Traffic Manager will not work as expected. See TMPE.log for technical details."; Log.Error(error); string log = "The following methods were overriden by another mod:"; foreach (string missingDetour in missingDetours) { log += $"\n\t{missingDetour}"; } Log.Info(log); if (GlobalConfig.Instance.Main.ShowCompatibilityCheckErrorMessage) { Singleton <SimulationManager> .instance.m_ThreadingWrapper.QueueMainThread(() => { UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Incompatibility Issue", error, true); }); } } } if (Options.timedLightsEnabled) { tlsMan.SimulationStep(); } }
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 override void OnBeforeSimulationFrame() { base.OnBeforeSimulationFrame(); if (firstFrame) { firstFrame = false; Log.Info("ThreadingExtension.OnBeforeSimulationFrame: First frame detected. Checking detours."); List <string> missingDetours = new List <string>(); foreach (Detour detour in Detours) { if (!RedirectionHelper.IsRedirected( detour.OriginalMethod, detour.CustomMethod)) { missingDetours.Add( string.Format( "<Manual> {0}.{1} with {2} parameters ({3})", detour.OriginalMethod.DeclaringType.Name, detour.OriginalMethod.Name, detour.OriginalMethod.GetParameters().Length, detour.OriginalMethod.DeclaringType.AssemblyQualifiedName)); } } foreach (KeyValuePair <MethodBase, RedirectCallsState> entry in HarmonyMethodStates) { MethodBase method = entry.Key; RedirectCallsState oldState = entry.Value; RedirectCallsState newState = RedirectionHelper.GetState(method.MethodHandle.GetFunctionPointer()); if (!oldState.Equals(newState)) { missingDetours.Add( string.Format( "<Harmony> {0}.{1} with {2} parameters ({3})", method.DeclaringType.Name, method.Name, method.GetParameters().Length, method.DeclaringType.AssemblyQualifiedName)); } } Log.Info($"ThreadingExtension.OnBeforeSimulationFrame: First frame detected. " + $"Detours checked. Result: {missingDetours.Count} missing detours"); if (missingDetours.Count > 0) { string error = "Traffic Manager: President Edition detected an incompatibility with another " + "mod! You can continue playing but it's NOT recommended. Traffic Manager will " + "not work as expected. See TMPE.log for technical details."; Log.Error(error); string log = "The following methods were overriden by another mod:"; foreach (string missingDetour in missingDetours) { log += $"\n\t{missingDetour}"; } Log.Info(log); if (GlobalConfig.Instance.Main.ShowCompatibilityCheckErrorMessage) { Prompt.Error("TM:PE Incompatibility Issue", error); } } } if (Options.timedLightsEnabled) { tlsMan.SimulationStep(); } }