public void LoadDetour(MethodInfo method) { // Setup variables DetourAttribute attribute = (DetourAttribute)Attribute.GetCustomAttribute(method, typeof(DetourAttribute)); // Do checks if (attribute == null) { return; } if (!attribute.MethodFound) { return; } if (Detours.Count(a => a.Key.Method == attribute.Method) > 0) { return; } try { DetourWrapper wrapper = new DetourWrapper(attribute.Method, method, attribute); wrapper.Detour(); Detours.Add(attribute, wrapper); } catch (Exception ex) { PointBlankLogging.LogError("Error detouring: " + method.Name, ex); } }
public void initDetours() { if (!LoadingExtension.Instance.DetourInited) { Log.Info("Init detours"); bool detourFailed = false; Log.Info("Redirecting Vehicle AI Calculate Segment Calls (1)"); try { Detours.Add(new Detour(typeof(VehicleAI).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(int), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(float).MakeByRefType() }, null), typeof(CustomVehicleAI).GetMethod("CustomCalculateSegmentPosition"))); } catch (Exception) { Log.Error("Could not redirect VehicleAI::CalculateSegmentPosition (1)."); detourFailed = true; } Log.Info("Redirecting Vehicle AI Calculate Segment Calls (2)"); try { Detours.Add(new Detour(typeof(VehicleAI).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), typeof(CustomVehicleAI).GetMethod("CustomCalculateSegmentPositionPathFinder"))); } catch (Exception) { Log.Error("Could not redirect VehicleAI::CalculateSegmentPosition (2)."); detourFailed = true; } Log.Info("Redirecting TramBaseAI Calculate Segment Calls (2)"); try { Detours.Add(new Detour(typeof(TramBaseAI).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), typeof(CustomTramBaseAI).GetMethod("CustomCalculateSegmentPositionPathFinder"))); } catch (Exception) { Log.Error("Could not redirect TramBaseAI::CalculateSegmentPosition (2)."); detourFailed = true; } Log.Info("Redirecting RoadBaseAI.SimulationStep for nodes"); try { Detours.Add(new Detour(typeof(RoadBaseAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(NetNode).MakeByRefType() }), typeof(CustomRoadAI).GetMethod("CustomNodeSimulationStep"))); } catch (Exception) { Log.Error("Could not redirect RoadBaseAI::SimulationStep."); detourFailed = true; } Log.Info("Redirecting RoadBaseAI.SimulationStep for segments"); try { Detours.Add(new Detour(typeof(RoadBaseAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(NetSegment).MakeByRefType() }), typeof(CustomRoadAI).GetMethod("CustomSegmentSimulationStep"))); } catch (Exception) { Log.Error("Could not redirect RoadBaseAI::SimulationStep."); } Log.Info("Redirecting Human AI Calls"); try { Detours.Add(new Detour(typeof(HumanAI).GetMethod("CheckTrafficLights", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(ushort) }, null), typeof(CustomHumanAI).GetMethod("CustomCheckTrafficLights"))); } catch (Exception) { Log.Error("Could not redirect HumanAI::CheckTrafficLights."); detourFailed = true; } Log.Info("Redirecting CarAI Simulation Step Calls"); try { Detours.Add(new Detour(typeof(CarAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }), typeof(CustomCarAI).GetMethod("TrafficManagerSimulationStep"))); } catch (Exception) { Log.Error("Could not redirect CarAI::SimulationStep."); detourFailed = true; } Log.Info("Redirecting PassengerCarAI Simulation Step Calls"); try { Detours.Add(new Detour(typeof(PassengerCarAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }), typeof(CustomPassengerCarAI).GetMethod("CustomSimulationStep"))); } catch (Exception) { Log.Error("Could not redirect PassengerCarAI::SimulationStep."); detourFailed = true; } Log.Info("Redirecting CargoTruckAI Simulation Step Calls"); try { Detours.Add(new Detour(typeof(CargoTruckAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }), typeof(CustomCargoTruckAI).GetMethod("CustomSimulationStep"))); } catch (Exception) { Log.Error("Could not redirect CargoTruckAI::SimulationStep."); detourFailed = true; } Log.Info("Redirecting TrainAI Simulation Step Calls"); try { Detours.Add(new Detour(typeof(TrainAI).GetMethod("SimulationStep", new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3) }), typeof(CustomTrainAI).GetMethod("TrafficManagerSimulationStep"))); } catch (Exception) { Log.Error("Could not redirect TrainAI::SimulationStep."); detourFailed = true; } Log.Info("Redirection TramBaseAI::SimulationStep calls"); try { Detours.Add(new Detour(typeof(TramBaseAI).GetMethod("SimulationStep", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), }, null), typeof(CustomTramBaseAI).GetMethod("CustomSimulationStep"))); } catch (Exception) { Log.Error("Could not redirect TramBaseAI::SimulationStep"); detourFailed = true; } /*++i; * Log._Debug("Redirecting Train AI Calculate Segment Calls"); * try { * LoadingExtension.Instance.OriginalMethods[i] = typeof(TrainAI).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[i] = typeof(CustomTrainAI).GetMethod("TmCalculateSegmentPosition"); * LoadingExtension.Instance.CustomRedirects[i] = RedirectionHelper.RedirectCalls(LoadingExtension.Instance.OriginalMethods[i], LoadingExtension.Instance.CustomMethods[i]); * } catch (Exception) { * Log.Error("Could not redirect TrainAI::CalculateSegmentPosition (1)"); * detourFailed = true; * }*/ Log.Info("Redirecting Car AI Calculate Segment Calls"); try { Detours.Add(new Detour(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(int), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(float).MakeByRefType() }, null), typeof(CustomCarAI).GetMethod("CustomCalculateSegmentPosition"))); } catch (Exception) { Log.Error("Could not redirect CarAI::CalculateSegmentPosition."); detourFailed = true; } Log.Info("Redirection TramBaseAI Calculate Segment Position calls"); try { Detours.Add(new Detour(typeof(TramBaseAI).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(int), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(float).MakeByRefType() }, null), typeof(CustomTramBaseAI).GetMethod("CustomCalculateSegmentPosition"))); } catch (Exception) { Log.Error("Could not redirect TramBaseAI::CalculateSegmentPosition"); detourFailed = true; } if (IsPathManagerCompatible) { Log.Info("Redirection CarAI Calculate Segment Position calls for non-Traffic++"); try { Detours.Add(new Detour(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), typeof(CustomCarAI).GetMethod("CustomCalculateSegmentPositionPathFinder"))); } catch (Exception) { Log.Error("Could not redirect CarAI::CalculateSegmentPosition"); detourFailed = true; } Log.Info("Redirection TrainAI Calculate Segment Position calls for non-Traffic++"); try { Detours.Add(new Detour(typeof(TrainAI).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), typeof(CustomTrainAI).GetMethod("TmCalculateSegmentPositionPathFinder"))); } catch (Exception) { Log.Error("Could not redirect TrainAI::CalculateSegmentPosition (2)"); detourFailed = true; } Log.Info("Redirection AmbulanceAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(AmbulanceAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool) }, null), typeof(CustomAmbulanceAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect AmbulanceAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection BusAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(BusAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool) }, null), typeof(CustomBusAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect BusAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection CarAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(CarAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool) }, null), typeof(CustomCarAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect CarAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection CargoTruckAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(CargoTruckAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool) }, null), typeof(CustomCargoTruckAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect CargoTruckAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection FireTruckAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(FireTruckAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool) }, null), typeof(CustomFireTruckAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect FireTruckAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection PassengerCarAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(PassengerCarAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool) }, null), typeof(CustomPassengerCarAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect PassengerCarAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection PoliceCarAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(PoliceCarAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool) }, null), typeof(CustomPoliceCarAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect PoliceCarAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection TaxiAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(TaxiAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool) }, null), typeof(CustomTaxiAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect TaxiAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection TrainAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(TrainAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool) }, null), typeof(CustomTrainAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect TrainAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection CitizenAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(CitizenAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(CitizenInstance).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(VehicleInfo) }, null), typeof(CustomCitizenAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect CitizenAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection TransportLineAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(TransportLineAI).GetMethod("StartPathFind", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(ushort), typeof(NetSegment).MakeByRefType(), typeof(ItemClass.Service), typeof(VehicleInfo.VehicleType), typeof(bool) }, null), typeof(CustomTransportLineAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect TransportLineAI::StartPathFind"); detourFailed = true; } Log.Info("Redirection TramBaseAI::StartPathFind calls"); try { Detours.Add(new Detour(typeof(TramBaseAI).GetMethod("StartPathFind", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(bool) }, null), typeof(CustomTramBaseAI).GetMethod("CustomStartPathFind"))); } catch (Exception) { Log.Error("Could not redirect TramBaseAI::StartPathFind"); detourFailed = true; } } Log.Info("Redirection RoadBaseAI::SetTrafficLightState calls"); try { Detours.Add(new Detour(typeof(RoadBaseAI).GetMethod("SetTrafficLightState", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(ushort), typeof(NetSegment).MakeByRefType(), typeof(uint), typeof(RoadBaseAI.TrafficLightState), typeof(RoadBaseAI.TrafficLightState), typeof(bool), typeof(bool) }, null), typeof(CustomRoadAI).GetMethod("CustomSetTrafficLightState"))); } catch (Exception) { Log.Error("Could not redirect RoadBaseAI::SetTrafficLightState"); detourFailed = true; } Log.Info("Reverse-Redirection CustomTrainAI::CheckOverlap calls (1)"); try { Detours.Add(new Detour(typeof(CustomTrainAI).GetMethod("CheckOverlap", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Segment3), typeof(ushort) }, null), typeof(TrainAI).GetMethod("CheckOverlap", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Segment3), typeof(ushort) }, null))); } catch (Exception) { Log.Error("Could not reverse-redirect CustomRoadBaseAI::CheckOverlap (1)"); detourFailed = true; } Log.Info("Reverse-Redirection CustomTrainAI::CheckOverlap calls (2)"); try { Detours.Add(new Detour(typeof(CustomTrainAI).GetMethod("CheckOverlap", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Segment3), typeof(ushort), typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(bool).MakeByRefType(), typeof(Vector3), typeof(Vector3) }, null), typeof(TrainAI).GetMethod("CheckOverlap", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(Segment3), typeof(ushort), typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(bool).MakeByRefType(), typeof(Vector3), typeof(Vector3) }, null))); } catch (Exception) { Log.Error("Could not reverse-redirect CustomRoadBaseAI::CheckOverlap (2)"); detourFailed = true; } Log.Info("Redirection TrainAI::CheckNextLane calls"); try { Detours.Add(new Detour(typeof(TrainAI).GetMethod("CheckNextLane", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(float).MakeByRefType(), typeof(PathUnit.Position), typeof(uint), typeof(byte), typeof(PathUnit.Position), typeof(uint), typeof(byte), typeof(Bezier3) }, null), typeof(CustomTrainAI).GetMethod("CustomCheckNextLane"))); } catch (Exception) { Log.Error("Could not redirect TrainAI::CheckNextLane"); detourFailed = true; } if (detourFailed) { Log.Info("Detours failed"); UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Incompatibility Issue", "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.", true); } else { Log.Info("Detours successful"); } LoadingExtension.Instance.DetourInited = true; } }