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) { Singleton <SimulationManager> .instance.m_ThreadingWrapper.QueueMainThread( () => { UIView .library .ShowModal <ExceptionPanel>( "ExceptionPanel").SetMessage( "Incompatibility Issue", error, true); }); } } } if (Options.timedLightsEnabled) { tlsMan.SimulationStep(); } }
public Detour(MethodInfo originalMethod, MethodInfo customMethod) { this.OriginalMethod = originalMethod; this.CustomMethod = customMethod; this.Redirect = RedirectionHelper.RedirectCalls(originalMethod, customMethod); }
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 OnUpdate(float realTimeDelta, float simulationTimeDelta) { base.OnUpdate(realTimeDelta, simulationTimeDelta); if (LoadingExtension.Instance == null) { return; } if (LoadingExtension.Instance.ToolMode != TrafficManagerMode.None && ToolsModifierControl.toolController.CurrentTool != LoadingExtension.Instance.TrafficLightTool) { LoadingExtension.Instance.SetToolMode(TrafficManagerMode.None); } if (ToolsModifierControl.toolController.CurrentTool != LoadingExtension.Instance.TrafficLightTool && LoadingExtension.Instance.UI.isVisible()) { LoadingExtension.Instance.UI.Close(); } if (!LoadingExtension.Instance.detourInited) { LoadingExtension.Instance.revertMethods[0] = RedirectionHelper.RedirectCalls( typeof(CarAI).GetMethod("CalculateSegmentPosition", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(PathUnit.Position), typeof(PathUnit.Position), typeof(uint), typeof(byte), typeof(PathUnit.Position), typeof(uint), typeof(byte), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(float).MakeByRefType() }, null), typeof(CustomCarAI).GetMethod("CalculateSegmentPosition")); LoadingExtension.Instance.revertMethods[1] = RedirectionHelper.RedirectCalls( typeof(RoadBaseAI).GetMethod("SimulationStep", new Type[] { typeof(ushort), typeof(NetNode).MakeByRefType() }), typeof(CustomRoadAI).GetMethod("SimulationStep", BindingFlags.NonPublic | BindingFlags.Instance)); LoadingExtension.Instance.revertMethods[2] = RedirectionHelper.RedirectCalls(typeof(HumanAI).GetMethod("CheckTrafficLights", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(ushort) }, null), typeof(CustomHumanAI).GetMethod("CheckTrafficLights")); LoadingExtension.Instance.revertMethods[3] = RedirectionHelper.RedirectCalls( typeof(CarAI).GetMethod("SimulationStep", new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }), typeof(CustomCarAI).GetMethod("SimulationStep", BindingFlags.NonPublic | BindingFlags.Instance)); LoadingExtension.Instance.revertMethods[4] = RedirectionHelper.RedirectCalls( typeof(PassengerCarAI).GetMethod("SimulationStep", new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }), typeof(CustomPassengerCarAI).GetMethod("SimulationStep", BindingFlags.NonPublic | BindingFlags.Instance)); LoadingExtension.Instance.revertMethods[5] = RedirectionHelper.RedirectCalls( typeof(CargoTruckAI).GetMethod("SimulationStep", new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }), typeof(CustomCargoTruckAI).GetMethod("SimulationStep", BindingFlags.NonPublic | BindingFlags.Instance)); LoadingExtension.Instance.revertMethods[6] = RedirectionHelper.RedirectCalls(typeof(CarAI).GetMethod("CalculateSegmentPosition", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(PathUnit.Position), typeof(uint), typeof(byte), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(float).MakeByRefType() }, null), typeof(CustomCarAI).GetMethod("CalculateSegmentPosition2")); //srcMethod8 = typeof(CarAI).GetMethod("StartPathFind", // BindingFlags.NonPublic | BindingFlags.Instance, // null, // new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool) }, // null); //destMethod[8 = typeof(CustomCarAI).GetMethod("StartPathFind"); //srcMethod9 = typeof (TransportLineAI).GetMethod("StartPathFind"); //destMethod[9 = typeof(CustomTransportLineAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Static); //srcMethod10 = typeof(PassengerCarAI).GetMethod("StartPathFind", // BindingFlags.NonPublic | BindingFlags.Instance, // null, // new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool) }, // null); //destMethod[10 = typeof(CustomPassengerCarAI).GetMethod("StartPathFind2"); //srcMethod11 = typeof(CargoTruckAI).GetMethod("StartPathFind", // BindingFlags.NonPublic | BindingFlags.Instance, // null, // new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool) }, // null); //destMethod[11 = typeof(CustomCargoTruckAI).GetMethod("StartPathFind2"); //LoadingExtension.Instance.revertMethods[1] = RedirectionHelper.RedirectCalls(typeof (NetNode).GetMethod("RefreshJunctionData", // BindingFlags.NonPublic | BindingFlags.Instance, // null, // new Type[] // { // typeof (ushort), typeof (int), typeof (ushort), typeof (Vector3), typeof (uint).MakeByRefType(), // typeof (RenderManager.Instance).MakeByRefType() // }, // null), // typeof (CustomNetNode).GetMethod("RefreshJunctionData")); LoadingExtension.Instance.detourInited = true; if (!LoadingExtension.Instance.nodeSimulationLoaded) { LoadingExtension.Instance.nodeSimulationLoaded = true; ToolsModifierControl.toolController.gameObject.AddComponent <CustomRoadAI>(); } } if (Input.GetKeyDown(KeyCode.Escape)) { LoadingExtension.Instance.UI.Close(); } }
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($"{detour.OriginalMethod.DeclaringType.Name}.{detour.OriginalMethod.Name} with {detour.OriginalMethod.GetParameters().Length} parameters ({detour.OriginalMethod.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 BENCHMARK using (var bm = new Benchmark(null, "RoutingManager.SimulationStep")) { #endif routeMan.SimulationStep(); #if BENCHMARK } #endif #if BENCHMARK using (var bm = new Benchmark(null, "TrafficLightSimulationManager.SimulationStep")) { #endif if (Options.timedLightsEnabled) { //try { tlsMan.SimulationStep(); /*} catch (Exception ex) { * Log.Warning($"Error occured while simulating traffic lights: {ex.ToString()}"); * }*/ } #if BENCHMARK } #endif }
public void initDetours() { Log.Warning("Init detours"); if (!LoadingExtension.Instance.DetourInited) { Log.Message("Redirecting Car AI Calculate Segment Calls"); try { LoadingExtension.Instance.OriginalMethods[0] = typeof(CarAI).GetMethod("CalculateSegmentPosition", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(PathUnit.Position), typeof(PathUnit.Position), typeof(uint), typeof(byte), typeof(PathUnit.Position), typeof(uint), typeof(byte), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(float).MakeByRefType() }, null); LoadingExtension.Instance.CustomMethods[0] = typeof(CustomCarAI).GetMethod("TmCalculateSegmentPosition"); LoadingExtension.Instance.CustomRedirects[0] = RedirectionHelper.RedirectCalls(LoadingExtension.Instance.OriginalMethods[0], LoadingExtension.Instance.CustomMethods[0]); } catch (Exception) { Log.Error("Could not redirect CarAI::CalculateSegmentPosition."); } Log.Message("Redirecting SimulationStep"); try { LoadingExtension.Instance.OriginalMethods[1] = typeof(RoadBaseAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(NetNode).MakeByRefType() }); LoadingExtension.Instance.CustomMethods[1] = typeof(CustomRoadAI).GetMethod("CustomSimulationStep"); LoadingExtension.Instance.CustomRedirects[1] = RedirectionHelper.RedirectCalls(LoadingExtension.Instance.OriginalMethods[1], LoadingExtension.Instance.CustomMethods[1]); } catch (Exception) { Log.Error("Could not redirect RoadBaseAI::SimulationStep."); } Log.Message("Redirecting Human AI Calls"); try { LoadingExtension.Instance.OriginalMethods[2] = typeof(HumanAI).GetMethod("CheckTrafficLights", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(ushort) }, null); LoadingExtension.Instance.CustomMethods[2] = typeof(CustomHumanAI).GetMethod("CustomCheckTrafficLights"); LoadingExtension.Instance.CustomRedirects[2] = RedirectionHelper.RedirectCalls(LoadingExtension.Instance.OriginalMethods[2], LoadingExtension.Instance.CustomMethods[2]); } catch (Exception) { Log.Error("Could not redirect HumanAI::CheckTrafficLights."); } if (LoadingExtension.IsPathManagerCompatible) { Log.Message("Traffic++ Not detected. Loading Pathfinder."); Log.Message("Redirecting CarAI Simulation Step Calls"); try { LoadingExtension.Instance.OriginalMethods[3] = typeof(CarAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }); LoadingExtension.Instance.CustomMethods[3] = typeof(CustomCarAI).GetMethod("TrafficManagerSimulationStep"); LoadingExtension.Instance.CustomRedirects[3] = RedirectionHelper.RedirectCalls(LoadingExtension.Instance.OriginalMethods[3], LoadingExtension.Instance.CustomMethods[3]); } catch (Exception) { Log.Error("Could not redirect CarAI::SimulationStep."); } Log.Message("Redirecting PassengerCarAI Simulation Step Calls"); try { LoadingExtension.Instance.OriginalMethods[4] = typeof(PassengerCarAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }); LoadingExtension.Instance.CustomMethods[4] = typeof(CustomPassengerCarAI).GetMethod("CustomSimulationStep"); LoadingExtension.Instance.CustomRedirects[4] = RedirectionHelper.RedirectCalls(LoadingExtension.Instance.OriginalMethods[4], LoadingExtension.Instance.CustomMethods[4]); } catch (Exception) { Log.Error("Could not redirect PassengerCarAI::SimulationStep."); } Log.Message("Redirecting CargoTruckAI Simulation Step Calls"); try { LoadingExtension.Instance.OriginalMethods[5] = typeof(CargoTruckAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }); LoadingExtension.Instance.CustomMethods[5] = typeof(CustomCargoTruckAI).GetMethod("CustomSimulationStep"); LoadingExtension.Instance.CustomRedirects[5] = RedirectionHelper.RedirectCalls(LoadingExtension.Instance.OriginalMethods[5], LoadingExtension.Instance.CustomMethods[5]); } catch (Exception) { Log.Error("Could not redirect CargoTruckAI::SimulationStep."); } Log.Message("Redirection CarAI Calculate Segment Position calls for non-Traffic++"); try { LoadingExtension.Instance.OriginalMethods[6] = typeof(CarAI).GetMethod("CalculateSegmentPosition", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(PathUnit.Position), typeof(uint), typeof(byte), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(float).MakeByRefType() }, null); LoadingExtension.Instance.CustomMethods[6] = typeof(CustomCarAI).GetMethod("TmCalculateSegmentPositionPathFinder"); LoadingExtension.Instance.CustomRedirects[6] = RedirectionHelper.RedirectCalls(LoadingExtension.Instance.OriginalMethods[6], LoadingExtension.Instance.CustomMethods[6]); } catch (Exception) { Log.Error("Could not redirect CarAI::CalculateSegmentPosition"); } } LoadingExtension.Instance.DetourInited = true; } }