diff --git a/README.md b/README.md index 66b80754..b48cdcb6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,15 @@ A work-in-progress modification for **Cities: Skylines** to add additional traffic control # Changelog +1.7.3, 07/29/2016: +- Added the possibility to enable/disable mod features (e.g. for performance reasons) +- Bugfix: Vehicle type determination was incorrect (fixed u-turning trams/trains, stuck vehicles) +- Bugfix: Clicking on a train/tram node with the lane connector tool led to an uncorrectable error (thanks to @noaccount for reporting this problem) +- Further code improvements + +1.7.2, 07/26/2016: +- Optimized UI overlay performance + 1.7.1, 07/24/2016: - Reverted "Busses now may only ignore lane arrows if driving on a bus lane" for now - Bugfix: Trains were not despawning if no path could be calculated diff --git a/TLM/TLM/Custom/AI/CustomAmbulanceAI.cs b/TLM/TLM/Custom/AI/CustomAmbulanceAI.cs index f883df0c..2cbe953b 100644 --- a/TLM/TLM/Custom/AI/CustomAmbulanceAI.cs +++ b/TLM/TLM/Custom/AI/CustomAmbulanceAI.cs @@ -10,6 +10,9 @@ namespace TrafficManager.Custom.AI { class CustomAmbulanceAI : CarAI { public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { + ExtVehicleType vehicleType = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0 ? ExtVehicleType.Emergency : ExtVehicleType.Service; + VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType = vehicleType; + VehicleInfo info = this.m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; PathUnit.Position startPosA; @@ -29,7 +32,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto endPosB = default(PathUnit.Position); } uint path; - if (Singleton.instance.CreatePath((vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0 ? ExtVehicleType.Emergency : ExtVehicleType.Service, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { + if (Singleton.instance.CreatePath(vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); } diff --git a/TLM/TLM/Custom/AI/CustomBusAI.cs b/TLM/TLM/Custom/AI/CustomBusAI.cs index 837b5f03..a975f875 100644 --- a/TLM/TLM/Custom/AI/CustomBusAI.cs +++ b/TLM/TLM/Custom/AI/CustomBusAI.cs @@ -17,6 +17,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto bool recalcRequested = state.PathRecalculationRequested; state.PathRecalculationRequested = false; #endif + VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType = ExtVehicleType.Bus; VehicleInfo info = this.m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; @@ -41,7 +42,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto #if PATHRECALC recalcRequested, #endif - ExtVehicleType.Bus, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { + ExtVehicleType.Bus, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); } diff --git a/TLM/TLM/Custom/AI/CustomCarAI.cs b/TLM/TLM/Custom/AI/CustomCarAI.cs index 5d762311..cbd1fcbc 100644 --- a/TLM/TLM/Custom/AI/CustomCarAI.cs +++ b/TLM/TLM/Custom/AI/CustomCarAI.cs @@ -14,7 +14,7 @@ using TrafficManager.State; namespace TrafficManager.Custom.AI { - internal class CustomCarAI : CarAI { // correct would be to inherit from VehicleAI (in order to keep the correct references to `base`) + public class CustomCarAI : CarAI { // correct would be to inherit from VehicleAI (in order to keep the correct references to `base`) public void Awake() { } @@ -35,10 +35,18 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vect VehicleState state = VehicleStateManager._GetVehicleState(vehicleId); #endif + PathManager pathMan = Singleton.instance; +#if DEBUG + if (!Options.disableSomething1) { + Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}) called. flags: {vehicleData.m_flags} pfFlags: {pathMan.m_pathUnits.m_buffer[vehicleData.m_path].m_pathFindFlags}"); + } +#endif + if ((vehicleData.m_flags & Vehicle.Flags.WaitingPath) != 0) { - PathManager instance = Singleton.instance; - byte pathFindFlags = instance.m_pathUnits.m_buffer[(int)((UIntPtr)vehicleData.m_path)].m_pathFindFlags; + PathManager pathManager = Singleton.instance; + byte pathFindFlags = pathManager.m_pathUnits.m_buffer[vehicleData.m_path].m_pathFindFlags; if ((pathFindFlags & PathUnit.FLAG_READY) != 0) { + #if USEPATHWAITCOUNTER state.PathWaitCounter = 0; // NON-STOCK CODE #endif @@ -47,7 +55,6 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vect vehicleData.m_flags &= ~Vehicle.Flags.Arriving; this.PathfindSuccess(vehicleId, ref vehicleData); this.TrySpawn(vehicleId, ref vehicleData); - VehicleStateManager.OnPathFindReady(vehicleId, ref vehicleData); // NON-STOCK CODE } else if ((pathFindFlags & PathUnit.FLAG_FAILED) != 0 || vehicleData.m_path == 0 #if USEPATHWAITCOUNTER || ((pathFindFlags & PathUnit.FLAG_CREATED) != 0 && state.PathWaitCounter == ushort.MaxValue) @@ -76,17 +83,24 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vect } } - try { - VehicleStateManager.LogTraffic(vehicleId, ref vehicleData, true); - } catch (Exception e) { - Log.Error("CarAI CustomSimulationStep Error: " + e.ToString()); + /// NON-STOCK CODE START /// + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); + if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { + try { + vehStateManager.UpdateVehiclePos(vehicleId, ref vehicleData); + } catch (Exception e) { + Log.Error("CarAI CustomSimulationStep Error: " + e.ToString()); + } } - try { - VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData); - } catch (Exception e) { - Log.Error("CarAI CustomSimulationStep Error: " + e.ToString()); + if (!Options.isStockLaneChangerUsed()) { + try { + vehStateManager.LogTraffic(vehicleId, ref vehicleData, true); + } catch (Exception e) { + Log.Error("CarAI CustomSimulationStep Error: " + e.ToString()); + } } + /// NON-STOCK CODE END /// Vector3 lastFramePosition = vehicleData.GetLastFramePosition(); int lodPhysics; @@ -131,12 +145,37 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vect #endif } + public override bool TrySpawn(ushort vehicleID, ref Vehicle vehicleData) { + if ((vehicleData.m_flags & Vehicle.Flags.Spawned) != (Vehicle.Flags)0) { + return true; + } + if (CustomCarAI.CheckOverlap(vehicleData.m_segment, 0, 1000f)) { + vehicleData.m_flags |= Vehicle.Flags.WaitingSpace; + return false; + } + vehicleData.Spawn(vehicleID); + vehicleData.m_flags &= ~Vehicle.Flags.WaitingSpace; + + // NON-STOCK CODE START + if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { + VehicleStateManager.Instance().OnVehicleSpawned(vehicleID, ref vehicleData); + } + // NON-STOCK CODE END + + return true; + } + + private static bool CheckOverlap(Segment3 segment, ushort ignoreVehicle, float maxVelocity) { + Log.Error("CustomCarAI.CheckOverlap called"); + return false; + } + public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { - if (Options.simAccuracy <= 1) { + if ((Options.prioritySignsEnabled || Options.timedLightsEnabled) && Options.simAccuracy <= 1) { try { - VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position); + VehicleStateManager.Instance().UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position); } catch (Exception e) { Log.Error("CarAI CustomCalculateSegmentPosition Error: " + e.ToString()); } @@ -191,22 +230,13 @@ public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicle var info2 = netManager.m_segments.m_buffer[position.m_segment].Info; if (info2.m_lanes != null && info2.m_lanes.Length > position.m_lane) { - var laneSpeedLimit = SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info2.m_lanes[position.m_lane]); // info2.m_lanes[position.m_lane].m_speedLimit; + var laneSpeedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info2.m_lanes[position.m_lane]) : info2.m_lanes[position.m_lane].m_speedLimit; // info2.m_lanes[position.m_lane].m_speedLimit; #if DEBUG /*if (position.m_segment == 275) { Log._Debug($"Applying lane speed limit of {laneSpeedLimit} to lane {laneID} @ seg. {position.m_segment}"); }*/ #endif - - /*if (TrafficRoadRestrictions.IsSegment(position.m_segment)) { - var restrictionSegment = TrafficRoadRestrictions.GetSegment(position.m_segment); - - if (restrictionSegment.SpeedLimits[position.m_lane] > 0.1f) { - laneSpeedLimit = restrictionSegment.SpeedLimits[position.m_lane]; - } - }*/ - maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); @@ -293,7 +323,7 @@ public void CustomCalculateSegmentPositionPathFinder(ushort vehicleId, ref Vehic out pos, out dir); var info = netManager.m_segments.m_buffer[position.m_segment].Info; if (info.m_lanes != null && info.m_lanes.Length > position.m_lane) { - var laneSpeedLimit = SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneId, info.m_lanes[position.m_lane]); //info.m_lanes[position.m_lane].m_speedLimit; + var laneSpeedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneId, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneId)].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); @@ -312,18 +342,11 @@ internal static bool IsRecklessDriver(ushort vehicleId, ref Vehicle vehicleData) } public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { - ExtVehicleType? vehicleType = VehicleStateManager.DetermineVehicleType(vehicleID, ref vehicleData); #if PATHRECALC VehicleState state = VehicleStateManager._GetVehicleState(vehicleID); bool recalcRequested = state.PathRecalculationRequested; state.PathRecalculationRequested = false; #endif - /*if (vehicleType == null) { - Log._Debug($"CustomCarAI.CustomStartPathFind: Could not determine ExtVehicleType from class type. typeof this={this.GetType().ToString()}"); - } else { - Log._Debug($"CustomCarAI.CustomStartPathFind: vehicleType={vehicleType}. typeof this={this.GetType().ToString()}"); - }*/ - VehicleInfo info = this.m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; PathUnit.Position startPosA; @@ -343,15 +366,19 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto endPosB = default(PathUnit.Position); } uint path; - bool res = false; - if (vehicleType == null) - res = Singleton.instance.CreatePath(out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false); - else - res = Singleton.instance.CreatePath( + ExtVehicleType vehicleType = VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType; + if (vehicleType == ExtVehicleType.None) { +#if DEBUG + Log._Debug($"CustomCarAI.CustomStartPathFind: Vehicle {vehicleID} does not have a valid vehicle type!"); +#endif + vehicleType = ExtVehicleType.RoadVehicle; + } + + bool res = Singleton.instance.CreatePath( #if PATHRECALC - recalcRequested, + recalcRequested, #endif - (ExtVehicleType)vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false); + (ExtVehicleType)vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false); if (res) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); diff --git a/TLM/TLM/Custom/AI/CustomCargoTruckAI.cs b/TLM/TLM/Custom/AI/CustomCargoTruckAI.cs index d4fb6170..a7dcbc9a 100644 --- a/TLM/TLM/Custom/AI/CustomCargoTruckAI.cs +++ b/TLM/TLM/Custom/AI/CustomCargoTruckAI.cs @@ -8,7 +8,7 @@ using TrafficManager.Custom.PathFinding; namespace TrafficManager.Custom.AI { - class CustomCargoTruckAI : CarAI { + public class CustomCargoTruckAI : CarAI { public void CustomSimulationStep(ushort vehicleId, ref Vehicle data, Vector3 physicsLodRefPos) { try { if ((data.m_flags & Vehicle.Flags.Congestion) != 0 && Options.enableDespawning) { @@ -24,14 +24,7 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle data, Vector3 phy } } - /*try { - VehicleStateManager.LogTraffic(vehicleId, ref data, true); - } catch (Exception e) { - Log.Error("CargoTruckAI CustomSimulationStep Error: " + e.ToString()); - }*/ - base.SimulationStep(vehicleId, ref data, physicsLodRefPos); - //BaseSimulationStep(vehicleId, ref data, physicsLodRefPos); } } catch (Exception ex) { Log.Error("Error in CargoTruckAI.SimulationStep: " + ex.ToString()); @@ -50,84 +43,13 @@ private static void RemoveOffers(ushort vehicleId, ref Vehicle data) { } } - /*private void BaseSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vector3 physicsLodRefPos) { - if ((vehicleData.m_flags & Vehicle.Flags.WaitingPath) != (Vehicle.Flags)0) { - PathManager instance = Singleton.instance; - byte pathFindFlags = instance.m_pathUnits.m_buffer[(int)((UIntPtr)vehicleData.m_path)].m_pathFindFlags; - if ((pathFindFlags & 4) != 0) { - vehicleData.m_pathPositionIndex = 255; - vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; - vehicleData.m_flags &= ~Vehicle.Flags.Arriving; - PathfindSuccess(vehicleId, ref vehicleData); - TrySpawn(vehicleId, ref vehicleData); - VehicleStateManager.OnPathFindReady(vehicleId, ref vehicleData); // NON-STOCK CODE - } else if ((pathFindFlags & 8) != 0 || ((pathFindFlags & 1) != 0 && vehicleData.m_blockCounter == 255)) { // NON-STOCK CODE - vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; - Singleton.instance.ReleasePath(vehicleData.m_path); - vehicleData.m_path = 0u; - PathfindFailure(vehicleId, ref vehicleData); - return; - } - } else if ((vehicleData.m_flags & Vehicle.Flags.WaitingSpace) != 0) { - TrySpawn(vehicleId, ref vehicleData); - } - - try { - VehicleStateManager.LogTraffic(vehicleId, ref vehicleData, true); - } catch (Exception e) { - Log.Error("CarAI CustomSimulationStep Error: " + e.ToString()); - } - - try { - VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData); - } catch (Exception e) { - Log.Error("CarAI CustomSimulationStep Error: " + e.ToString()); - } - - Vector3 lastFramePosition = vehicleData.GetLastFramePosition(); - int lodPhysics; - if (Vector3.SqrMagnitude(physicsLodRefPos - lastFramePosition) >= 1210000f) { - lodPhysics = 2; - } else if ( - Vector3.SqrMagnitude(Singleton.instance.m_simulationView.m_position - lastFramePosition) >= 250000f) { - lodPhysics = 1; - } else { - lodPhysics = 0; - } - SimulationStep(vehicleId, ref vehicleData, vehicleId, ref vehicleData, lodPhysics); - if (vehicleData.m_leadingVehicle == 0 && vehicleData.m_trailingVehicle != 0) { - VehicleManager instance2 = Singleton.instance; - ushort num = vehicleData.m_trailingVehicle; - int num2 = 0; - while (num != 0) { - ushort trailingVehicle = instance2.m_vehicles.m_buffer[num].m_trailingVehicle; - VehicleInfo info = instance2.m_vehicles.m_buffer[num].Info; - info.m_vehicleAI.SimulationStep(num, ref instance2.m_vehicles.m_buffer[num], vehicleId, - ref vehicleData, lodPhysics); - num = trailingVehicle; - if (++num2 > 16384) { - CODebugBase.Error(LogChannel.Core, - "Invalid list detected!\n" + Environment.StackTrace); - break; - } - } - } - int maxBlockCounter = (m_info.m_class.m_service > ItemClass.Service.Office) ? 150 : 100; - if ((vehicleData.m_flags & (Vehicle.Flags.Spawned | Vehicle.Flags.WaitingPath | Vehicle.Flags.WaitingSpace)) == - 0 && vehicleData.m_cargoParent == 0) { - Singleton.instance.ReleaseVehicle(vehicleId); - } else if (vehicleData.m_blockCounter >= maxBlockCounter && Options.enableDespawning) { - Singleton.instance.ReleaseVehicle(vehicleId); - } else if (vehicleData.m_leadingVehicle == 0 && CustomVehicleAI.ShouldRecalculatePath(vehicleId, ref vehicleData, maxBlockCounter)) { - CustomVehicleAI.MarkPathRecalculation(vehicleId); - InvalidPath(vehicleId, ref vehicleData, vehicleId, ref vehicleData); - } - }*/ - public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { if ((vehicleData.m_flags & (Vehicle.Flags.TransferToSource | Vehicle.Flags.GoingBack)) != 0) { - return CustomCargoTruckAI.BaseCustomStartPathFind(this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), ref this.m_info, vehicleID, ref vehicleData, startPos, endPos, startBothWays, endBothWays); + return base.StartPathFind(vehicleID, ref vehicleData, startPos, endPos, startBothWays, endBothWays, undergroundTarget); } + + VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType = ExtVehicleType.CargoTruck; + bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; PathUnit.Position startPosA; PathUnit.Position startPosB; @@ -176,7 +98,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto NetInfo.LaneType laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.CargoVehicle; VehicleInfo.VehicleType vehicleTypes = VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship; uint path; - if (instance.CreatePath(ExtVehicleType.CargoVehicle, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, laneTypes, vehicleTypes, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { + if (instance.CreatePath(ExtVehicleType.CargoVehicle, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, laneTypes, vehicleTypes, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { if (vehicleData.m_path != 0u) { instance.ReleasePath(vehicleData.m_path); } @@ -187,52 +109,5 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto } return false; } - - public static bool BaseCustomStartPathFind(bool heavyVehicle, bool ignoreBlocked, ref VehicleInfo info, ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays) { -#if PATHRECALC - VehicleState state = VehicleStateManager._GetVehicleState(vehicleID); - bool recalcRequested = state.PathRecalculationRequested; - state.PathRecalculationRequested = false; -#endif - - bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; - PathUnit.Position startPosA; - PathUnit.Position startPosB; - float num; - float num2; - PathUnit.Position endPosA; - PathUnit.Position endPosB; - float num3; - float num4; - if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out num, out num2) && - CustomPathManager.FindPathPosition(endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, false, false, 32f, out endPosA, out endPosB, out num3, out num4)) { - if (!startBothWays || num < 10f) { - startPosB = default(PathUnit.Position); - } - if (!endBothWays || num3 < 10f) { - endPosB = default(PathUnit.Position); - } - uint path; - ExtVehicleType? extVehicleType = VehicleStateManager.DetermineVehicleType(vehicleID, ref vehicleData); - bool res = false; - if (extVehicleType == null) - res = Singleton.instance.CreatePath(out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, heavyVehicle, ignoreBlocked, false, false); - else - res = Singleton.instance.CreatePath( -#if PATHRECALC - recalcRequested, -#endif - (ExtVehicleType)extVehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, heavyVehicle, ignoreBlocked, false, false); - if (res) { - if (vehicleData.m_path != 0u) { - Singleton.instance.ReleasePath(vehicleData.m_path); - } - vehicleData.m_path = path; - vehicleData.m_flags |= Vehicle.Flags.WaitingPath; - return true; - } - } - return false; - } } } diff --git a/TLM/TLM/Custom/AI/CustomCitizenAI.cs b/TLM/TLM/Custom/AI/CustomCitizenAI.cs index 1875b262..329907a1 100644 --- a/TLM/TLM/Custom/AI/CustomCitizenAI.cs +++ b/TLM/TLM/Custom/AI/CustomCitizenAI.cs @@ -16,6 +16,8 @@ class CustomCitizenAI : CitizenAI { // CitizenAI public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenData, Vector3 startPos, Vector3 endPos, VehicleInfo vehicleInfo) { + ExtVehicleType extVehicleType = ExtVehicleType.None; + NetInfo.LaneType laneType = NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleType = VehicleInfo.VehicleType.None; bool randomParking = false; @@ -26,9 +28,18 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa if (instance.m_isNightTime || instance.m_randomizer.Int32(2u) == 0) { laneType |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); vehicleType |= vehicleInfo.m_vehicleType; + extVehicleType = ExtVehicleType.Taxi; // NON-STOCK CODE } } } else { + // NON-STOCK CODE START + if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { + extVehicleType = ExtVehicleType.Bicycle; + } else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Car) { + extVehicleType = ExtVehicleType.PassengerCar; + } + // NON-STOCK CODE END + laneType |= NetInfo.LaneType.Vehicle; vehicleType |= vehicleInfo.m_vehicleType; if (citizenData.m_targetBuilding != 0 && Singleton.instance.m_buildings.m_buffer[(int)citizenData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office) { @@ -36,6 +47,7 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa } } } + PathUnit.Position vehiclePosition = default(PathUnit.Position); ushort parkedVehicle = Singleton.instance.m_citizens.m_buffer[(int)((UIntPtr)citizenData.m_citizen)].m_parkedVehicle; if (parkedVehicle != 0) { @@ -66,12 +78,12 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa // NON-STOCK CODE END // PathUnit.Position position2 = default(PathUnit.Position); uint path; - // NON-STOCK CODE START // - ExtVehicleType extVehicleType = ExtVehicleType.PassengerCar; - if (vehicleInfo != null && vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) - extVehicleType = ExtVehicleType.Bicycle; + bool res = false; //Log._Debug($"CustomCitizenAI: citizen instance {instanceID}, id {citizenData.m_citizen}. {vehicleType} {extVehicleType} mayUseTransport={mayUseTransport} wealthLevel={wealthLevel}"); - bool res = Singleton.instance.CreatePath(false, (ExtVehicleType)extVehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref position2, ref endPosA, ref position2, ref vehiclePosition, laneType, vehicleType, 20000f, false, false, false, false, randomParking); + if (extVehicleType == ExtVehicleType.None) + res = Singleton.instance.CreatePath(out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, position2, endPosA, position2, vehiclePosition, laneType, vehicleType, 20000f, false, false, false, false, randomParking); + else + res = Singleton.instance.CreatePath(false, (ExtVehicleType)extVehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, position2, endPosA, position2, vehiclePosition, laneType, vehicleType, 20000f, false, false, false, false, randomParking); // NON-STOCK CODE END // if (res) { if (citizenData.m_path != 0u) { diff --git a/TLM/TLM/Custom/AI/CustomFireTruckAI.cs b/TLM/TLM/Custom/AI/CustomFireTruckAI.cs index ec781fd4..848ce8af 100644 --- a/TLM/TLM/Custom/AI/CustomFireTruckAI.cs +++ b/TLM/TLM/Custom/AI/CustomFireTruckAI.cs @@ -17,6 +17,8 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto bool recalcRequested = state.PathRecalculationRequested; state.PathRecalculationRequested = false; #endif + ExtVehicleType vehicleType = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0 ? ExtVehicleType.Emergency : ExtVehicleType.Service; + VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType = vehicleType; VehicleInfo info = this.m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; @@ -41,7 +43,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto #if PATHRECALC recalcRequested, #endif - (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0 ? ExtVehicleType.Emergency : ExtVehicleType.Service, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { + vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); } diff --git a/TLM/TLM/Custom/AI/CustomHumanAI.cs b/TLM/TLM/Custom/AI/CustomHumanAI.cs index 3bccee56..5e5a4135 100644 --- a/TLM/TLM/Custom/AI/CustomHumanAI.cs +++ b/TLM/TLM/Custom/AI/CustomHumanAI.cs @@ -1,11 +1,12 @@ using ColossalFramework; +using TrafficManager.State; using TrafficManager.Traffic; using TrafficManager.TrafficLight; namespace TrafficManager.Custom.AI { class CustomHumanAI : CitizenAI { public bool CustomCheckTrafficLights(ushort node, ushort segment) { - var nodeSimulation = TrafficLightSimulation.GetNodeSimulation(node); + var nodeSimulation = Options.timedLightsEnabled ? TrafficLightSimulation.GetNodeSimulation(node) : null; var instance = Singleton.instance; var currentFrameIndex = Singleton.instance.m_currentFrameIndex; diff --git a/TLM/TLM/Custom/AI/CustomPassengerCarAI.cs b/TLM/TLM/Custom/AI/CustomPassengerCarAI.cs index f1065730..87d2e1b0 100644 --- a/TLM/TLM/Custom/AI/CustomPassengerCarAI.cs +++ b/TLM/TLM/Custom/AI/CustomPassengerCarAI.cs @@ -9,7 +9,7 @@ namespace TrafficManager.Custom.AI { - class CustomPassengerCarAI : CarAI + public class CustomPassengerCarAI : CarAI { public void CustomSimulationStep(ushort vehicleId, ref Vehicle data, Vector3 physicsLodRefPos) { @@ -49,6 +49,8 @@ public static ushort GetDriverInstance(ushort vehicleID, ref Vehicle data) { } public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { + VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType = ExtVehicleType.PassengerCar; + #if PATHRECALC VehicleState state = VehicleStateManager._GetVehicleState(vehicleID); bool recalcRequested = state.PathRecalculationRequested; @@ -90,7 +92,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto #else false #endif - , ExtVehicleType.PassengerCar, out path, ref instance2.m_randomizer, instance2.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, ref def, laneTypes, vehicleType, 20000f, false, false, false, false, randomParking)) { + , ExtVehicleType.PassengerCar, out path, ref instance2.m_randomizer, instance2.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, def, laneTypes, vehicleType, 20000f, false, false, false, false, randomParking)) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); } diff --git a/TLM/TLM/Custom/AI/CustomPoliceCarAI.cs b/TLM/TLM/Custom/AI/CustomPoliceCarAI.cs index e540d673..1497f881 100644 --- a/TLM/TLM/Custom/AI/CustomPoliceCarAI.cs +++ b/TLM/TLM/Custom/AI/CustomPoliceCarAI.cs @@ -17,6 +17,8 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto bool recalcRequested = state.PathRecalculationRequested; state.PathRecalculationRequested = false; #endif + ExtVehicleType vehicleType = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0 ? ExtVehicleType.Emergency : ExtVehicleType.Service; + VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType = vehicleType; VehicleInfo info = this.m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; @@ -37,13 +39,12 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto endPosB = default(PathUnit.Position); } uint path; - ExtVehicleType vehicleType = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0 ? ExtVehicleType.Emergency : ExtVehicleType.Service; //Log._Debug($"CustomPoliceCarAI.CustomStartPathFind: Vehicle {vehicleID}, type {vehicleType}"); if (Singleton.instance.CreatePath( #if PATHRECALC recalcRequested, #endif - vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { + vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); } diff --git a/TLM/TLM/Custom/AI/CustomRoadAI.cs b/TLM/TLM/Custom/AI/CustomRoadAI.cs index be3db2f7..407bb3d5 100644 --- a/TLM/TLM/Custom/AI/CustomRoadAI.cs +++ b/TLM/TLM/Custom/AI/CustomRoadAI.cs @@ -46,16 +46,19 @@ public void CustomNodeSimulationStep(ushort nodeId, ref NetNode data) { if (simStartFrame == 0) simStartFrame = Singleton.instance.m_currentFrameIndex; - try { - TrafficLightSimulation.SimulationStep(); + if (Options.timedLightsEnabled) { + try { + TrafficLightSimulation.SimulationStep(); - var nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeId); - if (nodeSim == null || !nodeSim.IsSimulationActive()) { - OriginalSimulationStep(nodeId, ref data); + var nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeId); + if (nodeSim == null || !nodeSim.IsSimulationActive()) { + OriginalSimulationStep(nodeId, ref data); + } + } catch (Exception e) { + Log.Warning($"CustomNodeSimulationStep: An error occurred: {e.ToString()}"); } - } catch (Exception e) { - Log.Warning($"CustomNodeSimulationStep: An error occurred: {e.ToString()}"); - } + } else + OriginalSimulationStep(nodeId, ref data); } public void CustomSegmentSimulationStep(ushort segmentID, ref NetSegment data) { @@ -140,7 +143,7 @@ public void CustomSegmentSimulationStep(ushort segmentID, ref NetSegment data) { // we use integer division here because it's faster if (currentBuf > 0) { uint currentSpeeds = currentLaneSpeeds[segmentID][laneIndex]; - currentMeanSpeed = (byte)Math.Min(100u, ((currentSpeeds * 100u) / currentBuf) / ((uint)(Math.Max(SpeedLimitManager.GetLockFreeGameSpeedLimit(segmentID, laneIndex, curLaneId, data.Info.m_lanes[laneIndex]) * 8f, 1f)))); // 0 .. 100, m_speedLimit of highway is 2, actual max. vehicle speed on highway is 16, that's why we use x*8 == x<<3 (don't ask why CO uses different units for velocity) + currentMeanSpeed = (byte)Math.Min(100u, ((currentSpeeds * 100u) / currentBuf) / ((uint)(Math.Max(SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(segmentID, laneIndex, curLaneId, data.Info.m_lanes[laneIndex]) * 8f, 1f)))); // 0 .. 100, m_speedLimit of highway is 2, actual max. vehicle speed on highway is 16, that's why we use x*8 == x<<3 (don't ask why CO uses different units for velocity) } #if MARKCONGESTEDSEGMENTS @@ -204,7 +207,7 @@ public void CustomSegmentSimulationStep(ushort segmentID, ref NetSegment data) { } public static void GetTrafficLightState(ushort vehicleId, ref Vehicle vehicleData, ushort nodeId, ushort fromSegmentId, byte fromLaneIndex, ushort toSegmentId, ref NetSegment segmentData, uint frame, out RoadBaseAI.TrafficLightState vehicleLightState, out RoadBaseAI.TrafficLightState pedestrianLightState) { - TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeId); + TrafficLightSimulation nodeSim = Options.timedLightsEnabled ? TrafficLightSimulation.GetNodeSimulation(nodeId) : null; if (nodeSim == null || !nodeSim.IsSimulationActive()) { RoadBaseAI.GetTrafficLightState(nodeId, ref segmentData, frame, out vehicleLightState, out pedestrianLightState); } else { @@ -213,7 +216,7 @@ public static void GetTrafficLightState(ushort vehicleId, ref Vehicle vehicleDat } public static void GetTrafficLightState(ushort vehicleId, ref Vehicle vehicleData, ushort nodeId, ushort fromSegmentId, byte fromLaneIndex, ushort toSegmentId, ref NetSegment segmentData, uint frame, out RoadBaseAI.TrafficLightState vehicleLightState, out RoadBaseAI.TrafficLightState pedestrianLightState, out bool vehicles, out bool pedestrians) { - TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeId); + TrafficLightSimulation nodeSim = Options.timedLightsEnabled ? TrafficLightSimulation.GetNodeSimulation(nodeId) : null; if (nodeSim == null || !nodeSim.IsSimulationActive()) { RoadBaseAI.GetTrafficLightState(nodeId, ref segmentData, frame, out vehicleLightState, out pedestrianLightState, out vehicles, out pedestrians); } else { @@ -228,40 +231,13 @@ private static void GetCustomTrafficLightState(ushort vehicleId, ref Vehicle veh nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeId); if (nodeSim == null) { Log.Error($"GetCustomTrafficLightState: node traffic light simulation not found at node {nodeId}! Vehicle {vehicleId} comes from segment {fromSegmentId} and goes to node {nodeId}"); - throw new ApplicationException($"GetCustomTrafficLightState: node traffic light simulation not found at node {nodeId}! Vehicle {vehicleId} comes from segment {fromSegmentId} and goes to node {nodeId}"); - } - } - - // get vehicle position - /*VehiclePosition vehiclePos = TrafficPriority.GetVehiclePosition(vehicleId); - if (!vehiclePos.Valid || vehiclePos.FromSegment != fromSegmentId || vehiclePos.ToNode != nodeId) { - Log._Debug($"GetTrafficLightState: Recalculating position for vehicle {vehicleId}! FromSegment={vehiclePos.FromSegment} Valid={vehiclePos.Valid}"); - try { - HandleVehicle(vehicleId, ref Singleton.instance.m_vehicles.m_buffer[vehicleId], false, false); - } catch (Exception e) { - Log.Error("VehicleAI GetTrafficLightState Error: " + e.ToString()); + vehicleLightState = TrafficLightState.Green; + pedestrianLightState = TrafficLightState.Green; + return; + //throw new ApplicationException($"GetCustomTrafficLightState: node traffic light simulation not found at node {nodeId}! Vehicle {vehicleId} comes from segment {fromSegmentId} and goes to node {nodeId}"); } } - if (!vehiclePos.Valid || vehiclePos.FromSegment != fromSegmentId || vehiclePos.ToNode != nodeId) { - Log.Warning($"GetTrafficLightState: Vehicle {vehicleId} is not moving at segment {fromSegmentId} to node {nodeId}! FromSegment={vehiclePos.FromSegment} ToNode={vehiclePos.ToNode} Valid={vehiclePos.Valid}"); - vehicleLightState = RoadBaseAI.TrafficLightState.Red; - pedestrianLightState = RoadBaseAI.TrafficLightState.Red; - return; - }*/ - - // get vehicle type - //ExtVehicleType? vehicleType = VehicleStateManager.GetVehicleState(vehicleId)?.VehicleType; - /*if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Tram && vehicleType != ExtVehicleType.Tram) - Log.Warning($"vehicleType={vehicleType} ({(int)vehicleType}) for Tram");*/ - //Log._Debug($"GetCustomTrafficLightState: Vehicle {vehicleId} is a {vehicleType}"); - /*if (vehicleType == null) { - Log.Warning($"GetTrafficLightState: Could not determine vehicle type of vehicle {vehicleId}!"); - vehicleLightState = RoadBaseAI.TrafficLightState.Red; - pedestrianLightState = RoadBaseAI.TrafficLightState.Red; - return; - }*/ - // get responsible traffic light //Log._Debug($"GetTrafficLightState: Getting custom light for vehicle {vehicleId} @ node {nodeId}, segment {fromSegmentId}, lane {fromLaneIndex}."); CustomSegmentLights lights = CustomTrafficLights.GetSegmentLights(nodeId, fromSegmentId); @@ -302,7 +278,7 @@ public static void CustomSetTrafficLightState(ushort nodeID, ref NetSegment segm public static void OriginalSetTrafficLightState(bool customCall, ushort nodeID, ref NetSegment segmentData, uint frame, RoadBaseAI.TrafficLightState vehicleLightState, RoadBaseAI.TrafficLightState pedestrianLightState, bool vehicles, bool pedestrians) { /// NON-STOCK CODE START /// - TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeID); + TrafficLightSimulation nodeSim = Options.timedLightsEnabled ? TrafficLightSimulation.GetNodeSimulation(nodeID) : null; if (nodeSim == null || !nodeSim.IsSimulationActive() || customCall) { /// NON-STOCK CODE END /// int num = (int)pedestrianLightState << 2 | (int)vehicleLightState; diff --git a/TLM/TLM/Custom/AI/CustomShipAI.cs b/TLM/TLM/Custom/AI/CustomShipAI.cs index f810156a..18b50db9 100644 --- a/TLM/TLM/Custom/AI/CustomShipAI.cs +++ b/TLM/TLM/Custom/AI/CustomShipAI.cs @@ -11,8 +11,13 @@ namespace TrafficManager.Custom.AI { class CustomShipAI : ShipAI { public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays) { /// NON-STOCK CODE START /// - ExtVehicleType? vehicleType = VehicleStateManager.DetermineVehicleType(vehicleID, ref vehicleData); - if (vehicleType == ExtVehicleType.CargoShip) + ExtVehicleType vehicleType = VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType; + if (vehicleType == ExtVehicleType.None) { +#if DEBUG + Log._Debug($"CustomShipAI.CustomStartPathFind: Vehicle {vehicleID} does not have a valid vehicle type!"); +#endif + vehicleType = ExtVehicleType.Ship; + } else if (vehicleType == ExtVehicleType.CargoShip) vehicleType = ExtVehicleType.CargoVehicle; /// NON-STOCK CODE END /// @@ -33,11 +38,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto endPosB = default(PathUnit.Position); } uint path; - bool res = false; - if (vehicleType == null) - res = Singleton.instance.CreatePath(out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f); - else - res = Singleton.instance.CreatePath((ExtVehicleType)vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f); + bool res = Singleton.instance.CreatePath((ExtVehicleType)vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f); if (res) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); diff --git a/TLM/TLM/Custom/AI/CustomTaxiAI.cs b/TLM/TLM/Custom/AI/CustomTaxiAI.cs index fba3a312..b39bfcbb 100644 --- a/TLM/TLM/Custom/AI/CustomTaxiAI.cs +++ b/TLM/TLM/Custom/AI/CustomTaxiAI.cs @@ -36,6 +36,8 @@ public static ushort GetPassengerInstance(ushort vehicleID, ref Vehicle data) { } public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { + VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType = ExtVehicleType.Taxi; + #if PATHRECALC VehicleState state = VehicleStateManager._GetVehicleState(vehicleID); bool recalcRequested = state.PathRecalculationRequested; @@ -72,7 +74,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto #if PATHRECALC recalcRequested, #endif - ExtVehicleType.Taxi, out path, ref instance2.m_randomizer, instance2.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, laneType, vehicleType, 20000f)) { + ExtVehicleType.Taxi, out path, ref instance2.m_randomizer, instance2.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, laneType, vehicleType, 20000f)) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); } diff --git a/TLM/TLM/Custom/AI/CustomTrainAI.cs b/TLM/TLM/Custom/AI/CustomTrainAI.cs index f29918a2..d060651c 100644 --- a/TLM/TLM/Custom/AI/CustomTrainAI.cs +++ b/TLM/TLM/Custom/AI/CustomTrainAI.cs @@ -36,7 +36,6 @@ public void TrafficManagerSimulationStep(ushort vehicleId, ref Vehicle vehicleDa //#endif return; } - VehicleStateManager.OnPathFindReady(vehicleId, ref vehicleData); // NON-STOCK CODE } else if ((pathFindFlags & PathUnit.FLAG_FAILED) != 0 || vehicleData.m_path == 0 #if USEPATHWAITCOUNTER || ((pathFindFlags & PathUnit.FLAG_CREATED) != 0 && state.PathWaitCounter == ushort.MaxValue) @@ -74,17 +73,23 @@ public void TrafficManagerSimulationStep(ushort vehicleId, ref Vehicle vehicleDa } /// NON-STOCK CODE START /// - try { - //Log._Debug($"HandleVehicle for trams. vehicleId={vehicleId} frontVehicleId={frontVehicleId}"); - VehicleStateManager.LogTraffic(frontVehicleId, ref Singleton.instance.m_vehicles.m_buffer[frontVehicleId], true); - } catch (Exception e) { - Log.Error("TrainAI TrafficManagerSimulationStep (1) Error: " + e.ToString()); + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); + + if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { + try { + vehStateManager.UpdateVehiclePos(frontVehicleId, ref Singleton.instance.m_vehicles.m_buffer[frontVehicleId]); + } catch (Exception e) { + Log.Error("TrainAI TrafficManagerSimulationStep (2) Error: " + e.ToString()); + } } - try { - VehicleStateManager.UpdateVehiclePos(frontVehicleId, ref Singleton.instance.m_vehicles.m_buffer[frontVehicleId]); - } catch (Exception e) { - Log.Error("TrainAI TrafficManagerSimulationStep (2) Error: " + e.ToString()); + if (!Options.isStockLaneChangerUsed()) { + try { + //Log._Debug($"HandleVehicle for trams. vehicleId={vehicleId} frontVehicleId={frontVehicleId}"); + vehStateManager.LogTraffic(frontVehicleId, ref Singleton.instance.m_vehicles.m_buffer[frontVehicleId], true); + } catch (Exception e) { + Log.Error("TrainAI TrafficManagerSimulationStep (1) Error: " + e.ToString()); + } } /// NON-STOCK CODE END /// @@ -149,12 +154,44 @@ public void TrafficManagerSimulationStep(ushort vehicleId, ref Vehicle vehicleDa } } + public override bool TrySpawn(ushort vehicleID, ref Vehicle vehicleData) { + if ((vehicleData.m_flags & Vehicle.Flags.Spawned) != (Vehicle.Flags)0) { + return true; + } + if (vehicleData.m_path != 0u) { + PathManager instance = Singleton.instance; + PathUnit.Position pathPos; + if (instance.m_pathUnits.m_buffer[(int)((UIntPtr)vehicleData.m_path)].GetPosition(0, out pathPos)) { + uint laneID = PathManager.GetLaneID(pathPos); + if (laneID != 0u && !Singleton.instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(1000f, vehicleID)) { + vehicleData.m_flags |= Vehicle.Flags.WaitingSpace; + return false; + } + } + } + vehicleData.Spawn(vehicleID); + vehicleData.m_flags &= ~Vehicle.Flags.WaitingSpace; + CustomTrainAI.InitializePath(vehicleID, ref vehicleData); + + // NON-STOCK CODE START + if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { + VehicleStateManager.Instance().OnVehicleSpawned(vehicleID, ref vehicleData); + } + // NON-STOCK CODE END + + return true; + } + + private static void InitializePath(ushort vehicleID, ref Vehicle vehicleData) { + Log.Error("CustomTrainAI.InitializePath called"); + } + public void TmCalculateSegmentPositionPathFinder(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position position, uint laneID, byte offset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { NetManager instance = Singleton.instance; instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection((float)offset * 0.003921569f, out pos, out dir); NetInfo info = instance.m_segments.m_buffer[(int)position.m_segment].Info; if (info.m_lanes != null && info.m_lanes.Length > (int)position.m_lane) { - var laneSpeedLimit = SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]); + var laneSpeedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, laneSpeedLimit, instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1f, 0f); @@ -163,18 +200,25 @@ public void TmCalculateSegmentPositionPathFinder(ushort vehicleID, ref Vehicle v public bool CustomStartPathFind(ushort vehicleId, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays) { /// NON-STOCK CODE START /// - ExtVehicleType? vehicleType = VehicleStateManager.DetermineVehicleType(vehicleId, ref vehicleData); - if (vehicleType == ExtVehicleType.CargoTrain) + ExtVehicleType vehicleType = VehicleStateManager.Instance()._GetVehicleState(vehicleId).VehicleType; + if (vehicleType == ExtVehicleType.None) { +#if DEBUG + Log._Debug($"CustomTrainAI.CustomStartPathFind: Vehicle {vehicleId} does not have a valid vehicle type!"); +#endif + vehicleType = ExtVehicleType.RailVehicle; + } else if (vehicleType == ExtVehicleType.CargoTrain) vehicleType = ExtVehicleType.CargoVehicle; #if DEBUG - /*bool reversed = (vehicleData.m_flags & Vehicle.Flags.Reversed) != 0; - ushort frontVehicleId; - if (reversed) { - frontVehicleId = vehicleData.GetLastVehicle(vehicleId); - } else { - frontVehicleId = vehicleId; - } - Log._Debug($"CustomTrainAI.CustomStartPathFind. vehicleID={vehicleId}. reversed={reversed} frontVehicleId={frontVehicleId} type={this.GetType().ToString()} vehicleType={vehicleType} target={vehicleData.m_targetBuilding}");*/ + /*if (vehicleType == ExtVehicleType.CargoVehicle) { + bool reversed = (vehicleData.m_flags & Vehicle.Flags.Reversed) != 0; + ushort frontVehicleId; + if (reversed) { + frontVehicleId = vehicleData.GetLastVehicle(vehicleId); + } else { + frontVehicleId = vehicleId; + } + Log._Debug($"CustomTrainAI.CustomStartPathFind. vehicleID={vehicleId}. reversed={reversed} frontVehicleId={frontVehicleId} type={this.GetType().ToString()} vehicleType={vehicleType} target={vehicleData.m_targetBuilding}"); + }*/ #endif /// NON-STOCK CODE END /// @@ -199,8 +243,8 @@ public bool CustomStartPathFind(ushort vehicleId, ref Vehicle vehicleData, Vecto PathUnit.Position endPosB; float num3; float num4; - if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out num, out num2) && - CustomPathManager.FindPathPosition(endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, allowUnderground2, false, 32f, out endPosA, out endPosB, out num3, out num4)) { + if (PathManager.FindPathPosition(startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out num, out num2) && + PathManager.FindPathPosition(endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, allowUnderground2, false, 32f, out endPosA, out endPosB, out num3, out num4)) { if (!startBothWays || num2 > num * 1.2f) { startPosB = default(PathUnit.Position); } @@ -208,11 +252,7 @@ public bool CustomStartPathFind(ushort vehicleId, ref Vehicle vehicleData, Vecto endPosB = default(PathUnit.Position); } uint path; - bool res = false; - if (vehicleType == null) - res = Singleton.instance.CreatePath(out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, false, false, true, false); - else - res = Singleton.instance.CreatePath((ExtVehicleType)vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, false, false, true, false); + bool res = Singleton.instance.CreatePath((ExtVehicleType)vehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, false, false, true, false); if (res) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); @@ -226,9 +266,9 @@ public bool CustomStartPathFind(ushort vehicleId, ref Vehicle vehicleData, Vecto } public void CustomCheckNextLane(ushort vehicleID, ref Vehicle vehicleData, ref float maxSpeed, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, Bezier3 bezier) { - if (Options.simAccuracy <= 1) { + if ((Options.prioritySignsEnabled || Options.timedLightsEnabled) && Options.simAccuracy <= 1) { try { - VehicleStateManager.UpdateVehiclePos(vehicleID, ref vehicleData, ref prevPos, ref position); + VehicleStateManager.Instance().UpdateVehiclePos(vehicleID, ref vehicleData, ref prevPos, ref position); } catch (Exception e) { Log.Error("TrainAI CustomCheckNextLane Error: " + e.ToString()); } diff --git a/TLM/TLM/Custom/AI/CustomTramBaseAI.cs b/TLM/TLM/Custom/AI/CustomTramBaseAI.cs index 9dd4a491..47c4b142 100644 --- a/TLM/TLM/Custom/AI/CustomTramBaseAI.cs +++ b/TLM/TLM/Custom/AI/CustomTramBaseAI.cs @@ -27,7 +27,6 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vect try { this.PathfindSuccess(vehicleId, ref vehicleData); this.PathFindReady(vehicleId, ref vehicleData); - VehicleStateManager.OnPathFindReady(vehicleId, ref vehicleData); // NON-STOCK CODE } catch (Exception e) { Log.Warning($"TramBaseAI.PathFindSuccess/PathFindReady({vehicleId}) threw an exception: {e.ToString()}"); vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; @@ -65,6 +64,8 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vect } /// NON-STOCK CODE START /// + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); + bool reversed = (vehicleData.m_flags & Vehicle.Flags.Reversed) != 0; ushort frontVehicleId; if (reversed) { @@ -73,17 +74,21 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vect frontVehicleId = vehicleId; } - try { - //Log._Debug($"HandleVehicle for trams. vehicleId={vehicleId} frontVehicleId={frontVehicleId}"); - VehicleStateManager.LogTraffic(frontVehicleId, ref Singleton.instance.m_vehicles.m_buffer[frontVehicleId], true); - } catch (Exception e) { - Log.Error("TramAI CustomSimulationStep (1) Error: " + e.ToString()); + if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { + try { + vehStateManager.UpdateVehiclePos(frontVehicleId, ref Singleton.instance.m_vehicles.m_buffer[frontVehicleId]); + } catch (Exception e) { + Log.Error("TramAI CustomSimulationStep (2) Error: " + e.ToString()); + } } - try { - VehicleStateManager.UpdateVehiclePos(frontVehicleId, ref Singleton.instance.m_vehicles.m_buffer[frontVehicleId]); - } catch (Exception e) { - Log.Error("TramAI CustomSimulationStep (2) Error: " + e.ToString()); + if (!Options.isStockLaneChangerUsed()) { + try { + //Log._Debug($"HandleVehicle for trams. vehicleId={vehicleId} frontVehicleId={frontVehicleId}"); + vehStateManager.LogTraffic(frontVehicleId, ref Singleton.instance.m_vehicles.m_buffer[frontVehicleId], true); + } catch (Exception e) { + Log.Error("TramAI CustomSimulationStep (1) Error: " + e.ToString()); + } } /// NON-STOCK CODE END /// @@ -112,7 +117,41 @@ public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vect } } + public override bool TrySpawn(ushort vehicleID, ref Vehicle vehicleData) { + if ((vehicleData.m_flags & Vehicle.Flags.Spawned) != (Vehicle.Flags)0) { + return true; + } + if (vehicleData.m_path != 0u) { + PathManager instance = Singleton.instance; + PathUnit.Position pathPos; + if (instance.m_pathUnits.m_buffer[(int)((UIntPtr)vehicleData.m_path)].GetPosition(0, out pathPos)) { + uint laneID = PathManager.GetLaneID(pathPos); + if (laneID != 0u && !Singleton.instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(1000f, vehicleID)) { + vehicleData.m_flags |= Vehicle.Flags.WaitingSpace; + return false; + } + } + } + vehicleData.Spawn(vehicleID); + vehicleData.m_flags &= ~Vehicle.Flags.WaitingSpace; + CustomTramBaseAI.InitializePath(vehicleID, ref vehicleData); + + // NON-STOCK CODE START + if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { + VehicleStateManager.Instance().OnVehicleSpawned(vehicleID, ref vehicleData); + } + // NON-STOCK CODE END + + return true; + } + + private static void InitializePath(ushort vehicleID, ref Vehicle vehicleData) { + Log.Error("CustomTrainAI.InitializePath called"); + } + public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays) { + VehicleStateManager.Instance()._GetVehicleState(vehicleID).VehicleType = ExtVehicleType.Tram; + VehicleInfo info = this.m_info; bool allowUnderground; bool allowUnderground2; @@ -139,7 +178,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto endPosB = default(PathUnit.Position); } uint path; - if (Singleton.instance.CreatePath(ExtVehicleType.Tram, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, false, false, true, false)) { + if (Singleton.instance.CreatePath(ExtVehicleType.Tram, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, false, false, true, false)) { if (vehicleData.m_path != 0u) { Singleton.instance.ReleasePath(vehicleData.m_path); } @@ -152,9 +191,9 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto } public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { - if (Options.simAccuracy <= 1) { + if ((Options.prioritySignsEnabled || Options.timedLightsEnabled) && Options.simAccuracy <= 1) { try { - VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position); + VehicleStateManager.Instance().UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position); } catch (Exception e) { Log.Error("TramAI CustomCalculateSegmentPosition Error: " + e.ToString()); } @@ -199,8 +238,8 @@ public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicle } NetInfo info = netManager.m_segments.m_buffer[(int)position.m_segment].Info; if (info.m_lanes != null && info.m_lanes.Length > (int)position.m_lane) { - //maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, info.m_lanes[(int)position.m_lane].m_speedLimit, instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); - maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]), netManager.m_lanes.m_buffer[laneID].m_curve); + float speedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; + maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, speedLimit, netManager.m_lanes.m_buffer[laneID].m_curve); } else { maxSpeed = this.CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } @@ -211,8 +250,8 @@ public void CustomCalculateSegmentPositionPathFinder(ushort vehicleID, ref Vehic instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection((float)offset * 0.003921569f, out pos, out dir); NetInfo info = instance.m_segments.m_buffer[(int)position.m_segment].Info; if (info.m_lanes != null && info.m_lanes.Length > (int)position.m_lane) { - //maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, info.m_lanes[(int)position.m_lane].m_speedLimit, instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); - maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]), instance.m_lanes.m_buffer[laneID].m_curve); + float speedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; + maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, speedLimit, instance.m_lanes.m_buffer[laneID].m_curve); } else { maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1f, 0f); } diff --git a/TLM/TLM/Custom/AI/CustomTransportLineAI.cs b/TLM/TLM/Custom/AI/CustomTransportLineAI.cs index b26da4eb..4b576bdd 100644 --- a/TLM/TLM/Custom/AI/CustomTransportLineAI.cs +++ b/TLM/TLM/Custom/AI/CustomTransportLineAI.cs @@ -79,7 +79,7 @@ public static bool CustomStartPathFind(ushort segmentID, ref NetSegment data, It extVehicleType = ExtVehicleType.PassengerPlane; //Log._Debug($"Transport line. extVehicleType={extVehicleType}"); - if (Singleton.instance.CreatePath(extVehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, vehicleType, 20000f, false, true, true, skipQueue)) { + if (Singleton.instance.CreatePath(extVehicleType, out path, ref Singleton.instance.m_randomizer, Singleton.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, vehicleType, 20000f, false, true, true, skipQueue)) { if (startPosA.m_segment != 0 && startPosB.m_segment != 0) { NetNode[] expr_2F5_cp_0 = instance.m_nodes.m_buffer; ushort expr_2F5_cp_1 = data.m_startNode; diff --git a/TLM/TLM/Custom/AI/CustomVehicleAI.cs b/TLM/TLM/Custom/AI/CustomVehicleAI.cs index 45a43ed2..5042097d 100644 --- a/TLM/TLM/Custom/AI/CustomVehicleAI.cs +++ b/TLM/TLM/Custom/AI/CustomVehicleAI.cs @@ -22,10 +22,6 @@ class CustomVehicleAI : VehicleAI { private static PathUnit.Position DUMMY_POS = default(PathUnit.Position); - public void CustomReleaseVehicle(ushort vehicleId, ref Vehicle vehicleData) { - VehicleStateManager.OnReleaseVehicle(vehicleId, ref vehicleData); - } - public void CustomCalculateSegmentPosition(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { CalculateSegPos(vehicleID, ref vehicleData, position, laneID, offset, out pos, out dir, out maxSpeed); } @@ -39,7 +35,7 @@ protected virtual void CalculateSegPos(ushort vehicleID, ref Vehicle vehicleData instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection((float)offset * 0.003921569f, out pos, out dir); NetInfo info = instance.m_segments.m_buffer[(int)position.m_segment].Info; if (info.m_lanes != null && info.m_lanes.Length > (int)position.m_lane) { - var laneSpeedLimit = SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]); + var laneSpeedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, laneSpeedLimit, instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1f, 0f); @@ -159,28 +155,16 @@ internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData, bool forceUpdatePos = false; VehicleState vehicleState = null; - try { - vehicleState = VehicleStateManager.GetVehicleState(vehicleId); - if (vehicleState == null) { - VehicleStateManager.OnPathFindReady(vehicleId, ref vehicleData); - vehicleState = VehicleStateManager.GetVehicleState(vehicleId); + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); - if (vehicleState == null) { -#if DEBUG - Log._Debug($"Could not get vehicle state of {vehicleId}!"); -#endif - } else { - forceUpdatePos = true; - } - } - } catch (Exception e) { - Log.Error("VehicleAI MayChangeSegment vehicle state error: " + e.ToString()); + if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { + vehicleState = vehStateManager.GetVehicleState(vehicleId); } - if (forceUpdatePos || Options.simAccuracy >= 2) { + if ((Options.prioritySignsEnabled || Options.timedLightsEnabled) && (forceUpdatePos || Options.simAccuracy >= 2)) { try { - VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position); + vehStateManager.UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position); } catch (Exception e) { Log.Error("VehicleAI MayChangeSegment Error: " + e.ToString()); } @@ -357,7 +341,7 @@ internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData, maxSpeed = 0f; return false; } - } else if (vehicleState != null) { + } else if (vehicleState != null && Options.prioritySignsEnabled) { #if DEBUG //bool debug = destinationNodeId == 10864; //bool debug = destinationNodeId == 13531; diff --git a/TLM/TLM/Custom/Manager/CustomVehicleManager.cs b/TLM/TLM/Custom/Manager/CustomVehicleManager.cs new file mode 100644 index 00000000..af79fa2e --- /dev/null +++ b/TLM/TLM/Custom/Manager/CustomVehicleManager.cs @@ -0,0 +1,78 @@ +using ColossalFramework.Math; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TrafficManager.Traffic; +using UnityEngine; + +namespace TrafficManager.Custom.Manager { + public class CustomVehicleManager : VehicleManager { + public void CustomReleaseVehicle(ushort vehicleId) { +#if DEBUG + Log._Debug($"CustomVehicleManager.CustomReleaseVehicle({vehicleId})"); +#endif + VehicleStateManager.Instance().OnReleaseVehicle(vehicleId); + ReleaseVehicleImplementation(vehicleId, ref this.m_vehicles.m_buffer[(int)vehicleId]); + } + + private void ReleaseVehicleImplementation(ushort vehicleId, ref Vehicle vehicleData) { + Log.Error("CustomVehicleManager.ReleaseVehicleImplementation called."); + } + + public bool CustomCreateVehicle(out ushort vehicleId, ref Randomizer r, VehicleInfo info, Vector3 position, TransferManager.TransferReason type, bool transferToSource, bool transferToTarget) { + ushort vehId; + if (this.m_vehicles.CreateItem(out vehId, ref r)) { + vehicleId = vehId; + Vehicle.Frame frame = new Vehicle.Frame(position, Quaternion.identity); + this.m_vehicles.m_buffer[(int)vehicleId].m_flags = Vehicle.Flags.Created; + if (transferToSource) { + this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToSource); + } + if (transferToTarget) { + this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToTarget); + } + this.m_vehicles.m_buffer[(int)vehicleId].Info = info; + this.m_vehicles.m_buffer[(int)vehicleId].m_frame0 = frame; + this.m_vehicles.m_buffer[(int)vehicleId].m_frame1 = frame; + this.m_vehicles.m_buffer[(int)vehicleId].m_frame2 = frame; + this.m_vehicles.m_buffer[(int)vehicleId].m_frame3 = frame; + this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos0 = Vector4.zero; + this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos1 = Vector4.zero; + this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos2 = Vector4.zero; + this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos3 = Vector4.zero; + this.m_vehicles.m_buffer[(int)vehicleId].m_sourceBuilding = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_targetBuilding = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_transferType = (byte)type; + this.m_vehicles.m_buffer[(int)vehicleId].m_transferSize = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_waitCounter = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_blockCounter = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_nextGridVehicle = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_nextOwnVehicle = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_nextGuestVehicle = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_nextLineVehicle = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_transportLine = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_leadingVehicle = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_trailingVehicle = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_cargoParent = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_firstCargo = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_nextCargo = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_citizenUnits = 0u; + this.m_vehicles.m_buffer[(int)vehicleId].m_path = 0u; + this.m_vehicles.m_buffer[(int)vehicleId].m_lastFrame = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_pathPositionIndex = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_lastPathOffset = 0; + this.m_vehicles.m_buffer[(int)vehicleId].m_gateIndex = 0; + info.m_vehicleAI.CreateVehicle(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]); + info.m_vehicleAI.FrameDataUpdated(vehicleId, ref this.m_vehicles.m_buffer[vehicleId], ref this.m_vehicles.m_buffer[vehicleId].m_frame0); + this.m_vehicleCount = (int)(this.m_vehicles.ItemCount() - 1u); + + VehicleStateManager.Instance().DetermineVehicleType(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]); // NON-STOCK CODE + + return true; + } + vehicleId = 0; + return false; + } + } +} diff --git a/TLM/TLM/Custom/PathFinding/CustomPathFind.cs b/TLM/TLM/Custom/PathFinding/CustomPathFind.cs index 73206688..40782e30 100644 --- a/TLM/TLM/Custom/PathFinding/CustomPathFind.cs +++ b/TLM/TLM/Custom/PathFinding/CustomPathFind.cs @@ -169,7 +169,7 @@ protected virtual void OnDestroy() { uint lockIter = 0; #endif try { - Monitor.Enter(QueueLock); + while (!Monitor.TryEnter(QueueLock, SimulationManager.SYNCHRONIZE_TIMEOUT)) {} Terminated = true; Monitor.PulseAll(QueueLock); } catch (Exception e) { @@ -182,7 +182,7 @@ protected virtual void OnDestroy() { public bool CalculatePath(ExtVehicleType vehicleType, uint unit, bool skipQueue) { if (Singleton.instance.AddPathReference(unit)) { try { - Monitor.Enter(QueueLock); + while (!Monitor.TryEnter(QueueLock, SimulationManager.SYNCHRONIZE_TIMEOUT)) { } if (skipQueue) { if (this.QueueLast == 0u) { this.QueueLast = unit; @@ -498,7 +498,7 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { // the current path unit is full, we need a new one uint createdPathUnitId; try { - Monitor.Enter(_bufferLock); + while (!Monitor.TryEnter(_bufferLock, SimulationManager.SYNCHRONIZE_TIMEOUT)) { } if (!this.PathUnits.CreateItem(out createdPathUnitId, ref this._pathRandomizer)) { // we failed to create a new path unit, thus the path-finding also failed PathUnits.m_buffer[(int)((UIntPtr)unit)].m_pathFindFlags |= PathUnit.FLAG_FAILED; @@ -527,9 +527,11 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { } uint laneID = PathManager.GetLaneID(currentPosition); // NON-STOCK CODE START - NetInfo.Lane laneInfo = Singleton.instance.m_segments.m_buffer[currentPosition.m_segment].Info.m_lanes[currentPosition.m_lane]; - if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) - CustomRoadAI.AddTraffic(currentPosition.m_segment, currentPosition.m_lane, (ushort)(this._isHeavyVehicle || _extVehicleType == ExtVehicleType.Bus ? 50 : 25), null); + if (!Options.isStockLaneChangerUsed()) { + NetInfo.Lane laneInfo = Singleton.instance.m_segments.m_buffer[currentPosition.m_segment].Info.m_lanes[currentPosition.m_lane]; + if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) + CustomRoadAI.AddTraffic(currentPosition.m_segment, currentPosition.m_lane, (ushort)(this._isHeavyVehicle || _extVehicleType == ExtVehicleType.Bus ? 50 : 25), null); + } // NON-STOCK CODE END currentPosition = this._laneTarget[(int)((UIntPtr)laneID)]; } @@ -553,7 +555,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ushort nextNodeId, re #if DEBUGPF //bool debug = Options.disableSomething1 && item.m_position.m_segment == 1459 && nextNodeId == 19630; //bool debug = Options.disableSomething1 && (item.m_position.m_segment == 3833 || item.m_position.m_segment == 9649); - bool debug = Options.disableSomething1 && nextNodeId == 6559; + bool debug = Options.disableSomething1 && nextNodeId == 15458; #endif #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) @@ -568,6 +570,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ushort nextNodeId, re //bool debug = nextNodeId == 12732; #else bool debug = false; + LaneConnectionManager laneConnManager = LaneConnectionManager.Instance(); #endif #if DEBUGPF2 @@ -962,11 +965,11 @@ private void ProcessItemMain(uint unitId, BufferItem item, ushort nextNodeId, re bool nextHasOutgoingConnections = false; bool nextIsConnectedWithPrev = true; - if (!Options.disableSomething2) { - nextHasOutgoingConnections = Singleton.instance.HasConnections(curLaneId, nextIsStartNodeOfNextSegment); + if (Options.laneConnectorEnabled) { + nextHasOutgoingConnections = laneConnManager.HasConnections(curLaneId, nextIsStartNodeOfNextSegment); if (nextHasOutgoingConnections) { hasLaneConnections = true; - nextIsConnectedWithPrev = Singleton.instance.AreLanesConnected(curLaneId, item.m_laneID, nextIsStartNodeOfNextSegment); + nextIsConnectedWithPrev = laneConnManager.AreLanesConnected(curLaneId, item.m_laneID, nextIsStartNodeOfNextSegment); } #if DEBUGPF if (debug) { @@ -1105,13 +1108,13 @@ private void ProcessItemMain(uint unitId, BufferItem item, ushort nextNodeId, re nextInnerSimilarIndex = prevInnerSimilarLaneIndex + numLanesSeen; // lane splitting #if DEBUGPF if (debug) - logBuf.Add($"Performing lane split. nextLeftSimilarIndex={nextLeftSimilarIndex} = prevLeftSimilarIndex({prevLeftSimilarIndex}) + numLanesSeen({numLanesSeen})"); + logBuf.Add($"Performing lane split. nextInnerSimilarIndex={nextInnerSimilarIndex} = prevInnerSimilarLaneIndex({prevInnerSimilarLaneIndex}) + numLanesSeen({numLanesSeen})"); #endif } else { nextInnerSimilarIndex = prevInnerSimilarLaneIndex - numLanesSeen; // lane merging #if DEBUGPF if (debug) - logBuf.Add($"Performing lane merge. nextLeftSimilarIndex={nextLeftSimilarIndex} = prevLeftSimilarIndex({prevLeftSimilarIndex}) - numLanesSeen({numLanesSeen})"); + logBuf.Add($"Performing lane merge. nextInnerSimilarIndex={nextInnerSimilarIndex} = prevInnerSimilarLaneIndex({prevInnerSimilarLaneIndex}) - numLanesSeen({numLanesSeen})"); #endif } @@ -1140,7 +1143,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ushort nextNodeId, re // If nextLaneI is still -1 here, then highways rules really cannot handle this situation (that's ok). #if DEBUGPF if (debug) - logBuf.Add($"Next lane out of bounds. nextLaneI={nextLaneI}, isIncomingLeft={isIncomingLeft}, prevRightSimilarIndex={prevRightSimilarIndex}, prevLeftSimilarIndex={prevLeftSimilarIndex}"); + logBuf.Add($"Next lane out of bounds. nextLaneI={nextLaneI}, isIncomingLeft={isIncomingLeft}, prevOuterSimilarLaneIndex={prevOuterSimilarLaneIndex}, prevInnerSimilarLaneIndex={prevInnerSimilarLaneIndex}"); #endif } @@ -1728,6 +1731,8 @@ private bool ProcessItemCosts(bool allowCustomLaneChanging, bool ignoreLaneArrow //bool emergencyLaneSelection = (Options.disableSomething3 && _extVehicleType == ExtVehicleType.Emergency); + LaneConnectionManager laneConnManager = Options.laneConnectorEnabled ? LaneConnectionManager.Instance() : null; + foundForced = false; bool blocked = false; if ((nextSegment.m_flags & (NetSegment.Flags.PathFailed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None) { @@ -1938,8 +1943,8 @@ private bool ProcessItemCosts(bool allowCustomLaneChanging, bool ignoreLaneArrow } #endif - if (forceLaneId == null && !Options.disableSomething2) { - if (Singleton.instance.HasConnections(curLaneId, nextIsStartNodeOfNextSegment) && !Singleton.instance.AreLanesConnected(curLaneId, item.m_laneID, nextIsStartNodeOfNextSegment)) + if (forceLaneId == null && Options.laneConnectorEnabled) { + if (laneConnManager.HasConnections(curLaneId, nextIsStartNodeOfNextSegment) && !laneConnManager.AreLanesConnected(curLaneId, item.m_laneID, nextIsStartNodeOfNextSegment)) goto IL_8F5; } @@ -2149,10 +2154,16 @@ private bool ProcessItemCosts(bool allowCustomLaneChanging, bool ignoreLaneArrow */ // calculate speed metric - divMetric = nextSpeed * nextMaxSpeed; // 0 .. nextMaxSpeed + if (Options.disableSomething2) + divMetric = nextMaxSpeed; + else + divMetric = Options.pathCostMultiplicator2 * nextSpeed * nextMaxSpeed; // 0 .. nextMaxSpeed // calculate density metric - multMetric = Options.pathCostMultiplicator * nextDensity; // 1 .. pathCostMultiplicator + if (Options.disableSomething3) + multMetric = 1f; + else + multMetric = 1f + Options.pathCostMultiplicator * nextDensity; // 1 .. pathCostMultiplicator // calculate density/speed metric metric = Math.Max(0.01f, multMetric) / Math.Max(0.1f, divMetric); @@ -2527,7 +2538,7 @@ private void PathFindThread() { while (true) { //Log.Message($"Pathfind Thread #{Thread.CurrentThread.ManagedThreadId} iteration!"); try { - Monitor.Enter(QueueLock); + while (!Monitor.TryEnter(QueueLock, SimulationManager.SYNCHRONIZE_TIMEOUT)) { } while (QueueFirst == 0u && !Terminated) { #if DEBUGPF @@ -2570,7 +2581,9 @@ private void PathFindThread() { } //tCurrentState = 7; try { +#if DEBUGPF m_pathfindProfiler.BeginStep(); +#endif #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Calling PathFindImplementation now. Calculating={Calculating}");*/ @@ -2579,9 +2592,17 @@ private void PathFindThread() { } catch (Exception ex) { Log.Error($"THREAD #{Thread.CurrentThread.ManagedThreadId} Path find error: " + ex.ToString()); //UIView.ForwardException(ex); + +#if DEBUG + ++_failedPathFinds; +#endif + pathUnitExtVehicleType[Calculating] = null; + PathUnits.m_buffer[(int)Calculating].m_pathFindFlags |= PathUnit.FLAG_FAILED; } finally { +#if DEBUGPF m_pathfindProfiler.EndStep(); +#endif #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} last step duration: {m_pathfindProfiler.m_lastStepDuration} average step duration: {m_pathfindProfiler.m_averageStepDuration} peak step duration: {m_pathfindProfiler.m_peakStepDuration}");*/ @@ -2593,7 +2614,7 @@ private void PathFindThread() { #endif try { - Monitor.Enter(QueueLock); + while (!Monitor.TryEnter(QueueLock, SimulationManager.SYNCHRONIZE_TIMEOUT)) { } PathUnits.m_buffer[(int)((UIntPtr)Calculating)].m_pathFindFlags = (byte)(PathUnits.m_buffer[(int)((UIntPtr)Calculating)].m_pathFindFlags & -3); Singleton.instance.ReleasePath(Calculating); Calculating = 0u; @@ -2616,6 +2637,9 @@ private void PathFindThread() { /// /// protected virtual bool CanUseLane(bool debug, ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { + if (!Options.vehicleRestrictionsEnabled) + return true; + if (_extVehicleType == null || _extVehicleType == ExtVehicleType.None) return true; @@ -2625,7 +2649,7 @@ protected virtual bool CanUseLane(bool debug, ushort segmentId, NetInfo segmentI if ((laneInfo.m_vehicleType & (VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Train)) == VehicleInfo.VehicleType.None) return true; - ExtVehicleType allowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); + ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); #if DEBUGPF if (debug) { Log._Debug($"CanUseLane: segmentId={segmentId} laneIndex={laneIndex} _extVehicleType={_extVehicleType} _vehicleTypes={_vehicleTypes} _laneTypes={_laneTypes} _transportVehicle={_transportVehicle} _isHeavyVehicle={_isHeavyVehicle} allowedTypes={allowedTypes} res={((allowedTypes & _extVehicleType) != ExtVehicleType.None)}"); @@ -2644,7 +2668,7 @@ protected virtual bool CanUseLane(bool debug, ushort segmentId, NetInfo segmentI /// /// protected virtual float GetLaneSpeedLimit(ushort segmentId, uint laneIndex, uint laneId, NetInfo.Lane lane) { - return SpeedLimitManager.GetLockFreeGameSpeedLimit(segmentId, (uint)laneIndex, laneId, lane); + return Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(segmentId, (uint)laneIndex, laneId, lane) : lane.m_speedLimit; } /// diff --git a/TLM/TLM/Custom/PathFinding/CustomPathManager.cs b/TLM/TLM/Custom/PathFinding/CustomPathManager.cs index 9df059bd..6cdad9a8 100644 --- a/TLM/TLM/Custom/PathFinding/CustomPathManager.cs +++ b/TLM/TLM/Custom/PathFinding/CustomPathManager.cs @@ -96,37 +96,37 @@ public void UpdateWithPathManagerValues(PathManager stockPathManager) { InitDone = true; } - public bool CreatePath(ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, ref PathUnit.Position startPos, ref PathUnit.Position endPos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { + public bool CreatePath(ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPos, PathUnit.Position endPos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { PathUnit.Position position = default(PathUnit.Position); - return this.CreatePath(false, vehicleType, out unit, ref randomizer, buildIndex, ref startPos, ref position, ref endPos, ref position, ref position, laneTypes, vehicleTypes, maxLength, false, false, false, false, false); + return this.CreatePath(false, vehicleType, out unit, ref randomizer, buildIndex, startPos, position, endPos, position, position, laneTypes, vehicleTypes, maxLength, false, false, false, false, false); } - public bool CreatePath(ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, ref PathUnit.Position startPosA, ref PathUnit.Position startPosB, ref PathUnit.Position endPosA, ref PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { + public bool CreatePath(ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { PathUnit.Position def = default(PathUnit.Position); - return this.CreatePath(false, vehicleType, out unit, ref randomizer, buildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, ref def, laneTypes, vehicleTypes, maxLength, false, false, false, false, false); + return this.CreatePath(false, vehicleType, out unit, ref randomizer, buildIndex, startPosA, startPosB, endPosA, endPosB, def, laneTypes, vehicleTypes, maxLength, false, false, false, false, false); } - public bool CreatePath(ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, ref PathUnit.Position startPosA, ref PathUnit.Position startPosB, ref PathUnit.Position endPosA, ref PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue) { + public bool CreatePath(ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue) { PathUnit.Position def = default(PathUnit.Position); - return this.CreatePath(false, vehicleType, out unit, ref randomizer, buildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, ref def, laneTypes, vehicleTypes, maxLength, isHeavyVehicle, ignoreBlocked, stablePath, skipQueue, false); + return this.CreatePath(false, vehicleType, out unit, ref randomizer, buildIndex, startPosA, startPosB, endPosA, endPosB, def, laneTypes, vehicleTypes, maxLength, isHeavyVehicle, ignoreBlocked, stablePath, skipQueue, false); } - public bool CreatePath(bool recalc, ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, ref PathUnit.Position startPos, ref PathUnit.Position endPos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { + public bool CreatePath(bool recalc, ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPos, PathUnit.Position endPos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { PathUnit.Position position = default(PathUnit.Position); - return this.CreatePath(recalc, vehicleType, out unit, ref randomizer, buildIndex, ref startPos, ref position, ref endPos, ref position, ref position, laneTypes, vehicleTypes, maxLength, false, false, false, false, false); + return this.CreatePath(recalc, vehicleType, out unit, ref randomizer, buildIndex, startPos,position, endPos,position,position, laneTypes, vehicleTypes, maxLength, false, false, false, false, false); } - public bool CreatePath(bool recalc, ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, ref PathUnit.Position startPosA, ref PathUnit.Position startPosB, ref PathUnit.Position endPosA, ref PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { + public bool CreatePath(bool recalc, ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { PathUnit.Position def = default(PathUnit.Position); - return this.CreatePath(recalc, vehicleType, out unit, ref randomizer, buildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, ref def, laneTypes, vehicleTypes, maxLength, false, false, false, false, false); + return this.CreatePath(recalc, vehicleType, out unit, ref randomizer, buildIndex, startPosA, startPosB, endPosA, endPosB, def, laneTypes, vehicleTypes, maxLength, false, false, false, false, false); } - public bool CreatePath(bool recalc, ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, ref PathUnit.Position startPosA, ref PathUnit.Position startPosB, ref PathUnit.Position endPosA, ref PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue) { + public bool CreatePath(bool recalc, ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue) { PathUnit.Position def = default(PathUnit.Position); - return this.CreatePath(recalc, vehicleType, out unit, ref randomizer, buildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, ref def, laneTypes, vehicleTypes, maxLength, isHeavyVehicle, ignoreBlocked, stablePath, skipQueue, false); + return this.CreatePath(recalc, vehicleType, out unit, ref randomizer, buildIndex, startPosA, startPosB, endPosA, endPosB, def, laneTypes, vehicleTypes, maxLength, isHeavyVehicle, ignoreBlocked, stablePath, skipQueue, false); } - public bool CreatePath(bool recalc, ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, ref PathUnit.Position startPosA, ref PathUnit.Position startPosB, ref PathUnit.Position endPosA, ref PathUnit.Position endPosB, ref PathUnit.Position vehiclePosition, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue, bool randomParking) { + public bool CreatePath(bool recalc, ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, PathUnit.Position vehiclePosition, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue, bool randomParking) { uint num; try { Monitor.Enter(this.m_bufferLock); diff --git a/TLM/TLM/LoadingExtension.cs b/TLM/TLM/LoadingExtension.cs index ffb94619..0b8203a2 100644 --- a/TLM/TLM/LoadingExtension.cs +++ b/TLM/TLM/LoadingExtension.cs @@ -15,6 +15,7 @@ using TrafficManager.Custom.PathFinding; using TrafficManager.Util; using TrafficManager.Custom.Manager; +using System.Linq; namespace TrafficManager { public class LoadingExtension : LoadingExtensionBase { @@ -59,7 +60,7 @@ public LoadingExtension() { public void revertDetours() { if (DetourInited) { Log.Info("Revert detours"); - foreach (Detour d in Detours) { + foreach (Detour d in Detours.Reverse()) { RedirectionHelper.RevertRedirect(d.OriginalMethod, d.Redirect); } DetourInited = false; @@ -72,6 +73,204 @@ public void initDetours() { Log.Info("Init detours"); bool detourFailed = false; + // REVERSE REDIRECTION + + Log.Info("Reverse-Redirection CustomVehicleManager::ReleaseVehicleImplementation calls"); + try { + Detours.Add(new Detour(typeof(CustomVehicleManager).GetMethod("ReleaseVehicleImplementation", + BindingFlags.NonPublic | BindingFlags.Instance, + null, + new[] + { + typeof (ushort), + typeof (Vehicle).MakeByRefType(), + }, + null), + typeof(VehicleManager).GetMethod("ReleaseVehicleImplementation", + BindingFlags.NonPublic | BindingFlags.Instance, + null, + new[] + { + typeof (ushort), + typeof (Vehicle).MakeByRefType(), + }, + null))); + } catch (Exception) { + Log.Error("Could not reverse-redirect CustomVehicleManager::ReleaseVehicleImplementation"); + detourFailed = true; + } + + Log.Info("Reverse-Redirection CarAI::CheckOverlap calls"); + try { + Detours.Add(new Detour(typeof(CustomCarAI).GetMethod("CheckOverlap", + BindingFlags.NonPublic | BindingFlags.Static, + null, + new[] + { + typeof (Segment3), + typeof (ushort), + typeof (float), + }, + null), + typeof(CarAI).GetMethod("CheckOverlap", + BindingFlags.NonPublic | BindingFlags.Static, + null, + new[] + { + typeof (Segment3), + typeof (ushort), + typeof (float), + }, + null))); + } catch (Exception) { + Log.Error("Could not reverse-redirect CarAI::CheckOverlap"); + detourFailed = true; + } + + Log.Info("Reverse-Redirection TrainAI::InitializePath calls"); + try { + Detours.Add(new Detour(typeof(CustomTrainAI).GetMethod("InitializePath", + BindingFlags.NonPublic | BindingFlags.Static, + null, + new[] + { + typeof (ushort), + typeof (Vehicle).MakeByRefType() + }, + null), + typeof(TrainAI).GetMethod("InitializePath", + BindingFlags.NonPublic | BindingFlags.Static, + null, + new[] + { + typeof (ushort), + typeof (Vehicle).MakeByRefType() + }, + null))); + } catch (Exception) { + Log.Error("Could not reverse-redirect TrainAI::InitializePath"); + detourFailed = true; + } + + Log.Info("Reverse-Redirection TramBaseAI::InitializePath calls"); + try { + Detours.Add(new Detour(typeof(CustomTramBaseAI).GetMethod("InitializePath", + BindingFlags.NonPublic | BindingFlags.Static, + null, + new[] + { + typeof (ushort), + typeof (Vehicle).MakeByRefType() + }, + null), + typeof(TramBaseAI).GetMethod("InitializePath", + BindingFlags.NonPublic | BindingFlags.Static, + null, + new[] + { + typeof (ushort), + typeof (Vehicle).MakeByRefType() + }, + null))); + } catch (Exception) { + Log.Error("Could not reverse-redirect TramBaseAI::InitializePath"); + detourFailed = true; + } + + Log.Info("Reverse-Redirection CustomRoadAI::CheckBuildings calls"); + try { + Detours.Add(new Detour(typeof(CustomRoadAI).GetMethod("CheckBuildings", + BindingFlags.NonPublic | BindingFlags.Instance, + null, + new[] + { + typeof (ushort), + typeof (NetSegment).MakeByRefType(), + }, + null), + typeof(RoadBaseAI).GetMethod("CheckBuildings", + BindingFlags.NonPublic | BindingFlags.Instance, + null, + new[] + { + typeof (ushort), + typeof (NetSegment).MakeByRefType(), + }, + null))); + } catch (Exception) { + Log.Error("Could not reverse-redirect CustomRoadAI::CheckBuildings"); + 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; + } + + // FORWARD REDIRECTION + Log.Info("Redirecting Vehicle AI Calculate Segment Calls (1)"); try { Detours.Add(new Detour(typeof(VehicleAI).GetMethod("CalculateSegmentPosition", @@ -124,23 +323,44 @@ public void initDetours() { detourFailed = true; } - Log.Info("Redirection VehicleAI::ReleaseVehicle calls"); + Log.Info("Redirection VehicleManager::ReleaseVehicle calls"); try { - Detours.Add(new Detour(typeof(VehicleAI).GetMethod("ReleaseVehicle", + Detours.Add(new Detour(typeof(VehicleManager).GetMethod("ReleaseVehicle", BindingFlags.Public | BindingFlags.Instance, null, new[] { - typeof (ushort), - typeof (Vehicle).MakeByRefType() + typeof (ushort) }, null), - typeof(CustomVehicleAI).GetMethod("CustomReleaseVehicle"))); + typeof(CustomVehicleManager).GetMethod("CustomReleaseVehicle"))); } catch (Exception) { - Log.Error("Could not redirect VehicleAI::ReleaseVehicle"); + Log.Error("Could not redirect VehicleManager::ReleaseVehicle"); detourFailed = true; } + Log.Info("Redirection VehicleManager::CreateVehicle calls"); + try { + Detours.Add(new Detour(typeof(VehicleManager).GetMethod("CreateVehicle", + BindingFlags.Public | BindingFlags.Instance, + null, + new[] + { + typeof (ushort).MakeByRefType(), + typeof (Randomizer).MakeByRefType(), + typeof (VehicleInfo), + typeof (Vector3), + typeof (TransferManager.TransferReason), + typeof (bool), + typeof (bool) + }, + null), + typeof(CustomVehicleManager).GetMethod("CustomCreateVehicle"))); + } catch (Exception) { + Log.Error("Could not redirect VehicleManager::CreateVehicle calls"); + detourFailed = true; + } + Log.Info("Redirecting TramBaseAI Calculate Segment Calls (2)"); try { Detours.Add(new Detour(typeof(TramBaseAI).GetMethod("CalculateSegmentPosition", @@ -194,6 +414,19 @@ public void initDetours() { detourFailed = true; } + Log.Info("Redirecting CarAI::TrySpawn Calls"); + try { + Detours.Add(new Detour(typeof(CarAI).GetMethod("TrySpawn", + new[] { + typeof (ushort), + typeof (Vehicle).MakeByRefType() + }), + typeof(CustomCarAI).GetMethod("TrySpawn"))); + } catch (Exception) { + Log.Error("Could not redirect CarAI::TrySpawn."); + detourFailed = true; + } + Log.Info("Redirecting CarAI Simulation Step Calls"); try { Detours.Add(new Detour(typeof(CarAI).GetMethod("SimulationStep", @@ -242,6 +475,19 @@ public void initDetours() { detourFailed = true; } + Log.Info("Redirecting TrainAI::TrySpawn Calls"); + try { + Detours.Add(new Detour(typeof(TrainAI).GetMethod("TrySpawn", + new[] { + typeof (ushort), + typeof (Vehicle).MakeByRefType() + }), + typeof(CustomTrainAI).GetMethod("TrySpawn"))); + } catch (Exception) { + Log.Error("Could not redirect TrainAI::TrySpawn."); + detourFailed = true; + } + Log.Info("Redirection TramBaseAI::SimulationStep calls"); try { Detours.Add(new Detour(typeof(TramBaseAI).GetMethod("SimulationStep", @@ -259,34 +505,18 @@ public void initDetours() { detourFailed = true; } - /*++i; - Log._Debug("Redirecting Train AI Calculate Segment Calls"); + Log.Info("Redirecting TramBaseAI::TrySpawn 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]); + Detours.Add(new Detour(typeof(TramBaseAI).GetMethod("TrySpawn", + new[] { + typeof (ushort), + typeof (Vehicle).MakeByRefType() + }), + typeof(CustomTramBaseAI).GetMethod("TrySpawn"))); } catch (Exception) { - Log.Error("Could not redirect TrainAI::CalculateSegmentPosition (1)"); + Log.Error("Could not redirect TramBaseAI::TrySpawn."); detourFailed = true; - }*/ + } Log.Info("Redirecting Car AI Calculate Segment Calls"); try { @@ -710,98 +940,6 @@ public void initDetours() { Log.Error("Could not redirect RoadBaseAI::UpdateLanes"); detourFailed = true; } - - Log.Info("Reverse-Redirection CustomRoadAI::CheckBuildings calls"); - try { - Detours.Add(new Detour(typeof(CustomRoadAI).GetMethod("CheckBuildings", - BindingFlags.NonPublic | BindingFlags.Instance, - null, - new[] - { - typeof (ushort), - typeof (NetSegment).MakeByRefType(), - }, - null), - typeof(RoadBaseAI).GetMethod("CheckBuildings", - BindingFlags.NonPublic | BindingFlags.Instance, - null, - new[] - { - typeof (ushort), - typeof (NetSegment).MakeByRefType(), - }, - null))); - } catch (Exception) { - Log.Error("Could not reverse-redirect CustomRoadAI::CheckBuildings"); - 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 { @@ -931,7 +1069,7 @@ public override void OnLevelUnloading() { CustomRoadAI.OnLevelUnloading(); CustomTrafficLights.OnLevelUnloading(); TrafficLightSimulation.OnLevelUnloading(); - VehicleRestrictionsManager.OnLevelUnloading(); + VehicleRestrictionsManager.Instance().OnLevelUnloading(); Flags.OnLevelUnloading(); Translation.OnLevelUnloading(); #if TRACE @@ -982,7 +1120,7 @@ public override void OnLevelLoaded(LoadMode mode) { determinePathManagerCompatible(); IsRainfallLoaded = CheckRainfallIsLoaded(); #if DEBUG - SpeedLimitManager.GetDefaultSpeedLimits(); + SpeedLimitManager.Instance().GetDefaultSpeedLimits(); #endif if (IsPathManagerCompatible && ! IsPathManagerReplaced) { @@ -1113,14 +1251,12 @@ private bool CheckRainfallIsLoaded() { public void SetToolMode(TrafficManagerMode mode) { if (mode == ToolMode) return; - //UI.toolMode = mode; ToolMode = mode; if (mode != TrafficManagerMode.None) { - DestroyTool(); EnableTool(); } else { - DestroyTool(); + DisableTool(); } } @@ -1134,14 +1270,22 @@ public void EnableTool() { ToolsModifierControl.SetTool(); } - private void DestroyTool() { - if (TrafficManagerTool != null) { - ToolsModifierControl.toolController.CurrentTool = ToolsModifierControl.GetTool(); - ToolsModifierControl.SetTool(); + public void DisableTool() { + ToolsModifierControl.toolController.CurrentTool = ToolsModifierControl.GetTool(); + ToolsModifierControl.SetTool(); + } - Object.Destroy(TrafficManagerTool); - TrafficManagerTool = null; - } + private void DestroyTool() { + if (ToolsModifierControl.toolController != null) { + ToolsModifierControl.toolController.CurrentTool = ToolsModifierControl.GetTool(); + ToolsModifierControl.SetTool(); + + if (TrafficManagerTool != null) { + Object.Destroy(TrafficManagerTool); + TrafficManagerTool = null; + } + } else + Log.Warning("LoadingExtensions.DestroyTool: ToolsModifierControl.toolController is null!"); } } } diff --git a/TLM/TLM/Resources/lang.txt b/TLM/TLM/Resources/lang.txt index e13c507b..dd27769e 100644 --- a/TLM/TLM/Resources/lang.txt +++ b/TLM/TLM/Resources/lang.txt @@ -123,4 +123,5 @@ Default_speed_limit Default speed limit Unit_system Unit system Metric Metric Imperial Imperial -Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_de.txt b/TLM/TLM/Resources/lang_de.txt index 06d632ce..a8b44c72 100644 --- a/TLM/TLM/Resources/lang_de.txt +++ b/TLM/TLM/Resources/lang_de.txt @@ -123,4 +123,5 @@ Default_speed_limit Standard-Geschwindigkeitsbeschränkung Unit_system Einheitensystem Metric Metrisch Imperial Imperial -Use_more_CPU_cores_for_route_calculation_if_available Verwende mehr CPU-Kerne zur Routenberechnung (falls verfügbar) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Verwende mehr CPU-Kerne zur Routenberechnung (falls verfügbar) +Activated_features Aktivierte Features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_es.txt b/TLM/TLM/Resources/lang_es.txt index e1c1ec38..924d5679 100644 --- a/TLM/TLM/Resources/lang_es.txt +++ b/TLM/TLM/Resources/lang_es.txt @@ -123,4 +123,5 @@ Default_speed_limit Límite de velocidad por defecto Unit_system Sistema de medida Metric Métrico Imperial Imperial -Use_more_CPU_cores_for_route_calculation_if_available Usar más nucleos del procesador para el cálculo de rutas (si está disponible) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Usar más nucleos del procesador para el cálculo de rutas (si está disponible) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_fr.txt b/TLM/TLM/Resources/lang_fr.txt index 3f15c5aa..1d6b653a 100644 --- a/TLM/TLM/Resources/lang_fr.txt +++ b/TLM/TLM/Resources/lang_fr.txt @@ -123,4 +123,5 @@ Default_speed_limit Default speed limit Unit_system Unit system Metric Metric Imperial Imperial -Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_ja.txt b/TLM/TLM/Resources/lang_ja.txt index 962fec61..8bcc63bf 100644 --- a/TLM/TLM/Resources/lang_ja.txt +++ b/TLM/TLM/Resources/lang_ja.txt @@ -124,4 +124,5 @@ Default_speed_limit Default speed limit Unit_system Unit system Metric Metric Imperial Imperial -Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_nl.txt b/TLM/TLM/Resources/lang_nl.txt index 48288492..056527ea 100644 --- a/TLM/TLM/Resources/lang_nl.txt +++ b/TLM/TLM/Resources/lang_nl.txt @@ -123,4 +123,5 @@ Default_speed_limit Default speed limit Unit_system Unit system Metric Metric Imperial Imperial -Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_pl.txt b/TLM/TLM/Resources/lang_pl.txt index 3aaeb680..4c039f74 100644 --- a/TLM/TLM/Resources/lang_pl.txt +++ b/TLM/TLM/Resources/lang_pl.txt @@ -123,4 +123,5 @@ Default_speed_limit Domyślny limit prędkości Unit_system System jednostek Metric Metryczne Imperial Imperialne -Use_more_CPU_cores_for_route_calculation_if_available Użyj więcej rdzeni procesora do obliczania tras (jeśli dostępne) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Użyj więcej rdzeni procesora do obliczania tras (jeśli dostępne) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_pt.txt b/TLM/TLM/Resources/lang_pt.txt index 021e0139..3bf4ed67 100644 --- a/TLM/TLM/Resources/lang_pt.txt +++ b/TLM/TLM/Resources/lang_pt.txt @@ -123,4 +123,5 @@ Default_speed_limit Limite de velocidade padrão Unit_system Sistema de unidade Metric Metrico Imperial Imperial -Use_more_CPU_cores_for_route_calculation_if_available Usar mais nucleos de CPU para calcular a rota (se disponivel) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Usar mais nucleos de CPU para calcular a rota (se disponivel) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_ru.txt b/TLM/TLM/Resources/lang_ru.txt index fea3a658..12f5c8cd 100644 --- a/TLM/TLM/Resources/lang_ru.txt +++ b/TLM/TLM/Resources/lang_ru.txt @@ -123,4 +123,5 @@ Default_speed_limit Ограничение скорости по-умолчан Unit_system Системы единиц Metric Метрическая Imperial Международная -Use_more_CPU_cores_for_route_calculation_if_available Многоядерный процессор для вычисления маршрута (при наличии) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Многоядерный процессор для вычисления маршрута (при наличии) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_template.txt b/TLM/TLM/Resources/lang_template.txt index 303c3b70..1f9d5cb3 100644 --- a/TLM/TLM/Resources/lang_template.txt +++ b/TLM/TLM/Resources/lang_template.txt @@ -123,4 +123,5 @@ Default_speed_limit Unit_system Metric Imperial -Use_more_CPU_cores_for_route_calculation_if_available \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available +Activated_features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_zh-cn.txt b/TLM/TLM/Resources/lang_zh-cn.txt index bfdc5e17..061b8454 100644 --- a/TLM/TLM/Resources/lang_zh-cn.txt +++ b/TLM/TLM/Resources/lang_zh-cn.txt @@ -123,4 +123,5 @@ Default_speed_limit Default speed limit Unit_system Unit system Metric Metric Imperial Imperial -Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available Use more CPU cores for route calculation (if available) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/Resources/lang_zh-tw.txt b/TLM/TLM/Resources/lang_zh-tw.txt index 157a8133..7e4834b6 100644 --- a/TLM/TLM/Resources/lang_zh-tw.txt +++ b/TLM/TLM/Resources/lang_zh-tw.txt @@ -124,4 +124,5 @@ Default_speed_limit 預設道路速限 Unit_system 單位制 Metric 公制 Imperial 英制 -Use_more_CPU_cores_for_route_calculation_if_available 使用更多的CPU核心來做路線運算 (若有的話) \ No newline at end of file +Use_more_CPU_cores_for_route_calculation_if_available 使用更多的CPU核心來做路線運算 (若有的話) +Activated_features Activated features \ No newline at end of file diff --git a/TLM/TLM/State/Flags.cs b/TLM/TLM/State/Flags.cs index 1d71cec0..adc6fa2c 100644 --- a/TLM/TLM/State/Flags.cs +++ b/TLM/TLM/State/Flags.cs @@ -178,7 +178,7 @@ internal static bool RemoveLaneConnection(uint lane1Id, uint lane2Id, bool start ushort commonNodeId; bool startNode2; - Singleton.instance.GetCommonNodeId(lane1Id, lane2Id, startNode1, out commonNodeId, out startNode2); // TODO refactor + LaneConnectionManager.Instance().GetCommonNodeId(lane1Id, lane2Id, startNode1, out commonNodeId, out startNode2); // TODO refactor if (CleanupLaneConnections(lane1Id, lane2Id, startNode1)) ret = true; @@ -256,7 +256,7 @@ internal static bool AddLaneConnection(uint lane1Id, uint lane2Id, bool startNod ushort commonNodeId; bool startNode2; - Singleton.instance.GetCommonNodeId(lane1Id, lane2Id, startNode1, out commonNodeId, out startNode2); // TODO refactor + LaneConnectionManager.Instance().GetCommonNodeId(lane1Id, lane2Id, startNode1, out commonNodeId, out startNode2); // TODO refactor if (commonNodeId != 0) { CreateLaneConnection(lane1Id, lane2Id, startNode1); @@ -548,7 +548,7 @@ public static bool toggleLaneArrowFlags(uint laneId, bool startNode, LaneArrows return false; // disallow custom lane arrows in highway rule mode } - if (Singleton.instance.HasConnections(laneId, startNode)) { // TODO refactor + if (LaneConnectionManager.Instance().HasConnections(laneId, startNode)) { // TODO refactor res = LaneArrowChangeResult.LaneConnection; return false; // custom lane connection present } diff --git a/TLM/TLM/State/Options.cs b/TLM/TLM/State/Options.cs index 49b3d5f3..c46e91ab 100644 --- a/TLM/TLM/State/Options.cs +++ b/TLM/TLM/State/Options.cs @@ -43,6 +43,13 @@ public class Options : MonoBehaviour { #endif private static UICheckBox showLanesToggle = null; private static UIButton forgetTrafficLightsBtn = null; + + private static UICheckBox enablePrioritySignsToggle = null; + private static UICheckBox enableTimedLightsToggle = null; + private static UICheckBox enableCustomSpeedLimitsToggle = null; + private static UICheckBox enableVehicleRestrictionsToggle = null; + private static UICheckBox enableLaneConnectorToggle = null; + #if DEBUG private static UIButton resetSpeedLimitsBtn = null; private static UICheckBox disableSomething5Toggle = null; @@ -67,6 +74,7 @@ public class Options : MonoBehaviour { private static UIHelperBase aiGroup = null; private static UIHelperBase overlayGroup = null; private static UIHelperBase maintenanceGroup = null; + private static UIHelperBase featureGroup = null; public static int simAccuracy = 1; //public static int laneChangingRandomization = 2; @@ -91,8 +99,8 @@ public class Options : MonoBehaviour { public static bool enableDespawning = true; public static bool preferOuterLane = false; //public static byte publicTransportUsage = 1; - public static float pathCostMultiplicator = 1f; // debug value - public static float pathCostMultiplicator2 = 0f; // debug value + public static float pathCostMultiplicator = 0.75f; // debug value + public static float pathCostMultiplicator2 = 1f; // debug value public static bool disableSomething1 = false; // debug switch public static bool disableSomething2 = false; // debug switch public static bool disableSomething3 = false; // debug switch @@ -108,6 +116,23 @@ public class Options : MonoBehaviour { public static float someValue8 = 3f; // debug value public static float someValue9 = 0.8f; // debug value + public static bool prioritySignsEnabled = true; + public static bool timedLightsEnabled = true; + public static bool customSpeedLimitsEnabled = true; + public static bool vehicleRestrictionsEnabled = true; + public static bool laneConnectorEnabled = true; + + public static bool MenuRebuildRequired { + get { return menuRebuildRequired; } + private set { + menuRebuildRequired = value; + if (LoadingExtension.Instance.UI != null) + LoadingExtension.Instance.UI.Close(); + } + } + + private static bool menuRebuildRequired = false; + public static void makeSettings(UIHelperBase helper) { mainGroup = helper.AddGroup(Translation.GetString("TMPE_Title")); simAccuracyDropdown = mainGroup.AddDropdown(Translation.GetString("Simulation_accuracy") + ":", new string[] { Translation.GetString("Very_high"), Translation.GetString("High"), Translation.GetString("Medium"), Translation.GetString("Low"), Translation.GetString("Very_Low") }, simAccuracy, onSimAccuracyChanged) as UIDropDown; @@ -132,6 +157,13 @@ public static void makeSettings(UIHelperBase helper) { #if DEBUG preferOuterLaneToggle = aiGroup.AddCheckbox(Translation.GetString("Prefer_outer_lane") + " (BETA feature)", preferOuterLane, onPreferOuterLaneChanged) as UICheckBox; #endif + featureGroup = helper.AddGroup(Translation.GetString("Activated_features")); + enablePrioritySignsToggle = featureGroup.AddCheckbox(Translation.GetString("Priority_signs"), prioritySignsEnabled, onPrioritySignsEnabledChanged) as UICheckBox; + enableTimedLightsToggle = featureGroup.AddCheckbox(Translation.GetString("Timed_traffic_lights"), timedLightsEnabled, onTimedLightsEnabledChanged) as UICheckBox; + enableCustomSpeedLimitsToggle = featureGroup.AddCheckbox(Translation.GetString("Speed_limits"), customSpeedLimitsEnabled, onCustomSpeedLimitsEnabledChanged) as UICheckBox; + enableVehicleRestrictionsToggle = featureGroup.AddCheckbox(Translation.GetString("Vehicle_restrictions"), vehicleRestrictionsEnabled, onVehicleRestrictionsEnabledChanged) as UICheckBox; + enableLaneConnectorToggle = featureGroup.AddCheckbox(Translation.GetString("Lane_connector"), laneConnectorEnabled, onLaneConnectorEnabledChanged) as UICheckBox; + //laneChangingRandomizationDropdown = aiGroup.AddDropdown(Translation.GetString("Drivers_want_to_change_lanes_(only_applied_if_Advanced_AI_is_enabled):"), new string[] { Translation.GetString("Very_often") + " (50 %)", Translation.GetString("Often") + " (25 %)", Translation.GetString("Sometimes") + " (10 %)", Translation.GetString("Rarely") + " (5 %)", Translation.GetString("Very_rarely") + " (2.5 %)", Translation.GetString("Only_if_necessary") }, laneChangingRandomization, onLaneChangingRandomizationChanged) as UIDropDown; overlayGroup = helper.AddGroup(Translation.GetString("Persistently_visible_overlays")); prioritySignsOverlayToggle = overlayGroup.AddCheckbox(Translation.GetString("Priority_signs"), prioritySignsOverlay, onPrioritySignsOverlayChanged) as UICheckBox; @@ -346,6 +378,60 @@ private static void onPreferOuterLaneChanged(bool val) { preferOuterLane = val; } + private static void onPrioritySignsEnabledChanged(bool val) { + if (!checkGameLoaded()) + return; + + MenuRebuildRequired = true; + prioritySignsEnabled = val; + if (val) + VehicleStateManager.Instance().InitAllVehicles(); + else + setPrioritySignsOverlay(false); + } + + private static void onTimedLightsEnabledChanged(bool val) { + if (!checkGameLoaded()) + return; + + MenuRebuildRequired = true; + timedLightsEnabled = val; + if (val) + VehicleStateManager.Instance().InitAllVehicles(); + else + setTimedLightsOverlay(false); + } + + private static void onCustomSpeedLimitsEnabledChanged(bool val) { + if (!checkGameLoaded()) + return; + + MenuRebuildRequired = true; + customSpeedLimitsEnabled = val; + if (!val) + setSpeedLimitsOverlay(false); + } + + private static void onVehicleRestrictionsEnabledChanged(bool val) { + if (!checkGameLoaded()) + return; + + MenuRebuildRequired = true; + vehicleRestrictionsEnabled = val; + if (!val) + setVehicleRestrictionsOverlay(false); + } + + private static void onLaneConnectorEnabledChanged(bool val) { + if (!checkGameLoaded()) + return; + + MenuRebuildRequired = true; + laneConnectorEnabled = val; + if (!val) + setConnectedLanesOverlay(false); + } + private static void onDynamicPathRecalculationChanged(bool value) { if (!checkGameLoaded()) return; @@ -804,6 +890,51 @@ public static void setVehicleOverlay(bool newVal) { vehicleOverlayToggle.isChecked = newVal; } + public static void setPrioritySignsEnabled(bool newValue) { + MenuRebuildRequired = true; + prioritySignsEnabled = newValue; + if (enablePrioritySignsToggle != null) + enablePrioritySignsToggle.isChecked = newValue; + if (!newValue) + setPrioritySignsOverlay(false); + } + + public static void setTimedLightsEnabled(bool newValue) { + MenuRebuildRequired = true; + timedLightsEnabled = newValue; + if (enableTimedLightsToggle != null) + enableTimedLightsToggle.isChecked = newValue; + if (!newValue) + setTimedLightsOverlay(false); + } + + public static void setCustomSpeedLimitsEnabled(bool newValue) { + MenuRebuildRequired = true; + customSpeedLimitsEnabled = newValue; + if (enableCustomSpeedLimitsToggle != null) + enableCustomSpeedLimitsToggle.isChecked = newValue; + if (!newValue) + setSpeedLimitsOverlay(false); + } + + public static void setVehicleRestrictionsEnabled(bool newValue) { + MenuRebuildRequired = true; + vehicleRestrictionsEnabled = newValue; + if (enableVehicleRestrictionsToggle != null) + enableVehicleRestrictionsToggle.isChecked = newValue; + if (!newValue) + setVehicleRestrictionsOverlay(false); + } + + public static void setLaneConnectorEnabled(bool newValue) { + MenuRebuildRequired = true; + laneConnectorEnabled = newValue; + if (enableLaneConnectorToggle != null) + enableLaneConnectorToggle.isChecked = newValue; + if (!newValue) + setConnectedLanesOverlay(false); + } + /*internal static int getLaneChangingRandomizationTargetValue() { int ret = 100; switch (laneChangingRandomization) { diff --git a/TLM/TLM/State/SerializableDataExtension.cs b/TLM/TLM/State/SerializableDataExtension.cs index 1ee74bd2..fa701ee5 100644 --- a/TLM/TLM/State/SerializableDataExtension.cs +++ b/TLM/TLM/State/SerializableDataExtension.cs @@ -41,7 +41,7 @@ public override void OnLoadData() { Log.Info("Initializing segment geometries"); SegmentGeometry.OnBeforeLoadData(); Log.Info("Initializing lane connection manager"); - Singleton.instance.OnBeforeLoadData(); // requires segment geometries + LaneConnectionManager.Instance().OnBeforeLoadData(); // requires segment geometries Log.Info("Initializing CustomRoadAI"); CustomRoadAI.OnBeforeLoadData(); Log.Info("Initialization done. Loading mod data now."); @@ -130,6 +130,26 @@ public override void OnLoadData() { if (options.Length >= 18) { Options.setConnectedLanesOverlay(options[17] == (byte)1); } + + if (options.Length >= 19) { + Options.setPrioritySignsEnabled(options[18] == (byte)1); + } + + if (options.Length >= 20) { + Options.setTimedLightsEnabled(options[19] == (byte)1); + } + + if (options.Length >= 21) { + Options.setCustomSpeedLimitsEnabled(options[20] == (byte)1); + } + + if (options.Length >= 22) { + Options.setVehicleRestrictionsEnabled(options[21] == (byte)1); + } + + if (options.Length >= 23) { + Options.setLaneConnectorEnabled(options[22] == (byte)1); + } } } catch (Exception e) { Log.Error($"OnLoadData: {e.ToString()}"); @@ -159,11 +179,11 @@ private static void DeserializeData(byte[] data) { } catch (Exception e) { Log.Error($"Error deserializing data: {e.Message}"); } - + LoadDataState(); Flags.clearHighwayLaneArrows(); Flags.applyAllFlags(); - VehicleStateManager.InitAllVehicles(); + VehicleStateManager.Instance().InitAllVehicles(); } private static void LoadDataState() { @@ -232,7 +252,7 @@ private static void LoadDataState() { Log.Info($"Loading lane vehicle restriction data. {_configuration.LaneAllowedVehicleTypes.Count} elements"); foreach (Configuration.LaneVehicleTypes laneVehicleTypes in _configuration.LaneAllowedVehicleTypes) { try { - ExtVehicleType baseMask = VehicleRestrictionsManager.GetBaseMask(laneVehicleTypes.laneId); + ExtVehicleType baseMask = VehicleRestrictionsManager.Instance().GetBaseMask(laneVehicleTypes.laneId); ExtVehicleType maskedType = laneVehicleTypes.vehicleTypes & baseMask; Log._Debug($"Loading lane vehicle restriction: lane {laneVehicleTypes.laneId} = {laneVehicleTypes.vehicleTypes}, masked = {maskedType}"); if (maskedType != baseMask) { @@ -512,7 +532,7 @@ private static void LoadDataState() { foreach (Configuration.LaneConnection conn in _configuration.LaneConnections) { try { Log._Debug($"Loading lane connection: lane {conn.lowerLaneId} -> {conn.higherLaneId}"); - Singleton.instance.AddLaneConnection(conn.lowerLaneId, conn.higherLaneId, conn.lowerStartNode); + LaneConnectionManager.Instance().AddLaneConnection(conn.lowerLaneId, conn.higherLaneId, conn.lowerStartNode); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading data from lane connection: " + e.ToString()); @@ -560,6 +580,8 @@ private static void LoadDataState() { public override void OnSaveData() { Log.Info("Recalculating segment geometries"); SegmentGeometry.OnBeforeSaveData(); + Log.Info("Applying all flags"); + Flags.applyAllFlags(); Log.Info("Saving Mod Data."); var configuration = new Configuration(); @@ -663,7 +685,12 @@ public override void OnSaveData() { (byte)(Options.allowLaneChangesWhileGoingStraight ? 1 : 0), (byte)(Options.enableDespawning ? 1 : 0), (byte)(Options.IsDynamicPathRecalculationActive() ? 1 : 0), - (byte)(Options.connectedLanesOverlay ? 1 : 0) + (byte)(Options.connectedLanesOverlay ? 1 : 0), + (byte)(Options.prioritySignsEnabled ? 1 : 0), + (byte)(Options.timedLightsEnabled ? 1 : 0), + (byte)(Options.customSpeedLimitsEnabled ? 1 : 0), + (byte)(Options.vehicleRestrictionsEnabled ? 1 : 0), + (byte)(Options.laneConnectorEnabled ? 1 : 0) }); } catch (Exception ex) { Log.Error("Unexpected error saving data: " + ex.Message); diff --git a/TLM/TLM/TLM.csproj b/TLM/TLM/TLM.csproj index da97e77a..2e2b9454 100644 --- a/TLM/TLM/TLM.csproj +++ b/TLM/TLM/TLM.csproj @@ -70,12 +70,12 @@ + - @@ -107,6 +107,7 @@ + diff --git a/TLM/TLM/Traffic/LaneConnectionManager.cs b/TLM/TLM/Traffic/LaneConnectionManager.cs index 2f95ecf0..af22a1de 100644 --- a/TLM/TLM/Traffic/LaneConnectionManager.cs +++ b/TLM/TLM/Traffic/LaneConnectionManager.cs @@ -11,7 +11,19 @@ using UnityEngine; namespace TrafficManager.Traffic { - public class LaneConnectionManager : Singleton, IObserver { + public class LaneConnectionManager : IObserver { + private static LaneConnectionManager instance = null; + + public static LaneConnectionManager Instance() { + if (instance == null) + instance = new LaneConnectionManager(); + return instance; + } + + static LaneConnectionManager() { + Instance(); + } + private Dictionary segGeometryUnsubscribers = new Dictionary(); private object geoLock = new object(); diff --git a/TLM/TLM/Traffic/SegmentEnd.cs b/TLM/TLM/Traffic/SegmentEnd.cs index 772a580c..ad720a58 100644 --- a/TLM/TLM/Traffic/SegmentEnd.cs +++ b/TLM/TLM/Traffic/SegmentEnd.cs @@ -92,13 +92,14 @@ internal void RequestCleanup() { internal void SimulationStep() { if (cleanupRequested) { VehicleManager vehManager = Singleton.instance; + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); #if DEBUG //Log._Debug($"Cleanup of SegmentEnd {SegmentId} @ {NodeId} requested. Performing cleanup now."); #endif ushort vehicleId = FirstRegisteredVehicleId; while (vehicleId != 0) { - VehicleState state = VehicleStateManager._GetVehicleState(vehicleId); + VehicleState state = vehStateManager._GetVehicleState(vehicleId); bool removeVehicle = false; if (!state.Valid) { @@ -128,6 +129,7 @@ public Dictionary GetVehicleMetricGoingToSegment(bool includeStopp #endif VehicleManager vehicleManager = Singleton.instance; NetManager netManager = Singleton.instance; + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); Dictionary ret = includeStopped ? numVehiclesGoingToSegmentId : numVehiclesFlowingToSegmentId; @@ -151,7 +153,7 @@ public Dictionary GetVehicleMetricGoingToSegment(bool includeStopp ushort vehicleId = FirstRegisteredVehicleId; int numProcessed = 0; while (vehicleId != 0) { - VehicleState state = VehicleStateManager._GetVehicleState(vehicleId); + VehicleState state = vehStateManager._GetVehicleState(vehicleId); bool breakLoop = false; @@ -241,11 +243,13 @@ public Dictionary GetVehicleMetricGoingToSegment(bool includeStopp } internal int GetRegisteredVehicleCount() { + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); + ushort vehicleId = FirstRegisteredVehicleId; int ret = 0; while (vehicleId != 0) { ++ret; - vehicleId = VehicleStateManager._GetVehicleState(vehicleId).NextVehicleIdOnSegment; + vehicleId = vehStateManager._GetVehicleState(vehicleId).NextVehicleIdOnSegment; } return ret; } @@ -259,8 +263,9 @@ internal void Destroy() { } private void UnregisterAllVehicles() { + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); while (FirstRegisteredVehicleId != 0) { - VehicleStateManager._GetVehicleState(FirstRegisteredVehicleId).Unlink(); + vehStateManager._GetVehicleState(FirstRegisteredVehicleId).Unlink(); } } diff --git a/TLM/TLM/Traffic/SegmentGeometry.cs b/TLM/TLM/Traffic/SegmentGeometry.cs index 4a42a5b2..b438c01e 100644 --- a/TLM/TLM/Traffic/SegmentGeometry.cs +++ b/TLM/TLM/Traffic/SegmentGeometry.cs @@ -1090,7 +1090,7 @@ private void cleanup() { Flags.removeHighwayLaneArrowFlagsAtSegment(SegmentId); // TODO refactor // clear default vehicle type cache - VehicleRestrictionsManager.ClearCache(SegmentId); + VehicleRestrictionsManager.Instance().ClearCache(SegmentId); } finally { Monitor.Exit(Lock); } diff --git a/TLM/TLM/Traffic/SpeedLimitManager.cs b/TLM/TLM/Traffic/SpeedLimitManager.cs index 8d7e7b6b..78a4a589 100644 --- a/TLM/TLM/Traffic/SpeedLimitManager.cs +++ b/TLM/TLM/Traffic/SpeedLimitManager.cs @@ -4,12 +4,26 @@ using System.Linq; using System.Text; using TrafficManager.State; +using UnityEngine; namespace TrafficManager.Traffic { - class SpeedLimitManager { - public static readonly List AvailableSpeedLimits; + public class SpeedLimitManager { + private static SpeedLimitManager instance = null; + private static readonly float MAX_SPEED = 6f; // 300 km/h + + public static SpeedLimitManager Instance() { + if (instance == null) + instance = new SpeedLimitManager(); + return instance; + } static SpeedLimitManager() { + Instance(); + } + + public readonly List AvailableSpeedLimits; + + private SpeedLimitManager() { AvailableSpeedLimits = new List(); AvailableSpeedLimits.Add(10); AvailableSpeedLimits.Add(20); @@ -33,7 +47,7 @@ static SpeedLimitManager() { /// /// /// - public static ushort GetCustomSpeedLimit(ushort segmentId, NetInfo.Direction finalDir) { + public ushort GetCustomSpeedLimit(ushort segmentId, NetInfo.Direction finalDir) { #if TRACE Singleton.instance.Start("SpeedLimitManager.GetCustomSpeedLimit1"); #endif @@ -69,7 +83,7 @@ public static ushort GetCustomSpeedLimit(ushort segmentId, NetInfo.Direction fin if (validLanes > 0) meanSpeedLimit /= (float)validLanes; - ushort ret = ToCustomSpeedLimit(meanSpeedLimit); + ushort ret = LaneToCustomSpeedLimit(meanSpeedLimit); #if TRACE Singleton.instance.Stop("SpeedLimitManager.GetCustomSpeedLimit1"); #endif @@ -83,7 +97,7 @@ public static ushort GetCustomSpeedLimit(ushort segmentId, NetInfo.Direction fin /// /// /// - public static ushort GetAverageDefaultCustomSpeedLimit(NetInfo segmentInfo, NetInfo.Direction? finalDir=null) { + public ushort GetAverageDefaultCustomSpeedLimit(NetInfo segmentInfo, NetInfo.Direction? finalDir=null) { #if TRACE Singleton.instance.Start("SpeedLimitManager.GetAverageDefaultCustomSpeedLimit"); #endif @@ -102,7 +116,7 @@ public static ushort GetAverageDefaultCustomSpeedLimit(NetInfo segmentInfo, NetI if (validLanes > 0) meanSpeedLimit /= (float)validLanes; - ushort ret = ToCustomSpeedLimit(meanSpeedLimit); + ushort ret = LaneToCustomSpeedLimit(meanSpeedLimit); #if TRACE Singleton.instance.Stop("SpeedLimitManager.GetAverageDefaultCustomSpeedLimit"); #endif @@ -115,7 +129,7 @@ public static ushort GetAverageDefaultCustomSpeedLimit(NetInfo segmentInfo, NetI /// /// /// - public static ushort GetCustomSpeedLimit(uint laneId) { + public ushort GetCustomSpeedLimit(uint laneId) { #if TRACE Singleton.instance.Start("SpeedLimitManager.GetCustomSpeedLimit2"); #endif @@ -144,7 +158,7 @@ public static ushort GetCustomSpeedLimit(uint laneId) { int laneIndex = 0; while (laneIndex < segmentInfo.m_lanes.Length && curLaneId != 0u) { if (curLaneId == laneId) { - ushort ret = ToCustomSpeedLimit(segmentInfo.m_lanes[laneIndex].m_speedLimit); + ushort ret = LaneToCustomSpeedLimit(segmentInfo.m_lanes[laneIndex].m_speedLimit); #if TRACE Singleton.instance.Stop("SpeedLimitManager.GetCustomSpeedLimit2"); #endif @@ -167,11 +181,11 @@ public static ushort GetCustomSpeedLimit(uint laneId) { /// /// /// - public static float GetGameSpeedLimit(uint laneId) { + public float GetGameSpeedLimit(uint laneId) { return ToGameSpeedLimit(GetCustomSpeedLimit(laneId)); } - internal static float GetLockFreeGameSpeedLimit(ushort segmentId, uint laneIndex, uint laneId, NetInfo.Lane laneInfo) { + internal float GetLockFreeGameSpeedLimit(ushort segmentId, uint laneIndex, uint laneId, NetInfo.Lane laneInfo) { #if TRACE Singleton.instance.Start("SpeedLimitManager.GetLockFreeGameSpeedLimit"); #endif @@ -209,34 +223,47 @@ internal static float GetLockFreeGameSpeedLimit(ushort segmentId, uint laneIndex /// /// /// - public static float ToGameSpeedLimit(ushort customSpeedLimit) { + public float ToGameSpeedLimit(ushort customSpeedLimit) { if (customSpeedLimit == 0) - return 4f; + return MAX_SPEED; return (float)customSpeedLimit / 50f; } /// - /// Converts a game speed limit to a custom speed limit. + /// Converts a lane speed limit to a custom speed limit. /// - /// + /// /// - public static ushort ToCustomSpeedLimit(float gameSpeedLimit) { - gameSpeedLimit /= 2f; // 1 == 100 km/h + public ushort LaneToCustomSpeedLimit(float laneSpeedLimit, bool roundToSignLimits=true) { + laneSpeedLimit /= 2f; // 1 == 100 km/h + + if (! roundToSignLimits) { + return (ushort)Mathf.Round(laneSpeedLimit * 100f); + } // translate the floating point speed limit into our discrete version ushort speedLimit = 0; - if (gameSpeedLimit < 0.15f) + if (laneSpeedLimit < 0.15f) speedLimit = 10; - else if (gameSpeedLimit < 1.15f) - speedLimit = (ushort)((ushort)Math.Round(gameSpeedLimit * 10f) * 10u); - else if (gameSpeedLimit < 1.25f) + else if (laneSpeedLimit < 1.15f) + speedLimit = (ushort)((ushort)Math.Round(laneSpeedLimit * 10f) * 10u); + else if (laneSpeedLimit < 1.25f) speedLimit = 120; - else if (gameSpeedLimit < 1.35f) + else if (laneSpeedLimit < 1.35f) speedLimit = 130; return speedLimit; } + /// + /// Converts a vehicle's velocity to a custom speed. + /// + /// + /// + public ushort VehicleToCustomSpeed(float vehicleSpeed) { + return LaneToCustomSpeedLimit(vehicleSpeed / 8f, false); + } + /// /// Sets the speed limit of a given segment and lane direction. /// @@ -244,7 +271,7 @@ public static ushort ToCustomSpeedLimit(float gameSpeedLimit) { /// /// /// - public static bool SetSpeedLimit(ushort segmentId, NetInfo.Direction finalDir, ushort speedLimit) { + public bool SetSpeedLimit(ushort segmentId, NetInfo.Direction finalDir, ushort speedLimit) { #if TRACE Singleton.instance.Start("SpeedLimitManager.SetSpeedLimit"); #endif @@ -262,7 +289,9 @@ public static bool SetSpeedLimit(ushort segmentId, NetInfo.Direction finalDir, u if ((Singleton.instance.m_segments.m_buffer[segmentId].Info.m_lanes[laneIndex].m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) == NetInfo.LaneType.None || d != finalDir) goto nextIter; +#if DEBUG Log._Debug($"SpeedLimitManager: Setting speed limit of lane {curLaneId} to {speedLimit}"); +#endif Flags.setLaneSpeedLimit(curLaneId, speedLimit); nextIter: @@ -276,7 +305,8 @@ public static bool SetSpeedLimit(ushort segmentId, NetInfo.Direction finalDir, u return true; } - public static Dictionary GetDefaultSpeedLimits() { +#if DEBUG + public Dictionary GetDefaultSpeedLimits() { Dictionary ret = new Dictionary(); int numLoaded = PrefabCollection.LoadedCount(); for (uint i = 0; i < numLoaded; ++i) { @@ -287,5 +317,6 @@ public static Dictionary GetDefaultSpeedLimits() { } return ret; } +#endif } } diff --git a/TLM/TLM/Traffic/TrafficPriority.cs b/TLM/TLM/Traffic/TrafficPriority.cs index 353aa118..31578905 100644 --- a/TLM/TLM/Traffic/TrafficPriority.cs +++ b/TLM/TLM/Traffic/TrafficPriority.cs @@ -328,7 +328,8 @@ public static bool HasIncomingVehiclesWithHigherPriority(ushort targetVehicleId, try { VehicleManager vehManager = Singleton.instance; NetManager netManager = Singleton.instance; - LaneConnectionManager connManager = Singleton.instance; + LaneConnectionManager connManager = LaneConnectionManager.Instance(); + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); uint frame = Singleton.instance.m_currentFrameIndex; @@ -445,7 +446,7 @@ public static bool HasIncomingVehiclesWithHigherPriority(ushort targetVehicleId, } #endif - VehicleState incomingState = VehicleStateManager._GetVehicleState(incomingVehicleId); + VehicleState incomingState = vehStateManager._GetVehicleState(incomingVehicleId); if (! incomingState.Valid) { #if DEBUG if (debug) diff --git a/TLM/TLM/Traffic/VehiclePosition.cs b/TLM/TLM/Traffic/VehiclePosition.cs deleted file mode 100644 index 08fe71b6..00000000 --- a/TLM/TLM/Traffic/VehiclePosition.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace TrafficManager.Traffic { - public struct VehiclePosition { - /// - /// Vehicle is coming from this segment/lane ... - /// - public ushort SourceSegmentId; - public byte SourceLaneIndex; - - /// - /// ... goes over this node ... - /// - public ushort TransitNodeId; - - /// - /// ... and goes to this segment/lane - /// - public ushort TargetSegmentId; - public byte TargetLaneIndex; - - public VehiclePosition(ushort sourceSegmentId, byte sourceLaneIndex, ushort targetNodeId, ushort targetSegmentId, byte targetLaneIndex) { - SourceSegmentId = sourceSegmentId; - SourceLaneIndex = sourceLaneIndex; - TransitNodeId = targetNodeId; - TargetSegmentId = targetSegmentId; - TargetLaneIndex = targetLaneIndex; - } - } -} diff --git a/TLM/TLM/Traffic/VehicleRestrictionsManager.cs b/TLM/TLM/Traffic/VehicleRestrictionsManager.cs index d29cb5a3..e9fe8c63 100644 --- a/TLM/TLM/Traffic/VehicleRestrictionsManager.cs +++ b/TLM/TLM/Traffic/VehicleRestrictionsManager.cs @@ -7,12 +7,24 @@ namespace TrafficManager.Traffic { class VehicleRestrictionsManager { + private static VehicleRestrictionsManager instance = null; + + public static VehicleRestrictionsManager Instance() { + if (instance == null) + instance = new VehicleRestrictionsManager(); + return instance; + } + + static VehicleRestrictionsManager() { + Instance(); + } + /// /// For each segment id and lane index: Holds the default set of vehicle types allowed for the lane /// - private static ExtVehicleType?[][] defaultVehicleTypeCache = null; + private ExtVehicleType?[][] defaultVehicleTypeCache = null; - internal static void OnLevelUnloading() { + internal void OnLevelUnloading() { defaultVehicleTypeCache = null; } @@ -22,7 +34,7 @@ internal static void OnLevelUnloading() { /// /// /// - internal static ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, ushort nodeId) { // TODO optimize method (don't depend on collections!) + internal ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, ushort nodeId) { // TODO optimize method (don't depend on collections!) #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.GetAllowedVehicleTypes(1)"); #endif @@ -42,7 +54,7 @@ internal static ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, ushort n /// /// /// - internal static HashSet GetAllowedVehicleTypesAsSet(ushort segmentId, ushort nodeId) { + internal HashSet GetAllowedVehicleTypesAsSet(ushort segmentId, ushort nodeId) { #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.GetAllowedVehicleTypesAsSet"); #endif @@ -59,7 +71,7 @@ internal static HashSet GetAllowedVehicleTypesAsSet(ushort segme /// /// /// - internal static Dictionary GetAllowedVehicleTypesAsDict(ushort segmentId, ushort nodeId) { + internal Dictionary GetAllowedVehicleTypesAsDict(ushort segmentId, ushort nodeId) { #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.GetAllowedVehicleTypesAsDict"); #endif @@ -109,7 +121,7 @@ internal static Dictionary GetAllowedVehicleTypesAsDict(us /// /// /// - internal static ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { + internal ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.GetAllowedVehicleTypes(2)"); #endif @@ -129,7 +141,7 @@ internal static ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, NetInfo return GetDefaultAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); } - internal static bool HasSegmentRestrictions(ushort segmentId) { // TODO clean up restrictions (currently we do not check if restrictions are equal with the base type) + internal bool HasSegmentRestrictions(ushort segmentId) { // TODO clean up restrictions (currently we do not check if restrictions are equal with the base type) #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.GetAllowedVehicleTypes(2)"); #endif @@ -152,7 +164,7 @@ internal static ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, NetInfo /// /// /// - public static ExtVehicleType GetDefaultAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { + public ExtVehicleType GetDefaultAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.GetDefaultAllowedVehicleTypes"); #endif @@ -204,7 +216,7 @@ public static ExtVehicleType GetDefaultAllowedVehicleTypes(ushort segmentId, Net /// /// /// - internal static ExtVehicleType GetDefaultAllowedVehicleTypes(uint laneId) { + internal ExtVehicleType GetDefaultAllowedVehicleTypes(uint laneId) { if (((NetLane.Flags)Singleton.instance.m_lanes.m_buffer[laneId].m_flags & NetLane.Flags.Created) == NetLane.Flags.None) return ExtVehicleType.None; ushort segmentId = Singleton.instance.m_lanes.m_buffer[laneId].m_segment; @@ -235,7 +247,7 @@ internal static ExtVehicleType GetDefaultAllowedVehicleTypes(uint laneId) { /// /// /// - internal static bool SetAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo, uint laneId, ExtVehicleType allowedTypes) { + internal bool SetAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo, uint laneId, ExtVehicleType allowedTypes) { #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.SetAllowedVehicleTypes"); #endif @@ -265,7 +277,7 @@ internal static bool SetAllowedVehicleTypes(ushort segmentId, NetInfo segmentInf /// /// /// - public static void AddAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType) { + public void AddAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType) { #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.AddAllowedType"); #endif @@ -296,7 +308,7 @@ public static void AddAllowedType(ushort segmentId, NetInfo segmentInfo, uint la /// /// /// - public static void RemoveAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType) { + public void RemoveAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType) { #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.RemoveAllowedType"); #endif @@ -318,7 +330,7 @@ public static void RemoveAllowedType(ushort segmentId, NetInfo segmentInfo, uint #endif } - public static void ToggleAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType, bool add) { + public void ToggleAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType, bool add) { #if TRACE Singleton.instance.Start("VehicleRestrictionsManager.ToggleAllowedType"); #endif @@ -336,7 +348,7 @@ public static void ToggleAllowedType(ushort segmentId, NetInfo segmentInfo, uint /// /// /// - public static ExtVehicleType GetBaseMask(NetInfo.Lane laneInfo) { + public ExtVehicleType GetBaseMask(NetInfo.Lane laneInfo) { if (IsRoadLane(laneInfo)) return ExtVehicleType.RoadVehicle; else if (IsRailLane(laneInfo)) @@ -350,7 +362,7 @@ public static ExtVehicleType GetBaseMask(NetInfo.Lane laneInfo) { /// /// /// - public static ExtVehicleType GetBaseMask(uint laneId) { + public ExtVehicleType GetBaseMask(uint laneId) { if (((NetLane.Flags)Singleton.instance.m_lanes.m_buffer[laneId].m_flags & NetLane.Flags.Created) == NetLane.Flags.None) return ExtVehicleType.None; ushort segmentId = Singleton.instance.m_lanes.m_buffer[laneId].m_segment; @@ -372,83 +384,83 @@ public static ExtVehicleType GetBaseMask(uint laneId) { return ExtVehicleType.None; } - public static bool IsAllowed(ExtVehicleType? allowedTypes, ExtVehicleType vehicleType) { + public bool IsAllowed(ExtVehicleType? allowedTypes, ExtVehicleType vehicleType) { return allowedTypes == null || ((ExtVehicleType)allowedTypes & vehicleType) != ExtVehicleType.None; } - public static bool IsBicycleAllowed(ExtVehicleType? allowedTypes) { + public bool IsBicycleAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Bicycle); } - public static bool IsBusAllowed(ExtVehicleType? allowedTypes) { + public bool IsBusAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Bus); } - public static bool IsCargoTrainAllowed(ExtVehicleType? allowedTypes) { + public bool IsCargoTrainAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.CargoTrain); } - public static bool IsCargoTruckAllowed(ExtVehicleType? allowedTypes) { + public bool IsCargoTruckAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.CargoTruck); } - public static bool IsEmergencyAllowed(ExtVehicleType? allowedTypes) { + public bool IsEmergencyAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Emergency); } - public static bool IsPassengerCarAllowed(ExtVehicleType? allowedTypes) { + public bool IsPassengerCarAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.PassengerCar); } - public static bool IsPassengerTrainAllowed(ExtVehicleType? allowedTypes) { + public bool IsPassengerTrainAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.PassengerTrain); } - public static bool IsServiceAllowed(ExtVehicleType? allowedTypes) { + public bool IsServiceAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Service); } - public static bool IsTaxiAllowed(ExtVehicleType? allowedTypes) { + public bool IsTaxiAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Taxi); } - public static bool IsTramAllowed(ExtVehicleType? allowedTypes) { + public bool IsTramAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Tram); } - public static bool IsRailVehicleAllowed(ExtVehicleType? allowedTypes) { + public bool IsRailVehicleAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.RailVehicle); } - public static bool IsRoadVehicleAllowed(ExtVehicleType? allowedTypes) { + public bool IsRoadVehicleAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.RoadVehicle); } - public static bool IsRailLane(NetInfo.Lane laneInfo) { + public bool IsRailLane(NetInfo.Lane laneInfo) { return (laneInfo.m_vehicleType & VehicleInfo.VehicleType.Train) != VehicleInfo.VehicleType.None; } - public static bool IsRoadLane(NetInfo.Lane laneInfo) { + public bool IsRoadLane(NetInfo.Lane laneInfo) { return (laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None; } - public static bool IsRailSegment(NetInfo segmentInfo) { + public bool IsRailSegment(NetInfo segmentInfo) { ItemClass connectionClass = segmentInfo.GetConnectionClass(); return connectionClass.m_service == ItemClass.Service.PublicTransport && connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain; } - public static bool IsRoadSegment(NetInfo segmentInfo) { + public bool IsRoadSegment(NetInfo segmentInfo) { ItemClass connectionClass = segmentInfo.GetConnectionClass(); return connectionClass.m_service == ItemClass.Service.Road; } - internal static void ClearCache(ushort segmentId) { + internal void ClearCache(ushort segmentId) { if (defaultVehicleTypeCache != null) { defaultVehicleTypeCache[segmentId] = null; } } - public static void NotifyStartEndNode(ushort segmentId) { + public void NotifyStartEndNode(ushort segmentId) { // notify observers of start node and end node ushort startNodeId = Singleton.instance.m_segments.m_buffer[segmentId].m_startNode; ushort endNodeId = Singleton.instance.m_segments.m_buffer[segmentId].m_endNode; diff --git a/TLM/TLM/Traffic/VehicleState.cs b/TLM/TLM/Traffic/VehicleState.cs index 56c39e00..289c2f15 100644 --- a/TLM/TLM/Traffic/VehicleState.cs +++ b/TLM/TLM/Traffic/VehicleState.cs @@ -61,7 +61,6 @@ public bool Valid { #endif public ExtVehicleType VehicleType; - #if PATHFORECAST private LinkedList VehiclePositions; // the last element holds the current position private LinkedListNode CurrentPosition; @@ -84,30 +83,32 @@ public ushort NextVehicleIdOnSegment { public VehicleState(ushort vehicleId) { this.VehicleId = vehicleId; VehicleType = ExtVehicleType.None; - Reset(); + Reset(false); } - private void Reset() { - Unlink(); + private void Reset(bool unlink=true) { + if (unlink) + Unlink(); Valid = false; TotalLength = 0f; //VehicleType = ExtVehicleType.None; WaitTime = 0; JunctionTransitState = VehicleJunctionTransitState.None; - Emergency = false; LastStateUpdate = 0; } internal void Unlink() { + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); + if (PreviousVehicleIdOnSegment != 0) { - VehicleStateManager._GetVehicleState(PreviousVehicleIdOnSegment).NextVehicleIdOnSegment = NextVehicleIdOnSegment; + vehStateManager._GetVehicleState(PreviousVehicleIdOnSegment).NextVehicleIdOnSegment = NextVehicleIdOnSegment; } else if (CurrentSegmentEnd != null && CurrentSegmentEnd.FirstRegisteredVehicleId == VehicleId) { CurrentSegmentEnd.FirstRegisteredVehicleId = NextVehicleIdOnSegment; } if (NextVehicleIdOnSegment != 0) { - VehicleStateManager._GetVehicleState(NextVehicleIdOnSegment).PreviousVehicleIdOnSegment = PreviousVehicleIdOnSegment; + vehStateManager._GetVehicleState(NextVehicleIdOnSegment).PreviousVehicleIdOnSegment = PreviousVehicleIdOnSegment; } NextVehicleIdOnSegment = 0; @@ -118,7 +119,7 @@ internal void Unlink() { private void Link(SegmentEnd end) { ushort oldFirstRegVehicleId = end.FirstRegisteredVehicleId; if (oldFirstRegVehicleId != 0) { - VehicleStateManager._GetVehicleState(oldFirstRegVehicleId).PreviousVehicleIdOnSegment = VehicleId; + VehicleStateManager.Instance()._GetVehicleState(oldFirstRegVehicleId).PreviousVehicleIdOnSegment = VehicleId; NextVehicleIdOnSegment = oldFirstRegVehicleId; } end.FirstRegisteredVehicleId = VehicleId; @@ -329,13 +330,6 @@ private bool ProcessPathUnit(ref PathUnit unit, byte index, PathPositionProcesso return true; } - /*public VehiclePosition GetCurrentPosition() { - LinkedListNode firstNode = CurrentPosition; - if (firstNode == null) - return null; - return firstNode.Value; - }*/ - internal void UpdatePosition(ref Vehicle vehicleData, ref PathUnit.Position curPos, ref PathUnit.Position nextPos, bool skipCheck=false) { if (! skipCheck && ! CheckValidity(ref vehicleData)) { return; @@ -371,25 +365,25 @@ internal void UpdatePosition(ref Vehicle vehicleData) { } internal bool CheckValidity(ref Vehicle vehicleData, bool skipCached=false) { - if (!skipCached && !Valid) - return false; +#if DEBUG + bool debug = skipCached; + byte pfFlags = Singleton.instance.m_pathUnits.m_buffer[vehicleData.m_path].m_pathFindFlags; +#endif - if ((vehicleData.m_flags & Vehicle.Flags.Created) == 0) { - Valid = false; - return false; - } +#if DEBUG + if (debug) + Log._Debug($"VehicleState.CheckValidity({VehicleId}) called. created: {(vehicleData.m_flags & Vehicle.Flags.Created) != 0} ({vehicleData.m_flags}) handled: {(vehicleData.Info.m_vehicleType & HANDLED_VEHICLE_TYPES) != VehicleInfo.VehicleType.None} ({vehicleData.Info.m_vehicleType}) has path unit: {vehicleData.m_path != 0} path ready: {(pfFlags & PathUnit.FLAG_READY) != 0} ({pfFlags})"); +#endif - if ((vehicleData.Info.m_vehicleType & HANDLED_VEHICLE_TYPES) == VehicleInfo.VehicleType.None) { - // vehicle type is not handled by TM:PE - Valid = false; + if (!skipCached && !Valid) return false; - } - if (vehicleData.m_path <= 0) { + if ((vehicleData.m_flags & Vehicle.Flags.Created) == 0 || (vehicleData.Info.m_vehicleType & HANDLED_VEHICLE_TYPES) == VehicleInfo.VehicleType.None || vehicleData.m_path <= 0) { Valid = false; return false; } + if ((Singleton.instance.m_pathUnits.m_buffer[vehicleData.m_path].m_pathFindFlags & PathUnit.FLAG_READY) == 0) { Valid = false; return false; @@ -413,30 +407,64 @@ internal static ushort GetTransitNodeId(ref PathUnit.Position curPos, ref PathUn return transitNodeId; } - internal void OnPathFindReady(ref Vehicle vehicleData) { + internal void OnVehicleSpawned(ref Vehicle vehicleData) { +#if DEBUG + Log._Debug($"VehicleState.OnPathFindReady called for vehicle {VehicleId} ({VehicleType}"); +#endif + Reset(); if (!CheckValidity(ref vehicleData, true)) { return; } - // determine vehicle type - if (VehicleType == ExtVehicleType.None) { - VehicleStateManager.DetermineVehicleType(VehicleId, ref vehicleData); - if (VehicleType == ExtVehicleType.None) - return; - } + // enforce updating trailers (they are not always present at path-finding time) + ApplyVehicleTypeToTrailers(); ReduceSpeedByValueToYield = UnityEngine.Random.Range(16f, 28f); - Emergency = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0; try { TotalLength = Singleton.instance.m_vehicles.m_buffer[VehicleId].CalculateTotalLength(VehicleId); } catch (Exception) { + TotalLength = 0; +#if DEBUG Log._Debug($"Error occurred while calculating total length of vehicle {VehicleId} ({VehicleType})."); +#endif return; } Valid = true; } + + private void ApplyVehicleTypeToTrailers() { + VehicleManager vehManager = Singleton.instance; + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); + +#if DEBUG + Log._Debug($"Applying VehicleType to trailes of vehicle {VehicleId} to {VehicleType}."); +#endif + + // apply vehicle type to all leading/trailing vehicles + ushort otherVehicleId = vehManager.m_vehicles.m_buffer[VehicleId].m_leadingVehicle; + while (otherVehicleId != 0) { +#if DEBUG + Log._Debug($" Setting VehicleType of leader {otherVehicleId} to {VehicleType}."); +#endif + VehicleState otherState = vehStateManager._GetVehicleState(otherVehicleId); + otherState.Valid = true; + otherState.VehicleType = VehicleType; + otherVehicleId = vehManager.m_vehicles.m_buffer[otherVehicleId].m_leadingVehicle; + } + + otherVehicleId = vehManager.m_vehicles.m_buffer[VehicleId].m_trailingVehicle; + while (otherVehicleId != 0) { +#if DEBUG + Log._Debug($" Setting VehicleType of trailer {otherVehicleId} to {VehicleType}."); +#endif + VehicleState otherState = vehStateManager._GetVehicleState(otherVehicleId); + otherState.Valid = true; + otherState.VehicleType = VehicleType; + otherVehicleId = vehManager.m_vehicles.m_buffer[otherVehicleId].m_trailingVehicle; + } + } } } diff --git a/TLM/TLM/Traffic/VehicleStateManager.cs b/TLM/TLM/Traffic/VehicleStateManager.cs index 159a9fe6..17ab4a5a 100644 --- a/TLM/TLM/Traffic/VehicleStateManager.cs +++ b/TLM/TLM/Traffic/VehicleStateManager.cs @@ -3,24 +3,43 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using TrafficManager.Custom.AI; +using TrafficManager.State; using UnityEngine; namespace TrafficManager.Traffic { public class VehicleStateManager { + private static VehicleStateManager instance = null; + + public static VehicleStateManager Instance() { + if (instance == null) + instance = new VehicleStateManager(); + return instance; + } + + static VehicleStateManager() { + Instance(); + } + /// /// Known vehicles and their current known positions. Index: vehicle id /// - private static VehicleState[] VehicleStates = null; + private VehicleState[] VehicleStates = null; - static VehicleStateManager() { + private VehicleStateManager() { VehicleStates = new VehicleState[VehicleManager.MAX_VEHICLE_COUNT]; for (ushort i = 0; i < VehicleManager.MAX_VEHICLE_COUNT; ++i) { VehicleStates[i] = new VehicleState(i); } } - public static VehicleState GetVehicleState(ushort vehicleId) { + /// + /// Determines the state of the given vehicle. + /// + /// + /// the vehicle state if the state is valid, null otherwise + public VehicleState GetVehicleState(ushort vehicleId) { #if TRACE Singleton.instance.Start("VehicleStateManager.GetVehicleState"); #endif @@ -37,7 +56,13 @@ public static VehicleState GetVehicleState(ushort vehicleId) { return null; } - internal static VehicleState _GetVehicleState(ushort vehicleId) { + /// + /// Determines the state of the given vehicle. + /// The returned vehicle state is not necessarily valid. + /// + /// + /// the vehicle state + internal VehicleState _GetVehicleState(ushort vehicleId) { #if TRACE Singleton.instance.Start("VehicleStateManager._GetVehicleState"); #endif @@ -48,19 +73,12 @@ internal static VehicleState _GetVehicleState(ushort vehicleId) { return ret; } - /*public static VehiclePosition GetVehiclePosition(ushort vehicleId) { - VehicleState state = GetVehicleState(vehicleId); - if (state == null) - return null; - return state.GetCurrentPosition(); - }*/ - - internal static void OnLevelUnloading() { + internal void OnLevelUnloading() { for (int i = 0; i < VehicleStates.Length; ++i) VehicleStates[i].Valid = false; } - internal static void UpdateVehiclePos(ushort vehicleId, ref Vehicle vehicleData) { + internal void UpdateVehiclePos(ushort vehicleId, ref Vehicle vehicleData) { #if TRACE Singleton.instance.Start("VehicleStateManager.UpdateVehiclePos(1)"); #endif @@ -70,7 +88,7 @@ internal static void UpdateVehiclePos(ushort vehicleId, ref Vehicle vehicleData) #endif } - internal static void UpdateVehiclePos(ushort vehicleId, ref Vehicle vehicleData, ref PathUnit.Position curPos, ref PathUnit.Position nextPos) { + internal void UpdateVehiclePos(ushort vehicleId, ref Vehicle vehicleData, ref PathUnit.Position curPos, ref PathUnit.Position nextPos) { #if TRACE Singleton.instance.Start("VehicleStateManager.UpdateVehiclePos(2)"); #endif @@ -80,7 +98,7 @@ internal static void UpdateVehiclePos(ushort vehicleId, ref Vehicle vehicleData, #endif } - internal static void LogTraffic(ushort vehicleId, ref Vehicle vehicleData, bool logSpeed) { + internal void LogTraffic(ushort vehicleId, ref Vehicle vehicleData, bool logSpeed) { #if TRACE Singleton.instance.Start("VehicleStateManager.LogTraffic"); #endif @@ -88,7 +106,9 @@ internal static void LogTraffic(ushort vehicleId, ref Vehicle vehicleData, bool if (state == null) return; - ushort length = (ushort)Mathf.RoundToInt(vehicleData.CalculateTotalLength(vehicleId)); + ushort length = (ushort)state.TotalLength; + if (length == 0) + return; ushort? speed = logSpeed ? (ushort?)Mathf.RoundToInt(vehicleData.GetLastFrameData().m_velocity.magnitude) : null; state.ProcessCurrentPathPosition(ref vehicleData, delegate (ref PathUnit.Position pos) { @@ -99,43 +119,53 @@ internal static void LogTraffic(ushort vehicleId, ref Vehicle vehicleData, bool #endif } - internal static void OnReleaseVehicle(ushort vehicleId, ref Vehicle vehicleData) { + internal void OnReleaseVehicle(ushort vehicleId) { #if TRACE Singleton.instance.Start("VehicleStateManager.OnReleaseVehicle"); +#endif +#if DEBUG + Log._Debug($"VehicleStateManager.OnReleaseVehicle({vehicleId}) called."); #endif VehicleState state = _GetVehicleState(vehicleId); - state.Valid = false; state.VehicleType = ExtVehicleType.None; + state.Valid = false; //VehicleStates[vehicleId].Reset(); #if TRACE Singleton.instance.Stop("VehicleStateManager.OnReleaseVehicle"); #endif } - internal static void OnPathFindReady(ushort vehicleId, ref Vehicle vehicleData) { + internal void OnVehicleSpawned(ushort vehicleId, ref Vehicle vehicleData) { //Log._Debug($"VehicleStateManager: OnPathFindReady({vehicleId})"); #if TRACE Singleton.instance.Start("VehicleStateManager.OnPathFindReady"); #endif - VehicleStates[vehicleId].OnPathFindReady(ref vehicleData); + VehicleStates[vehicleId].OnVehicleSpawned(ref vehicleData); #if TRACE Singleton.instance.Stop("VehicleStateManager.OnPathFindReady"); #endif } - internal static void InitAllVehicles() { - //Log._Debug("VehicleStateManager: InitAllVehicles()"); - VehicleManager vehicleManager = Singleton.instance; - for (ushort i = 0; i < vehicleManager.m_vehicles.m_size; ++i) { - try { - OnPathFindReady(i, ref Singleton.instance.m_vehicles.m_buffer[i]); - } catch (Exception e) { - Log.Error("VehicleStateManager: InitAllVehicles Error: " + e.ToString()); + internal void InitAllVehicles() { + Log._Debug("VehicleStateManager: InitAllVehicles()"); + if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { + VehicleManager vehicleManager = Singleton.instance; + + for (ushort vehicleId = 0; vehicleId < VehicleManager.MAX_VEHICLE_COUNT; ++vehicleId) { + if ((Singleton.instance.m_vehicles.m_buffer[vehicleId].m_flags & Vehicle.Flags.Created) == 0) + continue; + + try { + DetermineVehicleType(vehicleId, ref Singleton.instance.m_vehicles.m_buffer[vehicleId]); + OnVehicleSpawned(vehicleId, ref Singleton.instance.m_vehicles.m_buffer[vehicleId]); + } catch (Exception e) { + Log.Error("VehicleStateManager: InitAllVehicles Error: " + e.ToString()); + } } } } - internal static ExtVehicleType? DetermineVehicleType(ushort vehicleId, ref Vehicle vehicleData) { + internal ExtVehicleType? DetermineVehicleType(ushort vehicleId, ref Vehicle vehicleData) { #if TRACE Singleton.instance.Start("VehicleStateManager.DetermineVehicleType"); #endif @@ -162,7 +192,7 @@ internal static void InitAllVehicles() { return ret; } - private static ExtVehicleType? DetermineVehicleTypeFromAIType(VehicleAI ai, bool emergencyOnDuty) { + private ExtVehicleType? DetermineVehicleTypeFromAIType(VehicleAI ai, bool emergencyOnDuty) { if (emergencyOnDuty) return ExtVehicleType.Emergency; diff --git a/TLM/TLM/TrafficLight/CustomSegmentLight.cs b/TLM/TLM/TrafficLight/CustomSegmentLight.cs index 339fd4d3..c556b699 100644 --- a/TLM/TLM/TrafficLight/CustomSegmentLight.cs +++ b/TLM/TLM/TrafficLight/CustomSegmentLight.cs @@ -100,7 +100,9 @@ public void ChangeMode() { var hasForwardSegment = geometry.HasOutgoingStraightSegment(startNode); var hasRightSegment = geometry.HasOutgoingRightSegment(startNode); +#if DEBUG Log._Debug($"ChangeMode. segment {SegmentId} @ node {NodeId}, hasOutgoingLeft={hasLeftSegment}, hasOutgoingStraight={hasForwardSegment}, hasOutgoingRight={hasRightSegment}"); +#endif if (CurrentMode == Mode.Simple) { if (!hasLeftSegment) { diff --git a/TLM/TLM/TrafficLight/CustomSegmentLights.cs b/TLM/TLM/TrafficLight/CustomSegmentLights.cs index 1dbf623f..c8492832 100644 --- a/TLM/TLM/TrafficLight/CustomSegmentLights.cs +++ b/TLM/TLM/TrafficLight/CustomSegmentLights.cs @@ -157,8 +157,8 @@ internal void housekeeping(bool mayDelete, RoadBaseAI.TrafficLightState mainStat // we intentionally never delete vehicle types (because we may want to retain traffic light states if a segment is upgraded or replaced) HashSet setupLights = new HashSet(); - Dictionary allAllowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypesAsDict(segmentId, nodeId); - ExtVehicleType allAllowedMask = VehicleRestrictionsManager.GetAllowedVehicleTypes(segmentId, nodeId); + Dictionary allAllowedTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypesAsDict(segmentId, nodeId); + ExtVehicleType allAllowedMask = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(segmentId, nodeId); SeparateVehicleTypes = ExtVehicleType.None; #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}, allAllowedTypes={string.Join(", ", allAllowedTypes.Select(x => x.ToString()).ToArray())}"); diff --git a/TLM/TLM/TrafficLight/TimedTrafficLightsStep.cs b/TLM/TLM/TrafficLight/TimedTrafficLightsStep.cs index 3ee2ec6f..9515d721 100644 --- a/TLM/TLM/TrafficLight/TimedTrafficLightsStep.cs +++ b/TLM/TLM/TrafficLight/TimedTrafficLightsStep.cs @@ -580,7 +580,7 @@ public bool calcWaitFlow(out float wait, out float flow) { } //bool startPhase = getCurrentFrame() <= startFrame + minTime + 2; // during start phase all vehicles on "green" segments are counted as flowing - ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(fromSegmentId, timedNode.NodeId); + ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(fromSegmentId, timedNode.NodeId); foreach (KeyValuePair e2 in segLights.VehicleTypeByLaneIndex) { byte laneIndex = e2.Key; diff --git a/TLM/TLM/TrafficManagerMod.cs b/TLM/TLM/TrafficManagerMod.cs index 451da762..99402b4d 100644 --- a/TLM/TLM/TrafficManagerMod.cs +++ b/TLM/TLM/TrafficManagerMod.cs @@ -5,7 +5,7 @@ namespace TrafficManager { public class TrafficManagerMod : IUserMod { - public static readonly string Version = "1.7.1"; + public static readonly string Version = "1.7.3"; public static readonly uint GameVersion = 155313168u; public static readonly uint GameVersionA = 1u; diff --git a/TLM/TLM/UI/SubTool.cs b/TLM/TLM/UI/SubTool.cs index 82ecb044..82a93014 100644 --- a/TLM/TLM/UI/SubTool.cs +++ b/TLM/TLM/UI/SubTool.cs @@ -9,13 +9,13 @@ public abstract class SubTool { public TrafficManagerTool MainTool { get; set; } protected ushort HoveredNodeId { - get { return MainTool.HoveredNodeId; } - set { MainTool.HoveredNodeId = value; } + get { return TrafficManagerTool.HoveredNodeId; } + set { TrafficManagerTool.HoveredNodeId = value; } } protected ushort HoveredSegmentId { - get { return MainTool.HoveredSegmentId; } - set { MainTool.HoveredSegmentId = value; } + get { return TrafficManagerTool.HoveredSegmentId; } + set { TrafficManagerTool.HoveredSegmentId = value; } } protected ushort SelectedNodeId { diff --git a/TLM/TLM/UI/SubTools/LaneConnectorTool.cs b/TLM/TLM/UI/SubTools/LaneConnectorTool.cs index 2550e519..6f25f42c 100644 --- a/TLM/TLM/UI/SubTools/LaneConnectorTool.cs +++ b/TLM/TLM/UI/SubTools/LaneConnectorTool.cs @@ -24,7 +24,7 @@ enum MarkerSelectionMode { private Dictionary nodeGeometryUnsubscribers; private NodeLaneMarker selectedMarker = null; private NodeLaneMarker hoveredMarker = null; - //private Dictionary> allNodeMarkers; + private Dictionary> currentNodeMarkers; //private bool initDone = false; class NodeLaneMarker { @@ -42,8 +42,8 @@ class NodeLaneMarker { public LaneConnectorTool(TrafficManagerTool mainTool) : base(mainTool) { //Log._Debug($"TppLaneConnectorTool: Constructor called"); - //allNodeMarkers = new Dictionary>(); nodeGeometryUnsubscribers = new Dictionary(); + currentNodeMarkers = new Dictionary>(); } public override void OnToolGUI(Event e) { @@ -62,20 +62,16 @@ private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo) { Bounds bounds = new Bounds(Vector3.zero, Vector3.one); Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition); - for (ushort nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId) { - /*foreach (KeyValuePair> e in allNodeMarkers) { + //for (ushort nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId) { + foreach (KeyValuePair> e in currentNodeMarkers) { ushort nodeId = e.Key; - List nodeMarkers = e.Value;*/ + List nodeMarkers = e.Value; Vector3 nodePos = NetManager.instance.m_nodes.m_buffer[nodeId].m_position; var diff = nodePos - camPos; if (diff.magnitude > TrafficManagerTool.PriorityCloseLod) continue; // do not draw if too distant - List nodeMarkers = GetNodeMarkers(nodeId); - if (nodeMarkers == null) - continue; - foreach (NodeLaneMarker sourceLaneMarker in nodeMarkers) { foreach (NodeLaneMarker targetLaneMarker in sourceLaneMarker.connectedMarkers) { // render lane connection @@ -144,10 +140,11 @@ public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) { selectedMarker = null; foreach (NodeLaneMarker sourceLaneMarker in nodeMarkers) { foreach (NodeLaneMarker targetLaneMarker in sourceLaneMarker.connectedMarkers) { - Singleton.instance.RemoveLaneConnection(sourceLaneMarker.laneId, targetLaneMarker.laneId, sourceLaneMarker.startNode); + LaneConnectionManager.Instance().RemoveLaneConnection(sourceLaneMarker.laneId, targetLaneMarker.laneId, sourceLaneMarker.startNode); } } } + RefreshCurrentNodeMarkers(); } } @@ -183,10 +180,14 @@ public override void OnPrimaryClickOverlay() { Log._Debug($"Node {HoveredNodeId} has been selected. Creating markers."); #endif - SelectedNodeId = HoveredNodeId; - selectedMarker = null; - // selected node has changed. create markers + List markers = GetNodeMarkers(HoveredNodeId); + if (markers != null) { + SelectedNodeId = HoveredNodeId; + selectedMarker = null; + + currentNodeMarkers[SelectedNodeId] = markers; + } //this.allNodeMarkers[SelectedNodeId] = GetNodeMarkers(SelectedNodeId); } } else { @@ -216,13 +217,13 @@ public override void OnPrimaryClickOverlay() { } else if (GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget) { // select target marker //bool success = false; - if (Singleton.instance.RemoveLaneConnection(selectedMarker.laneId, hoveredMarker.laneId, selectedMarker.startNode)) { // try to remove connection + if (LaneConnectionManager.Instance().RemoveLaneConnection(selectedMarker.laneId, hoveredMarker.laneId, selectedMarker.startNode)) { // try to remove connection selectedMarker.connectedMarkers.Remove(hoveredMarker); #if DEBUGCONN Log._Debug($"TppLaneConnectorTool: removed lane connection: {selectedMarker.laneId}, {hoveredMarker.laneId}"); #endif //success = true; - } else if (Singleton.instance.AddLaneConnection(selectedMarker.laneId, hoveredMarker.laneId, selectedMarker.startNode)) { // try to add connection + } else if (LaneConnectionManager.Instance().AddLaneConnection(selectedMarker.laneId, hoveredMarker.laneId, selectedMarker.startNode)) { // try to add connection selectedMarker.connectedMarkers.Add(hoveredMarker); #if DEBUGCONN Log._Debug($"TppLaneConnectorTool: added lane connection: {selectedMarker.laneId}, {hoveredMarker.laneId}"); @@ -272,6 +273,21 @@ public override void OnActivate() { SelectedNodeId = 0; selectedMarker = null; hoveredMarker = null; + RefreshCurrentNodeMarkers(); + } + + private void RefreshCurrentNodeMarkers() { + currentNodeMarkers.Clear(); + + for (ushort nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId) { + if ((Singleton.instance.m_nodes.m_buffer[nodeId].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) + continue; + + List nodeMarkers = GetNodeMarkers(nodeId); + if (nodeMarkers == null) + continue; + currentNodeMarkers[nodeId] = nodeMarkers; + } } private MarkerSelectionMode GetMarkerSelectionMode() { @@ -293,6 +309,8 @@ public override void Initialize() { return; } + RefreshCurrentNodeMarkers(); + /*NetManager netManager = Singleton.instance; allNodeMarkers.Clear(); @@ -325,7 +343,7 @@ private List GetNodeMarkers(ushort nodeId) { return null; List nodeMarkers = new List(); - LaneConnectionManager connManager = Singleton.instance; + LaneConnectionManager connManager = LaneConnectionManager.Instance(); int offsetMultiplier = NetManager.instance.m_nodes.m_buffer[nodeId].CountSegments() <= 2 ? 3 : 1; for (int i = 0; i < 8; i++) { @@ -368,7 +386,7 @@ private List GetNodeMarkers(ushort nodeId) { if (!laneMarker1.isSource) continue; - uint[] connections = Singleton.instance.GetLaneConnections(laneMarker1.laneId, laneMarker1.startNode); + uint[] connections = LaneConnectionManager.Instance().GetLaneConnections(laneMarker1.laneId, laneMarker1.startNode); if (connections == null || connections.Length == 0) continue; diff --git a/TLM/TLM/UI/SubTools/PrioritySignsTool.cs b/TLM/TLM/UI/SubTools/PrioritySignsTool.cs index 6f8c88f4..9e70c517 100644 --- a/TLM/TLM/UI/SubTools/PrioritySignsTool.cs +++ b/TLM/TLM/UI/SubTools/PrioritySignsTool.cs @@ -12,8 +12,10 @@ namespace TrafficManager.UI.SubTools { public class PrioritySignsTool : SubTool { + private HashSet currentPrioritySegmentIds; + public PrioritySignsTool(TrafficManagerTool mainTool) : base(mainTool) { - + currentPrioritySegmentIds = new HashSet(); } public override void OnPrimaryClickOverlay() { @@ -40,6 +42,28 @@ public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) { MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId); } + public override void Initialize() { + RefreshCurrentPrioritySegmentIds(); + } + + public override void OnActivate() { + RefreshCurrentPrioritySegmentIds(); + } + + private void RefreshCurrentPrioritySegmentIds() { + currentPrioritySegmentIds.Clear(); + for (ushort segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { + if ((Singleton.instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) + continue; + + var trafficSegment = TrafficPriority.TrafficSegments[segmentId]; + if (trafficSegment == null) + continue; + + currentPrioritySegmentIds.Add(segmentId); + } + } + public override void ShowGUIOverlay() { ShowGUI(true); } @@ -54,7 +78,7 @@ public void ShowGUI(bool viewOnly) { //Log.Message("_guiPrioritySigns called. num of prio segments: " + TrafficPriority.PrioritySegments.Count); HashSet nodeIdsWithSigns = new HashSet(); - for (ushort segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { + foreach (ushort segmentId in currentPrioritySegmentIds) { var trafficSegment = TrafficPriority.TrafficSegments[segmentId]; if (trafficSegment == null) continue; @@ -238,12 +262,14 @@ public void ShowGUI(bool viewOnly) { if (delete) { TrafficPriority.RemovePrioritySegments(hoveredExistingNodeId); + RefreshCurrentPrioritySegmentIds(); } else if (ok) { if (!TrafficPriority.IsPriorityNode(HoveredNodeId)) { //Log._Debug("_guiPrioritySigns: adding prio segments @ nodeId=" + HoveredNodeId); TrafficLightSimulation.RemoveNodeFromSimulation(HoveredNodeId, false, true); Flags.setNodeTrafficLight(HoveredNodeId, false); // TODO refactor! TrafficPriority.AddPriorityNode(HoveredNodeId); + RefreshCurrentPrioritySegmentIds(); } } else if (nodeSim != null && nodeSim.IsTimedLight()) { MainTool.ShowTooltip(Translation.GetString("NODE_IS_TIMED_LIGHT"), Singleton.instance.m_nodes.m_buffer[HoveredNodeId].m_position); diff --git a/TLM/TLM/UI/SubTools/SpeedLimitsTool.cs b/TLM/TLM/UI/SubTools/SpeedLimitsTool.cs index 0ea35cd6..8ea26deb 100644 --- a/TLM/TLM/UI/SubTools/SpeedLimitsTool.cs +++ b/TLM/TLM/UI/SubTools/SpeedLimitsTool.cs @@ -15,13 +15,15 @@ public class SpeedLimitsTool : SubTool { private bool _cursorInSecondaryPanel; private int curSpeedLimitIndex = 0; private bool overlayHandleHovered; - private static Dictionary> segmentCenterByDir = new Dictionary>(); - private static float speedLimitSignSize = 80f; + private Dictionary> segmentCenterByDir = new Dictionary>(); + private readonly float speedLimitSignSize = 80f; private Texture2D SecondPanelTexture; private Rect windowRect = TrafficManagerTool.MoveGUI(new Rect(0, 0, 7 * 105, 210)); + private HashSet currentlyVisibleSegmentIds; public SpeedLimitsTool(TrafficManagerTool mainTool) : base(mainTool) { SecondPanelTexture = TrafficManagerTool.MakeTex(1, 1, new Color(0.5f, 0.5f, 0.5f, 1f)); + currentlyVisibleSegmentIds = new HashSet(); } public override bool IsCursorInPanel() { @@ -63,33 +65,62 @@ public override void ShowGUIOverlay() { public override void Cleanup() { segmentCenterByDir.Clear(); + currentlyVisibleSegmentIds.Clear(); + lastCamPos = null; + lastCamRot = null; } + private Quaternion? lastCamRot = null; + private Vector3? lastCamPos = null; + private void ShowSigns(bool viewOnly) { if (viewOnly && !Options.speedLimitsOverlay) return; - Array16 segments = Singleton.instance.m_segments; + Quaternion camRot = Camera.main.transform.rotation; + Vector3 camPos = Camera.main.transform.position; + + NetManager netManager = Singleton.instance; + + if (lastCamPos == null || lastCamRot == null || !lastCamRot.Equals(camRot) || !lastCamPos.Equals(camPos)) { + // cache visible segments + currentlyVisibleSegmentIds.Clear(); + + for (ushort segmentId = 1; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { + if ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) + continue; + if ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None) + continue; + + if ((netManager.m_segments.m_buffer[segmentId].m_bounds.center - camPos).magnitude > TrafficManagerTool.PriorityCloseLod) + continue; // do not draw if too distant + + Vector3 screenPos = Camera.main.WorldToScreenPoint(netManager.m_segments.m_buffer[segmentId].m_bounds.center); + if (screenPos.z < 0) + continue; + + ItemClass connectionClass = Singleton.instance.m_segments.m_buffer[segmentId].Info.GetConnectionClass(); + if (!(connectionClass.m_service == ItemClass.Service.Road || + (connectionClass.m_service == ItemClass.Service.PublicTransport && connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain))) + continue; + + currentlyVisibleSegmentIds.Add(segmentId); + } + + lastCamPos = camPos; + lastCamRot = camRot; + } + bool handleHovered = false; - for (int i = 1; i < segments.m_size; ++i) { - if (segments.m_buffer[i].m_flags == NetSegment.Flags.None) // segment is unused - continue; -#if !DEBUG - if ((segments.m_buffer[i].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None) - continue; -#endif - var segmentInfo = segments.m_buffer[i].Info; - - Vector3 centerPos = segments.m_buffer[i].m_bounds.center; - var screenPos = Camera.main.WorldToScreenPoint(centerPos); + foreach (ushort segmentId in currentlyVisibleSegmentIds) { + Vector3 screenPos = Camera.main.WorldToScreenPoint(netManager.m_segments.m_buffer[segmentId].m_bounds.center); screenPos.y = Screen.height - screenPos.y; - if (screenPos.z < 0) - continue; + NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info; // draw speed limits - if (TrafficManagerTool.GetToolMode() != ToolMode.VehicleRestrictions || i != SelectedSegmentId) { // no speed limit overlay on selected segment when in vehicle restrictions mode - if (drawSpeedLimitHandles((ushort)i, viewOnly)) + if (TrafficManagerTool.GetToolMode() != ToolMode.VehicleRestrictions || segmentId != SelectedSegmentId) { // no speed limit overlay on selected segment when in vehicle restrictions mode + if (drawSpeedLimitHandles((ushort)segmentId, viewOnly, ref camPos)) handleHovered = true; } } @@ -100,11 +131,11 @@ private void _guiSpeedLimitsWindow(int num) { GUILayout.BeginHorizontal(); Color oldColor = GUI.color; - for (int i = 0; i < SpeedLimitManager.AvailableSpeedLimits.Count; ++i) { + for (int i = 0; i < SpeedLimitManager.Instance().AvailableSpeedLimits.Count; ++i) { if (curSpeedLimitIndex != i) GUI.color = Color.gray; float signSize = TrafficManagerTool.AdaptWidth(100); - if (GUILayout.Button(TrafficLightToolTextureResources.SpeedLimitTextures[SpeedLimitManager.AvailableSpeedLimits[i]], GUILayout.Width(signSize), GUILayout.Height(signSize))) { + if (GUILayout.Button(TrafficLightToolTextureResources.SpeedLimitTextures[SpeedLimitManager.Instance().AvailableSpeedLimits[i]], GUILayout.Width(signSize), GUILayout.Height(signSize))) { curSpeedLimitIndex = i; } GUI.color = oldColor; @@ -118,7 +149,7 @@ private void _guiSpeedLimitsWindow(int num) { GUILayout.EndHorizontal(); } - private bool drawSpeedLimitHandles(ushort segmentId, bool viewOnly) { + private bool drawSpeedLimitHandles(ushort segmentId, bool viewOnly, ref Vector3 camPos) { if (!LoadingExtension.IsPathManagerCompatible) { return false; } @@ -134,26 +165,13 @@ private bool drawSpeedLimitHandles(ushort segmentId, bool viewOnly) { bool hovered = false; foreach (KeyValuePair e in segmentCenterByDir[segmentId]) { - Vector3 signPos = e.Value; - var screenPos = Camera.main.WorldToScreenPoint(signPos); + var screenPos = Camera.main.WorldToScreenPoint(e.Value); screenPos.y = Screen.height - screenPos.y; - if (screenPos.z < 0) - return false; - var camPos = Singleton.instance.m_simulationView.m_position; - var diff = signPos - camPos; - - if (diff.magnitude > TrafficManagerTool.PriorityCloseLod) - return false; // do not draw if too distant - - ItemClass connectionClass = Singleton.instance.m_segments.m_buffer[segmentId].Info.GetConnectionClass(); - if (!(connectionClass.m_service == ItemClass.Service.Road || - (connectionClass.m_service == ItemClass.Service.PublicTransport && connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain))) - return false; - - var zoom = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom(); - var size = speedLimitSignSize * zoom; - var guiColor = GUI.color; - var boundingBox = new Rect(screenPos.x - size / 2, screenPos.y - size / 2, size, size); + + float zoom = 1.0f / (e.Value - camPos).magnitude * 100f * MainTool.GetBaseZoom(); + float size = speedLimitSignSize * zoom; + Color guiColor = GUI.color; + Rect boundingBox = new Rect(screenPos.x - size / 2, screenPos.y - size / 2, size, size); bool hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox); if (hoveredHandle) { @@ -167,19 +185,20 @@ private bool drawSpeedLimitHandles(ushort segmentId, bool viewOnly) { GUI.color = guiColor; try { - GUI.DrawTexture(boundingBox, TrafficLightToolTextureResources.SpeedLimitTextures[SpeedLimitManager.GetCustomSpeedLimit(segmentId, e.Key)]); + GUI.DrawTexture(boundingBox, TrafficLightToolTextureResources.SpeedLimitTextures[SpeedLimitManager.Instance().GetCustomSpeedLimit(segmentId, e.Key)]); } catch (Exception ex) { - Log.Error("segment " + segmentId + " limit: " + SpeedLimitManager.GetCustomSpeedLimit(segmentId, e.Key) + ", ex: " + ex.ToString()); + Log.Error("segment " + segmentId + " limit: " + SpeedLimitManager.Instance().GetCustomSpeedLimit(segmentId, e.Key) + ", ex: " + ex.ToString()); } if (hoveredHandle && Input.GetMouseButton(0)) { // change the speed limit to the selected one - ushort speedLimitToSet = SpeedLimitManager.AvailableSpeedLimits[curSpeedLimitIndex]; + ushort speedLimitToSet = SpeedLimitManager.Instance().AvailableSpeedLimits[curSpeedLimitIndex]; //Log._Debug($"Setting speed limit of segment {segmentId}, dir {e.Key.ToString()} to {speedLimitToSet}"); - SpeedLimitManager.SetSpeedLimit(segmentId, e.Key, speedLimitToSet); + SpeedLimitManager.Instance().SetSpeedLimit(segmentId, e.Key, speedLimitToSet); // TODO use SegmentTraverser if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { + // apply new speed limit to connected segments NetInfo selectedSegmentInfo = Singleton.instance.m_segments.m_buffer[segmentId].Info; List selectedSortedLanes = TrafficManagerTool.GetSortedVehicleLanes(segmentId, selectedSegmentInfo, null); @@ -230,7 +249,7 @@ private bool drawSpeedLimitHandles(ushort segmentId, bool viewOnly) { NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if (laneInfo.m_finalDirection == e.Key) { - SpeedLimitManager.SetSpeedLimit(otherSegmentId, laneInfo.m_finalDirection, speedLimitToSet); + SpeedLimitManager.Instance().SetSpeedLimit(otherSegmentId, laneInfo.m_finalDirection, speedLimitToSet); } // apply restrictions of selected segment & lane diff --git a/TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs b/TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs index fede86dd..dbaad7cc 100644 --- a/TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs +++ b/TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs @@ -29,23 +29,42 @@ public class TimedTrafficLightsTool : SubTool { private float _waitFlowBalance = 0.8f; private string _stepMinValueStr = "1"; private string _stepMaxValueStr = "1"; + private HashSet currentTimedNodeIds; public TimedTrafficLightsTool(TrafficManagerTool mainTool) : base(mainTool) { - + currentTimedNodeIds = new HashSet(); } public override bool IsCursorInPanel() { return _cursorInSecondaryPanel; } + public override void Initialize() { + RefreshCurrentTimedNodeIds(); + } + + private void RefreshCurrentTimedNodeIds() { + currentTimedNodeIds.Clear(); + for (ushort nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId) { + if ((Singleton.instance.m_nodes.m_buffer[nodeId].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) + continue; + + TrafficLightSimulation lightSim = TrafficLightSimulation.GetNodeSimulation(nodeId); + if (lightSim != null && lightSim.IsTimedLight()) { + currentTimedNodeIds.Add(nodeId); + } + } + } + public override void OnActivate() { + RefreshCurrentTimedNodeIds(); + nodeSelectionLocked = false; - foreach (var selectedNodeIndex in SelectedNodeIndexes) { - TrafficLightSimulation lightSim = TrafficLightSimulation.GetNodeSimulation(selectedNodeIndex); + foreach (ushort nodeId in currentTimedNodeIds) { + TrafficLightSimulation lightSim = TrafficLightSimulation.GetNodeSimulation(nodeId); if (lightSim != null) { lightSim.housekeeping(); } - //TrafficPriority.nodeHousekeeping(selectedNodeIndex); } } @@ -125,6 +144,7 @@ public override void OnPrimaryClickOverlay() { foreach (ushort nodeId in timedLight2.NodeGroup) AddSelectedNode(nodeId); TrafficManagerTool.SetToolMode(ToolMode.TimedLightsShowLights); + RefreshCurrentTimedNodeIds(); break; case ToolMode.TimedLightsRemoveNode: if (SelectedNodeIndexes.Count <= 0) { @@ -134,6 +154,7 @@ public override void OnPrimaryClickOverlay() { if (SelectedNodeIndexes.Contains(HoveredNodeId)) { TrafficLightSimulation.RemoveNodeFromSimulation(HoveredNodeId, false, false); + RefreshCurrentTimedNodeIds(); } RemoveSelectedNode(HoveredNodeId); TrafficManagerTool.SetToolMode(ToolMode.TimedLightsShowLights); @@ -1372,6 +1393,7 @@ private void _guiTimedTrafficLightsNodeWindow(int num) { TrafficLightSimulation.AddNodeToSimulation(selectedNodeIndex); var nodeSimulation = TrafficLightSimulation.GetNodeSimulation(selectedNodeIndex); nodeSimulation.SetupTimedTrafficLight(SelectedNodeIndexes); + RefreshCurrentTimedNodeIds(); /*for (var s = 0; s < 8; s++) { var segment = Singleton.instance.m_nodes.m_buffer[selectedNodeIndex].GetSegment(s); @@ -1413,6 +1435,7 @@ private void DisableTimed() { foreach (var selectedNodeIndex in SelectedNodeIndexes) { TrafficLightSimulation.RemoveNodeFromSimulation(selectedNodeIndex, true, false); } + RefreshCurrentTimedNodeIds(); } private void AddSelectedNode(ushort node) { @@ -1568,6 +1591,7 @@ public override void ShowGUIOverlay() { Log._Debug($"TimedTrafficLightsTool.ShowGUIOverlay: Node {nodeId} does not have an instance of TimedTrafficLights. Removing node from simulation"); #endif TrafficLightSimulation.RemoveNodeFromSimulation(nodeId, true, false); + RefreshCurrentTimedNodeIds(); break; } diff --git a/TLM/TLM/UI/SubTools/VehicleRestrictionsTool.cs b/TLM/TLM/UI/SubTools/VehicleRestrictionsTool.cs index 96b2c16c..9cfe5f92 100644 --- a/TLM/TLM/UI/SubTools/VehicleRestrictionsTool.cs +++ b/TLM/TLM/UI/SubTools/VehicleRestrictionsTool.cs @@ -13,18 +13,36 @@ namespace TrafficManager.UI.SubTools { public class VehicleRestrictionsTool : SubTool { private static ExtVehicleType[] roadVehicleTypes = new ExtVehicleType[] { ExtVehicleType.PassengerCar, ExtVehicleType.Bus, ExtVehicleType.Taxi, ExtVehicleType.CargoTruck, ExtVehicleType.Service, ExtVehicleType.Emergency }; private static ExtVehicleType[] railVehicleTypes = new ExtVehicleType[] { ExtVehicleType.PassengerTrain, ExtVehicleType.CargoTrain }; - private static float vehicleRestrictionsSignSize = 80f; + private readonly float vehicleRestrictionsSignSize = 80f; private bool _cursorInSecondaryPanel; private bool overlayHandleHovered; private Texture2D SecondPanelTexture; private Rect windowRect = TrafficManagerTool.MoveGUI(new Rect(0, 0, 620, 100)); + private HashSet currentRestrictedSegmentIds; public VehicleRestrictionsTool(TrafficManagerTool mainTool) : base(mainTool) { SecondPanelTexture = TrafficManagerTool.MakeTex(1, 1, new Color(0.5f, 0.5f, 0.5f, 1f)); + currentRestrictedSegmentIds = new HashSet(); } public override void OnActivate() { _cursorInSecondaryPanel = false; + RefreshCurrentRestrictedSegmentIds(); + } + + private void RefreshCurrentRestrictedSegmentIds() { + currentRestrictedSegmentIds.Clear(); + for (ushort segmentId = 1; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { + if ((Singleton.instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) + continue; + + if (VehicleRestrictionsManager.Instance().HasSegmentRestrictions(segmentId)) + currentRestrictedSegmentIds.Add(segmentId); + } + } + + public override void Initialize() { + RefreshCurrentRestrictedSegmentIds(); } public override bool IsCursorInPanel() { @@ -37,6 +55,7 @@ public override void OnPrimaryClickOverlay() { if (overlayHandleHovered) return; SelectedSegmentId = HoveredSegmentId; + currentRestrictedSegmentIds.Add(SelectedSegmentId); MainTool.CheckClicked(); // TODO do we need that? } @@ -86,15 +105,13 @@ private void ShowSigns(bool viewOnly) { if (viewOnly && !Options.vehicleRestrictionsOverlay) return; + bool stateUpdated = false; Array16 segments = Singleton.instance.m_segments; bool handleHovered = false; - for (int i = 1; i < segments.m_size; ++i) { - if (segments.m_buffer[i].m_flags == NetSegment.Flags.None) // segment is unused - continue; - - var segmentInfo = segments.m_buffer[i].Info; + foreach (ushort segmentId in currentRestrictedSegmentIds) { + var segmentInfo = segments.m_buffer[segmentId].Info; - Vector3 centerPos = segments.m_buffer[i].m_bounds.center; + Vector3 centerPos = segments.m_buffer[segmentId].m_bounds.center; var screenPos = Camera.main.WorldToScreenPoint(centerPos); screenPos.y = Screen.height - screenPos.y; @@ -102,10 +119,17 @@ private void ShowSigns(bool viewOnly) { continue; // draw vehicle restrictions - if (drawVehicleRestrictionHandles((ushort)i, viewOnly || i != SelectedSegmentId)) + bool update; + if (drawVehicleRestrictionHandles((ushort)segmentId, viewOnly || segmentId != SelectedSegmentId, out update)) handleHovered = true; + + if (update) + stateUpdated = true; } overlayHandleHovered = handleHovered; + + if (stateUpdated) + RefreshCurrentRestrictedSegmentIds(); } private void _guiVehicleRestrictionsWindow(int num) { @@ -119,15 +143,16 @@ private void _guiVehicleRestrictionsWindow(int num) { uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; - ExtVehicleType baseMask = VehicleRestrictionsManager.GetBaseMask(laneInfo); + ExtVehicleType baseMask = VehicleRestrictionsManager.Instance().GetBaseMask(laneInfo); if (baseMask == ExtVehicleType.None) continue; - ExtVehicleType allowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo); + ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo); allowedTypes = ~allowedTypes & baseMask; - VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, allowedTypes); + VehicleRestrictionsManager.Instance().SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, allowedTypes); } + RefreshCurrentRestrictedSegmentIds(); } GUILayout.BeginHorizontal(); @@ -141,13 +166,14 @@ private void _guiVehicleRestrictionsWindow(int num) { uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; - ExtVehicleType baseMask = VehicleRestrictionsManager.GetBaseMask(laneInfo); + ExtVehicleType baseMask = VehicleRestrictionsManager.Instance().GetBaseMask(laneInfo); if (baseMask == ExtVehicleType.None) continue; - VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, baseMask); + VehicleRestrictionsManager.Instance().SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, baseMask); } + RefreshCurrentRestrictedSegmentIds(); } if (GUILayout.Button(Translation.GetString("Ban_all_vehicles"))) { @@ -160,13 +186,15 @@ private void _guiVehicleRestrictionsWindow(int num) { uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; - VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, ExtVehicleType.None); + VehicleRestrictionsManager.Instance().SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, ExtVehicleType.None); } + RefreshCurrentRestrictedSegmentIds(); } GUILayout.EndHorizontal(); if (GUILayout.Button(Translation.GetString("Apply_vehicle_restrictions_to_all_road_segments_between_two_junctions"))) { ApplyRestrictionsToAllSegments(); + RefreshCurrentRestrictedSegmentIds(); } } @@ -227,7 +255,7 @@ private void ApplyRestrictionsToAllSegments(int? sortedLaneIndex=null) { NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; // apply restrictions of selected segment & lane - VehicleRestrictionsManager.SetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo, laneId, VehicleRestrictionsManager.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo)); + VehicleRestrictionsManager.Instance().SetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo, laneId, VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo)); } // add nodes to explore @@ -243,7 +271,8 @@ private void ApplyRestrictionsToAllSegments(int? sortedLaneIndex=null) { } } - private bool drawVehicleRestrictionHandles(ushort segmentId, bool viewOnly) { + private bool drawVehicleRestrictionHandles(ushort segmentId, bool viewOnly, out bool stateUpdated) { + stateUpdated = false; if (!LoadingExtension.IsPathManagerCompatible) { return false; } @@ -304,16 +333,16 @@ private bool drawVehicleRestrictionHandles(ushort segmentId, bool viewOnly) { } ExtVehicleType[] possibleVehicleTypes = null; - if (VehicleRestrictionsManager.IsRoadLane(laneInfo)) { + if (VehicleRestrictionsManager.Instance().IsRoadLane(laneInfo)) { possibleVehicleTypes = roadVehicleTypes; - } else if (VehicleRestrictionsManager.IsRailLane(laneInfo)) { + } else if (VehicleRestrictionsManager.Instance().IsRailLane(laneInfo)) { possibleVehicleTypes = railVehicleTypes; } else { ++x; continue; } - ExtVehicleType allowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); + ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); uint y = 0; #if DEBUGx @@ -335,7 +364,7 @@ private bool drawVehicleRestrictionHandles(ushort segmentId, bool viewOnly) { ++y; #endif foreach (ExtVehicleType vehicleType in possibleVehicleTypes) { - bool allowed = VehicleRestrictionsManager.IsAllowed(allowedTypes, vehicleType); + bool allowed = VehicleRestrictionsManager.Instance().IsAllowed(allowedTypes, vehicleType); if (allowed && viewOnly) continue; // do not draw allowed vehicles in view-only mode @@ -347,7 +376,8 @@ private bool drawVehicleRestrictionHandles(ushort segmentId, bool viewOnly) { if (hoveredHandle && MainTool.CheckClicked()) { // toggle vehicle restrictions //Log._Debug($"Setting vehicle restrictions of segment {segmentId}, lane idx {laneIndex}, {vehicleType.ToString()} to {!allowed}"); - VehicleRestrictionsManager.ToggleAllowedType(segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType, !allowed); + VehicleRestrictionsManager.Instance().ToggleAllowedType(segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType, !allowed); + stateUpdated = true; // TODO use SegmentTraverser if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { diff --git a/TLM/TLM/UI/TrafficLightToolTextureResources.cs b/TLM/TLM/UI/TrafficLightToolTextureResources.cs index d2c93183..543476f2 100644 --- a/TLM/TLM/UI/TrafficLightToolTextureResources.cs +++ b/TLM/TLM/UI/TrafficLightToolTextureResources.cs @@ -101,7 +101,7 @@ static TrafficLightToolTextureResources() ClockTestTexture2D = LoadDllResource("clock_test.png", 512, 512); SpeedLimitTextures = new Dictionary(); - foreach (ushort speedLimit in SpeedLimitManager.AvailableSpeedLimits) { + foreach (ushort speedLimit in SpeedLimitManager.Instance().AvailableSpeedLimits) { SpeedLimitTextures.Add(speedLimit, LoadDllResource(speedLimit.ToString() + ".png", 200, 200)); } diff --git a/TLM/TLM/UI/TrafficManagerTool.cs b/TLM/TLM/UI/TrafficManagerTool.cs index ab16dfe3..c028fa39 100644 --- a/TLM/TLM/UI/TrafficManagerTool.cs +++ b/TLM/TLM/UI/TrafficManagerTool.cs @@ -22,17 +22,13 @@ namespace TrafficManager.UI { public class TrafficManagerTool : DefaultTool { private static ToolMode _toolMode; - internal ushort HoveredNodeId; - internal ushort HoveredSegmentId; + internal static ushort HoveredNodeId; + internal static ushort HoveredSegmentId; - private bool mouseClickProcessed; + private static bool mouseClickProcessed; - public const float DebugCloseLod = 300f; - public const float PriorityCloseLod = 450f; - - /*private uint tooltipStartFrame = 0; - private String tooltipText = null; - private Vector3? tooltipWorldPos = null;*/ + public static readonly float DebugCloseLod = 300f; + public static readonly float PriorityCloseLod = 450f; private static SubTool[] subTools = new SubTool[12]; private static bool initDone = false; @@ -88,6 +84,13 @@ protected override void Awake() { subTools[(int)ToolMode.SpeedLimits] = new SpeedLimitsTool(this); subTools[(int)ToolMode.LaneChange] = new LaneArrowTool(this); subTools[(int)ToolMode.LaneConnector] = new LaneConnectorTool(this); + + for (int i = 0; i < subTools.Length; ++i) { + if (subTools[i] == null) + continue; + subTools[i].Initialize(); + } + Log.Info("TrafficManagerTool: Awake - Initialization completed."); initDone = true; } else { @@ -97,12 +100,6 @@ protected override void Awake() { subTools[i].MainTool = this; } } - - for (int i = 0; i < subTools.Length; ++i) { - if (subTools[i] == null) - continue; - subTools[i].Initialize(); - } } public static SubTool GetSubTool(ToolMode mode) { @@ -248,12 +245,12 @@ protected override void OnToolGUI(Event e) { _guiNodes(); } -#if DEBUG +//#if DEBUG if (Options.vehicleOverlay) { _guiVehicles(); //_guiCitizens(); } -#endif +//#endif for (int i = 0; i < subTools.Length; ++i) { if (subTools[i] == null) @@ -468,7 +465,7 @@ private void _guiLanes(ushort segmentId, ref NetSegment segment, ref NetInfo seg labelStr += "Lane idx " + i + ", id " + curLaneId; #if DEBUG - labelStr += ", flags: " + ((NetLane.Flags)Singleton.instance.m_lanes.m_buffer[curLaneId].m_flags).ToString() + ", limit: " + SpeedLimitManager.GetCustomSpeedLimit(curLaneId) + " km/h, dir: " + laneInfo.m_direction + ", final: " + laneInfo.m_finalDirection + ", pos: " + String.Format("{0:0.##}", laneInfo.m_position) + ", sim. idx: " + laneInfo.m_similarLaneIndex + " for " + laneInfo.m_vehicleType + "/" + laneInfo.m_laneType; + labelStr += ", flags: " + ((NetLane.Flags)Singleton.instance.m_lanes.m_buffer[curLaneId].m_flags).ToString() + ", limit: " + SpeedLimitManager.Instance().GetCustomSpeedLimit(curLaneId) + " km/h, dir: " + laneInfo.m_direction + ", final: " + laneInfo.m_finalDirection + ", pos: " + String.Format("{0:0.##}", laneInfo.m_position) + ", sim. idx: " + laneInfo.m_similarLaneIndex + " for " + laneInfo.m_vehicleType + "/" + laneInfo.m_laneType; #endif /*if (CustomRoadAI.InStartupPhase) labelStr += ", in start-up phase"; @@ -625,9 +622,10 @@ private void _guiNodes() { private void _guiVehicles() { GUIStyle _counterStyle = new GUIStyle(); Array16 vehicles = Singleton.instance.m_vehicles; - LaneConnectionManager connManager = Singleton.instance; + LaneConnectionManager connManager = LaneConnectionManager.Instance(); SimulationManager simManager = Singleton.instance; NetManager netManager = Singleton.instance; + VehicleStateManager vehStateManager = VehicleStateManager.Instance(); for (int i = 1; i < vehicles.m_size; ++i) { Vehicle vehicle = vehicles.m_buffer[i]; if (vehicle.m_flags == 0) // node is unused @@ -651,7 +649,7 @@ private void _guiVehicles() { _counterStyle.normal.textColor = new Color(1f, 1f, 1f); //_counterStyle.normal.background = MakeTex(1, 1, new Color(0f, 0f, 0f, 0.4f)); - VehicleState vState = VehicleStateManager.GetVehicleState((ushort)i); + VehicleState vState = vehStateManager._GetVehicleState((ushort)i); PathUnit.Position? curPos = vState?.GetCurrentPathPosition(ref vehicle); PathUnit.Position? nextPos = vState?.GetNextPathPosition(ref vehicle); bool? startNode = vState?.CurrentSegmentEnd?.StartNode; @@ -659,7 +657,7 @@ private void _guiVehicles() { ushort? transitNodeId = vState?.CurrentSegmentEnd?.NodeId; /*float distanceToTransitNode = Single.NaN; float timeToTransitNode = Single.NaN;*/ - float vehSpeed = vehicle.GetLastFrameVelocity().magnitude; + ushort vehSpeed = SpeedLimitManager.Instance().VehicleToCustomSpeed(vehicle.GetLastFrameVelocity().magnitude); Vector3? targetPos = null; if (transitNodeId != null) @@ -677,7 +675,7 @@ private void _guiVehicles() { else timeToTransitNode = Single.PositiveInfinity; }*/ - String labelStr = "V #" + i + " @ " + vState?.CurrentSegmentEnd?.SegmentId; + String labelStr = "V #" + i + " is a " + (vState.Valid ? "valid" : "invalid") + " " + vState.VehicleType + " @ ~" + vehSpeed + " km/h"; //String labelStr = "Veh. " + i + " @ " + String.Format("{0:0.##}", vehSpeed) + "/" + (vState != null ? vState.CurrentMaxSpeed.ToString() : "-") + " (" + (vState != null ? vState.VehicleType.ToString() : "-") + ", valid? " + (vState != null ? vState.Valid.ToString() : "-") + ")" + ", len: " + (vState != null ? vState.TotalLength.ToString() : "-") + ", state: " + (vState != null ? vState.JunctionTransitState.ToString() : "-"); #if PATHRECALC labelStr += ", recalc: " + (vState != null ? vState.LastPathRecalculation.ToString() : "-"); diff --git a/TLM/TLM/UI/UIBase.cs b/TLM/TLM/UI/UIBase.cs index 8dcfeaf0..2b14ea50 100644 --- a/TLM/TLM/UI/UIBase.cs +++ b/TLM/TLM/UI/UIBase.cs @@ -80,7 +80,8 @@ public void Close() { var trafficManager = uiView.FindUIComponent("UITrafficManager"); if (trafficManager != null) { Log._Debug("Hiding TM UI"); - trafficManager.Hide(); + Destroy(trafficManager); + //trafficManager.Hide(); } else { Log._Debug("Hiding TM UI: null!"); } diff --git a/TLM/TLM/UI/UITrafficManager.cs b/TLM/TLM/UI/UITrafficManager.cs index 773ee9f9..08066b63 100644 --- a/TLM/TLM/UI/UITrafficManager.cs +++ b/TLM/TLM/UI/UITrafficManager.cs @@ -56,10 +56,9 @@ public override void Start() { backgroundSprite = "GenericPanel"; color = new Color32(75, 75, 135, 255); width = Translation.getMenuWidth(); - height = LoadingExtension.IsPathManagerCompatible ? 430 : 230; -#if DEBUG - height += 40 * 9; -#endif + height = 30; + + //height = LoadingExtension.IsPathManagerCompatible ? 430 : 230; relativePosition = new Vector3(85f, 80f); title = AddUIComponent(); @@ -67,56 +66,89 @@ public override void Start() { title.relativePosition = new Vector3(50.0f, 5.0f); int y = 30; + _buttonSwitchTraffic = _createButton(Translation.GetString("Switch_traffic_lights"), y, clickSwitchTraffic); y += 40; - _buttonPrioritySigns = _createButton(Translation.GetString("Add_priority_signs"), y, clickAddPrioritySigns); - y += 40; + height += 40; + + if (Options.prioritySignsEnabled) { + _buttonPrioritySigns = _createButton(Translation.GetString("Add_priority_signs"), y, clickAddPrioritySigns); + y += 40; + height += 40; + } + _buttonManualControl = _createButton(Translation.GetString("Manual_traffic_lights"), y, clickManualControl); y += 40; - _buttonTimedMain = _createButton(Translation.GetString("Timed_traffic_lights"), y, clickTimedAdd); - y += 40; + height += 40; + + if (Options.timedLightsEnabled) { + _buttonTimedMain = _createButton(Translation.GetString("Timed_traffic_lights"), y, clickTimedAdd); + y += 40; + height += 40; + } if (LoadingExtension.IsPathManagerCompatible) { _buttonLaneChange = _createButton(Translation.GetString("Change_lane_arrows"), y, clickChangeLanes); y += 40; + height += 40; - _buttonLaneConnector = _createButton(Translation.GetString("Lane_connector"), y, clickLaneConnector); - y += 40; + if (Options.laneConnectorEnabled) { + _buttonLaneConnector = _createButton(Translation.GetString("Lane_connector"), y, clickLaneConnector); + y += 40; + height += 40; + } - _buttonSpeedLimits = _createButton(Translation.GetString("Speed_limits"), y, clickSpeedLimits); - y += 40; + if (Options.customSpeedLimitsEnabled) { + _buttonSpeedLimits = _createButton(Translation.GetString("Speed_limits"), y, clickSpeedLimits); + y += 40; + height += 40; + } - _buttonVehicleRestrictions = _createButton(Translation.GetString("Vehicle_restrictions"), y, clickVehicleRestrictions); - y += 40; + if (Options.vehicleRestrictionsEnabled) { + _buttonVehicleRestrictions = _createButton(Translation.GetString("Vehicle_restrictions"), y, clickVehicleRestrictions); + y += 40; + height += 40; + } } _buttonClearTraffic = _createButton(Translation.GetString("Clear_Traffic"), y, clickClearTraffic); y += 40; + height += 40; if (LoadingExtension.IsPathManagerCompatible) { _buttonToggleDespawn = _createButton(Options.enableDespawning ? Translation.GetString("Disable_despawning") : Translation.GetString("Enable_despawning"), y, ClickToggleDespawn); y += 40; + height += 40; } #if DEBUG _goToField = CreateTextField("", y); y += 40; + height += 40; _goToSegmentButton = _createButton("Goto segment", y, clickGoToSegment); y += 40; + height += 40; _goToNodeButton = _createButton("Goto node", y, clickGoToNode); y += 40; + height += 40; _goToVehicleButton = _createButton("Goto vehicle", y, clickGoToVehicle); y += 40; + height += 40; _goToBuildingButton = _createButton("Goto building", y, clickGoToBuilding); y += 40; + height += 40; _printDebugInfoButton = _createButton("Print debug info", y, clickPrintDebugInfo); y += 40; + height += 40; _noneToVehicleButton = _createButton("None -> Vehicle", y, clickNoneToVehicle); y += 40; + height += 40; _vehicleToNoneButton = _createButton("Vehicle -> None", y, clickVehicleToNone); y += 40; + height += 40; _togglePathFindStatsButton = _createButton("Toggle PathFind stats", y, clickTogglePathFindStats); y += 40; + height += 40; #endif } diff --git a/TLM/TLM/Util/ICustomManager.cs b/TLM/TLM/Util/ICustomManager.cs new file mode 100644 index 00000000..48f6b36e --- /dev/null +++ b/TLM/TLM/Util/ICustomManager.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TrafficManager.Util { + public interface ICustomManager { + void OnLevelLoaded(); + void OnLevelUnloaded(); + } +}