Example #1
0
        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);
            }
        }
Example #2
0
        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;
            }
        }