public void ResetCar() { Valid = false; ToNode = 0; FromSegment = 0; ToSegment = 0; //ToLaneId = 0; ToLaneIndex = 0; //FromLaneId = 0; FromLaneIndex = 0; VehicleType = ExtVehicleType.None; Stopped = false; WaitTime = 0; CarState = VehicleJunctionTransitState.None; OnEmergency = false; }
internal CustomSegmentLight GetCustomLight(ExtVehicleType vehicleType) { foreach (KeyValuePair<ExtVehicleType, CustomSegmentLight> e in CustomLights) { if ((e.Key & vehicleType) != ExtVehicleType.None) return e.Value; } /*if (vehicleType != ExtVehicleType.None) Log._Debug($"No traffic light for vehicle type {vehicleType} defined at segment {segmentId}, node {nodeId}.");*/ return mainSegmentLight; }
public static void setLaneAllowedVehicleTypes(ushort segmentId, uint laneIndex, uint laneId, ExtVehicleType vehicleTypes) { if (segmentId <= 0 || laneIndex < 0 || laneId <= 0) return; if ((Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) { return; } if (((NetLane.Flags)Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_flags & NetLane.Flags.Created) == NetLane.Flags.None) return; NetInfo segmentInfo = Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].Info; if (laneIndex >= segmentInfo.m_lanes.Length) { return; } try { Monitor.Enter(laneAllowedVehicleTypesLock); Log._Debug($"Flags.setLaneAllowedVehicleTypes: setting allowed vehicles of lane index {laneIndex} @ seg. {segmentId} to {vehicleTypes.ToString()}"); laneAllowedVehicleTypes[laneId] = vehicleTypes; // save allowed vehicle types into the fast-access array. // (1) ensure that the array is defined and large enough if (laneAllowedVehicleTypesArray[segmentId] == null) { laneAllowedVehicleTypesArray[segmentId] = new ExtVehicleType?[segmentInfo.m_lanes.Length]; } else if (laneAllowedVehicleTypesArray[segmentId].Length < segmentInfo.m_lanes.Length) { var oldArray = laneAllowedVehicleTypesArray[segmentId]; laneAllowedVehicleTypesArray[segmentId] = new ExtVehicleType?[segmentInfo.m_lanes.Length]; Array.Copy(oldArray, laneAllowedVehicleTypesArray[segmentId], oldArray.Length); } // (2) insert the custom speed limit laneAllowedVehicleTypesArray[segmentId][laneIndex] = vehicleTypes; } finally { Monitor.Exit(laneAllowedVehicleTypesLock); } }
/// <summary> /// Calculates for each segment the number of cars going to this segment. /// We use integer arithmetic for better performance. /// </summary> public Dictionary <ushort, uint> GetVehicleMetricGoingToSegment(float?minSpeed, ExtVehicleType?vehicleTypes = null, ExtVehicleType separateVehicleTypes = ExtVehicleType.None, bool debug = false) { Dictionary <ushort, uint> numCarsGoingToSegmentId = new Dictionary <ushort, uint>(); VehicleManager vehicleManager = Singleton <VehicleManager> .instance; NetManager netManager = Singleton <NetManager> .instance; for (var s = 0; s < 8; s++) { var segmentId = netManager.m_nodes.m_buffer[NodeId].GetSegment(s); if (segmentId == 0 || segmentId == SegmentId) { continue; } if (CustomRoadAI.GetSegmentGeometry(segmentId).IsIncomingOneWay(NodeId)) { continue; } numCarsGoingToSegmentId[segmentId] = 0; } List <ushort> vehicleIdsToReHandle = new List <ushort>(); foreach (KeyValuePair <ushort, VehiclePosition> e in Vehicles) { var vehicleId = e.Key; var carPos = e.Value; if (vehicleId <= 0 || carPos.ToSegment <= 0) { continue; } if ((vehicleManager.m_vehicles.m_buffer[vehicleId].m_flags & Vehicle.Flags.Created) == Vehicle.Flags.None) { vehicleIdsToReHandle.Add(vehicleId); continue; } if (minSpeed != null && vehicleManager.m_vehicles.m_buffer[vehicleId].GetLastFrameVelocity().magnitude < minSpeed) { continue; } VehiclePosition globalPos = TrafficPriority.GetVehiclePosition(vehicleId); if (globalPos == null || !globalPos.Valid || globalPos.LastFrame >> 7 < Singleton <SimulationManager> .instance.m_currentFrameIndex >> 7) // ~64 sec. { vehicleIdsToReHandle.Add(vehicleId); continue; } if (vehicleTypes != null) { if (vehicleTypes == ExtVehicleType.None) { if ((globalPos.VehicleType & separateVehicleTypes) != ExtVehicleType.None) { // we want all vehicles that do not have separate traffic lights continue; } } else { if ((globalPos.VehicleType & vehicleTypes) == ExtVehicleType.None) { continue; } } } //debug = vehicleManager.m_vehicles.m_buffer[vehicleId].Info.m_vehicleType == VehicleInfo.VehicleType.Tram; #if DEBUG /*if (debug) { * Log._Debug($"getNumCarsGoingToSegment: Handling vehicle {vehicleId} going from {carPos.FromSegment}/{SegmentId} to {carPos.ToSegment}. carState={globalPos.CarState}. lastUpdate={globalPos.LastCarStateUpdate}"); * }*/ #endif uint avgSegmentLength = (uint)Singleton <NetManager> .instance.m_segments.m_buffer[SegmentId].m_averageLength; uint normLength = (uint)(vehicleManager.m_vehicles.m_buffer[vehicleId].CalculateTotalLength(vehicleId) * 100u) / avgSegmentLength; #if DEBUG /*if (debug) { * Log._Debug($"getNumCarsGoingToSegment: NormLength of vehicle {vehicleId} going to {carPos.ToSegment}: {avgSegmentLength} -> {normLength}"); * }*/ #endif if (numCarsGoingToSegmentId.ContainsKey(carPos.ToSegment)) { /*if (carPos.OnEmergency) * numCarsGoingToSegmentId[carPos.ToSegment] += 10000f; * else*/ numCarsGoingToSegmentId[carPos.ToSegment] += normLength; } // "else" must not happen (incoming one-way) } foreach (ushort vehicleId in vehicleIdsToReHandle) { CustomVehicleAI.HandleVehicle(vehicleId, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleId], false, false); } return(numCarsGoingToSegmentId); }
/// <summary> /// Calculates for each segment the number of cars going to this segment. /// We use integer arithmetic for better performance. /// </summary> public Dictionary<ushort, uint> GetVehicleMetricGoingToSegment(float? minSpeed, ExtVehicleType? vehicleTypes=null, ExtVehicleType separateVehicleTypes=ExtVehicleType.None, bool debug = false) { Dictionary<ushort, uint> numCarsGoingToSegmentId = new Dictionary<ushort, uint>(); VehicleManager vehicleManager = Singleton<VehicleManager>.instance; NetManager netManager = Singleton<NetManager>.instance; for (var s = 0; s < 8; s++) { var segmentId = netManager.m_nodes.m_buffer[NodeId].GetSegment(s); if (segmentId == 0 || segmentId == SegmentId) continue; if (CustomRoadAI.GetSegmentGeometry(segmentId).IsIncomingOneWay(NodeId)) continue; numCarsGoingToSegmentId[segmentId] = 0; } List<ushort> vehicleIdsToReHandle = new List<ushort>(); foreach (KeyValuePair<ushort, VehiclePosition> e in Vehicles) { var vehicleId = e.Key; var carPos = e.Value; if (vehicleId <= 0 || carPos.ToSegment <= 0) continue; if ((vehicleManager.m_vehicles.m_buffer[vehicleId].m_flags & Vehicle.Flags.Created) == 0) { vehicleIdsToReHandle.Add(vehicleId); continue; } if (minSpeed != null && vehicleManager.m_vehicles.m_buffer[vehicleId].GetLastFrameVelocity().magnitude < minSpeed) continue; VehiclePosition globalPos = TrafficPriority.GetVehiclePosition(vehicleId); if (globalPos == null || !globalPos.Valid || globalPos.LastFrame >> 7 < Singleton<SimulationManager>.instance.m_currentFrameIndex >> 7) { // ~64 sec. vehicleIdsToReHandle.Add(vehicleId); continue; } if (vehicleTypes != null) { if (vehicleTypes == ExtVehicleType.None) { if ((globalPos.VehicleType & separateVehicleTypes) != ExtVehicleType.None) { // we want all vehicles that do not have separate traffic lights continue; } } else { if ((globalPos.VehicleType & vehicleTypes) == ExtVehicleType.None) { continue; } } } debug = vehicleManager.m_vehicles.m_buffer[vehicleId].Info.m_vehicleType == VehicleInfo.VehicleType.Tram; #if DEBUG if (debug) { Log._Debug($"getNumCarsGoingToSegment: Handling vehicle {vehicleId} going from {carPos.FromSegment}/{SegmentId} to {carPos.ToSegment}. carState={globalPos.CarState}. lastUpdate={globalPos.LastCarStateUpdate}"); } #endif uint avgSegmentLength = (uint)Singleton<NetManager>.instance.m_segments.m_buffer[SegmentId].m_averageLength; uint normLength = (uint)(vehicleManager.m_vehicles.m_buffer[vehicleId].CalculateTotalLength(vehicleId) * 100u) / avgSegmentLength; #if DEBUG /*if (debug) { Log._Debug($"getNumCarsGoingToSegment: NormLength of vehicle {vehicleId} going to {carPos.ToSegment}: {avgSegmentLength} -> {normLength}"); }*/ #endif if (numCarsGoingToSegmentId.ContainsKey(carPos.ToSegment)) { /*if (carPos.OnEmergency) numCarsGoingToSegmentId[carPos.ToSegment] += 10000f; else*/ numCarsGoingToSegmentId[carPos.ToSegment] += normLength; } // "else" must not happen (incoming one-way) } foreach (ushort vehicleId in vehicleIdsToReHandle) { CustomVehicleAI.HandleVehicle(vehicleId, ref Singleton<VehicleManager>.instance.m_vehicles.m_buffer[vehicleId], false, false); } return numCarsGoingToSegmentId; }
public static bool IsTramAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Tram); }
public static bool IsCargoTruckAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.CargoTruck); }
/// <summary> /// Removes the given vehicle type from the set of allowed vehicles at the specified lane /// </summary> /// <param name="segmentId"></param> /// <param name="laneIndex"></param> /// <param name="laneId"></param> /// <param name="laneInfo"></param> /// <param name="road"></param> /// <param name="vehicleType"></param> public static void RemoveAllowedType(ushort segmentId, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType) { ExtVehicleType allowedTypes = GetAllowedVehicleTypes(segmentId, laneIndex, laneId, laneInfo); allowedTypes &= ~vehicleType; Flags.setLaneAllowedVehicleTypes(segmentId, laneIndex, laneId, allowedTypes); }
public long CheckNextChange(ushort segmentId, bool startNode, ExtVehicleType vehicleType, int lightType) { var curStep = CurrentStep; var nextStep = (CurrentStep + 1) % NumSteps(); var numFrames = Steps[CurrentStep].MaxTimeRemaining(); RoadBaseAI.TrafficLightState currentState; CustomSegmentLights segmentLights = CustomSegmentLightsManager.Instance.GetSegmentLights(segmentId, startNode, false); if (segmentLights == null) { Log._Debug($"CheckNextChange: No segment lights at node {NodeId}, segment {segmentId}"); return(99); } CustomSegmentLight segmentLight = segmentLights.GetCustomLight(vehicleType); if (segmentLight == null) { Log._Debug($"CheckNextChange: No segment light at node {NodeId}, segment {segmentId}"); return(99); } if (lightType == 0) { currentState = segmentLight.LightMain; } else if (lightType == 1) { currentState = segmentLight.LightLeft; } else if (lightType == 2) { currentState = segmentLight.LightRight; } else { currentState = segmentLights.PedestrianLightState == null ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)segmentLights.PedestrianLightState; } while (true) { if (nextStep == curStep) { numFrames = 99; break; } var light = Steps[nextStep].GetLight(segmentId, vehicleType, lightType); if (light != currentState) { break; } else { numFrames += Steps[nextStep].maxTime; } nextStep = (nextStep + 1) % NumSteps(); } return(numFrames); }
/// <summary> /// Sets the allowed vehicle types for the given segment and lane. /// </summary> /// <param name="segmentId"></param> /// <param name="laneIndex"></param> /// <param name="laneId"></param> /// <param name="allowedTypes"></param> /// <returns></returns> internal bool SetAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo, uint laneId, ExtVehicleType allowedTypes) { if (!Services.NetService.IsLaneValid(laneId)) { return(false); } if (!Services.NetService.IsSegmentValid(segmentId)) { // TODO we do not need the segmentId given here. Lane is enough return(false); } allowedTypes &= GetBaseMask(segmentInfo.m_lanes[laneIndex], VehicleRestrictionsMode.Configured); // ensure default base mask Flags.setLaneAllowedVehicleTypes(segmentId, laneIndex, laneId, allowedTypes); SubscribeToSegmentGeometry(segmentId); NotifyStartEndNode(segmentId); if (OptionsManager.Instance.MayPublishSegmentChanges()) { Services.NetService.PublishSegmentChanges(segmentId); } return(true); }
class CustomTransportLineAI : TransportLineAI { // TODO inherit from NetAI (in order to keep the correct references to `base`) public static bool CustomStartPathFind(ushort segmentID, ref NetSegment data, ItemClass.Service netService, ItemClass.Service netService2, VehicleInfo.VehicleType vehicleType, bool skipQueue) { if (data.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(data.m_path); data.m_path = 0u; } NetManager netManager = Singleton <NetManager> .instance; if ((netManager.m_nodes.m_buffer[(int)data.m_startNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None) { for (int i = 0; i < 8; i++) { ushort segment = netManager.m_nodes.m_buffer[(int)data.m_startNode].GetSegment(i); if (segment != 0 && segment != segmentID && netManager.m_segments.m_buffer[(int)segment].m_path != 0u) { return(true); } } } if ((netManager.m_nodes.m_buffer[(int)data.m_endNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None) { for (int j = 0; j < 8; j++) { ushort segment2 = netManager.m_nodes.m_buffer[(int)data.m_endNode].GetSegment(j); if (segment2 != 0 && segment2 != segmentID && netManager.m_segments.m_buffer[(int)segment2].m_path != 0u) { return(true); } } } Vector3 position = netManager.m_nodes.m_buffer[(int)data.m_startNode].m_position; Vector3 position2 = netManager.m_nodes.m_buffer[(int)data.m_endNode].m_position; #if DEBUG bool debug = GlobalConfig.Instance.Debug.Switches[18]; if (debug) { Log._Debug($"TransportLineAI.CustomStartPathFind({segmentID}, ..., {netService}, {netService2}, {vehicleType}, {skipQueue}): startNode={data.m_startNode} @ {position}, endNode={data.m_endNode} @ {position2} -- line: {netManager.m_nodes.m_buffer[(int)data.m_startNode].m_transportLine}/{netManager.m_nodes.m_buffer[(int)data.m_endNode].m_transportLine}"); } #endif PathUnit.Position startPosA; PathUnit.Position startPosB; float startSqrDistA; float startSqrDistB; if (!CustomPathManager.FindPathPosition(position, netService, netService2, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, vehicleType, true, false, 32f, out startPosA, out startPosB, out startSqrDistA, out startSqrDistB)) { CustomTransportLineAI.CheckSegmentProblems(segmentID, ref data); return(true); } PathUnit.Position endPosA; PathUnit.Position endPosB; float endSqrDistA; float endSqrDistB; if (!CustomPathManager.FindPathPosition(position2, netService, netService2, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, vehicleType, true, false, 32f, out endPosA, out endPosB, out endSqrDistA, out endSqrDistB)) { CustomTransportLineAI.CheckSegmentProblems(segmentID, ref data); return(true); } if ((netManager.m_nodes.m_buffer[(int)data.m_startNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None) { startPosB = default(PathUnit.Position); } if ((netManager.m_nodes.m_buffer[(int)data.m_endNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None) { endPosB = default(PathUnit.Position); } if (vehicleType != VehicleInfo.VehicleType.None) { startPosA.m_offset = 128; startPosB.m_offset = 128; endPosA.m_offset = 128; endPosB.m_offset = 128; } else { startPosA.m_offset = (byte)Mathf.Clamp(startPosA.m_offset, 1, 254); startPosB.m_offset = (byte)Mathf.Clamp(startPosB.m_offset, 1, 254); endPosA.m_offset = (byte)Mathf.Clamp(endPosA.m_offset, 1, 254); endPosB.m_offset = (byte)Mathf.Clamp(endPosB.m_offset, 1, 254); } bool stopLane = CustomTransportLineAI.GetStopLane(ref startPosA, vehicleType); bool stopLane2 = CustomTransportLineAI.GetStopLane(ref startPosB, vehicleType); bool stopLane3 = CustomTransportLineAI.GetStopLane(ref endPosA, vehicleType); bool stopLane4 = CustomTransportLineAI.GetStopLane(ref endPosB, vehicleType); if ((!stopLane && !stopLane2) || (!stopLane3 && !stopLane4)) { CustomTransportLineAI.CheckSegmentProblems(segmentID, ref data); return(true); } ExtVehicleType extVehicleType = ExtVehicleType.None; #if BENCHMARK using (var bm = new Benchmark(null, "extVehicleType")) { #endif if ((vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Bus; } if ((vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro | VehicleInfo.VehicleType.Monorail)) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.PassengerTrain; } if ((vehicleType & VehicleInfo.VehicleType.Tram) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Tram; } if ((vehicleType & VehicleInfo.VehicleType.Ship) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.PassengerShip; } if ((vehicleType & VehicleInfo.VehicleType.Plane) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.PassengerPlane; } if ((vehicleType & VehicleInfo.VehicleType.Ferry) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Ferry; } if ((vehicleType & VehicleInfo.VehicleType.Blimp) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Blimp; } if ((vehicleType & VehicleInfo.VehicleType.CableCar) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.CableCar; } #if BENCHMARK } #endif //Log._Debug($"Transport line. extVehicleType={extVehicleType}"); uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtCitizenInstance.ExtPathType.None; args.extVehicleType = extVehicleType; args.vehicleId = 0; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default(PathUnit.Position); args.vehicleTypes = vehicleType; args.isHeavyVehicle = false; args.hasCombustionEngine = false; args.ignoreBlocked = true; args.ignoreFlooded = false; args.ignoreCosts = false; args.randomParking = false; args.stablePath = true; args.skipQueue = skipQueue; if (vehicleType == VehicleInfo.VehicleType.None) { args.laneTypes = NetInfo.LaneType.Pedestrian; args.maxLength = 160000f; } else { args.laneTypes = (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); args.maxLength = 20000f; } if (CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { // NON-STOCK CODE END if (startPosA.m_segment != 0 && startPosB.m_segment != 0) { netManager.m_nodes.m_buffer[data.m_startNode].m_flags |= NetNode.Flags.Ambiguous; } else { netManager.m_nodes.m_buffer[data.m_startNode].m_flags &= ~NetNode.Flags.Ambiguous; } if (endPosA.m_segment != 0 && endPosB.m_segment != 0) { netManager.m_nodes.m_buffer[data.m_endNode].m_flags |= NetNode.Flags.Ambiguous; } else { netManager.m_nodes.m_buffer[data.m_endNode].m_flags &= ~NetNode.Flags.Ambiguous; } data.m_path = path; data.m_flags |= NetSegment.Flags.WaitingPath; #if DEBUG if (debug) { Log._Debug($"TransportLineAI.CustomStartPathFind({segmentID}, ..., {netService}, {netService2}, {vehicleType}, {skipQueue}): Started calculating path {path} for extVehicleType={extVehicleType}, startPosA=[seg={startPosA.m_segment}, lane={startPosA.m_lane}, off={startPosA.m_offset}], startPosB=[seg={startPosB.m_segment}, lane={startPosB.m_lane}, off={startPosB.m_offset}], endPosA=[seg={endPosA.m_segment}, lane={endPosA.m_lane}, off={endPosA.m_offset}], endPosB=[seg={endPosB.m_segment}, lane={endPosB.m_lane}, off={endPosB.m_offset}]"); } #endif return(false); } CustomTransportLineAI.CheckSegmentProblems(segmentID, ref data); return(true); }
public LaneVehicleTypes(uint laneId, ExtVehicleType vehicleTypes) { this.laneId = laneId; this.vehicleTypes = vehicleTypes; }
public bool CustomStartPathFind(ushort vehicleId, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { ExtVehicleType emergencyVehType = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0 ? ExtVehicleType.Emergency : ExtVehicleType.Service; ExtVehicleType vehicleType = ExtVehicleManager.Instance.OnStartPathFind(vehicleId, ref vehicleData, emergencyVehType); VehicleInfo info = m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; if (PathManager.FindPathPosition( startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out PathUnit.Position startPosA, out PathUnit.Position startPosB, out float startDistSqrA, out _) && PathManager.FindPathPosition( endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, undergroundTarget, false, 32f, out PathUnit.Position endPosA, out PathUnit.Position endPosB, out float endDistSqrA, out _)) { if (!startBothWays || startDistSqrA < 10f) { startPosB = default; } if (!endBothWays || endDistSqrA < 10f) { endPosB = default; } // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtPathType.None; args.extVehicleType = vehicleType; args.vehicleId = vehicleId; args.spawned = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default; args.laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle; args.vehicleTypes = info.m_vehicleType; args.maxLength = 20000f; args.isHeavyVehicle = IsHeavyVehicle(); args.hasCombustionEngine = CombustionEngine(); args.ignoreBlocked = IgnoreBlocked(vehicleId, ref vehicleData); args.ignoreFlooded = false; args.ignoreCosts = false; args.randomParking = false; args.stablePath = false; args.skipQueue = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; if (CustomPathManager._instance.CustomCreatePath( out uint path, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { // NON-STOCK CODE END if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays) { #if DEBUG //Log._Debug($"CustomTrainAI.CustomStartPathFind called for vehicle {vehicleID}"); #endif /// NON-STOCK CODE START /// ExtVehicleType vehicleType = VehicleStateManager.Instance._GetVehicleState(vehicleID).VehicleType; if (vehicleType == ExtVehicleType.None) { #if DEBUG Log.Warning($"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 /*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 /// VehicleInfo info = this.m_info; if ((vehicleData.m_flags & Vehicle.Flags.Spawned) == 0 && Vector3.Distance(startPos, endPos) < 100f) { startPos = endPos; } bool allowUnderground; bool allowUnderground2; if (info.m_vehicleType == VehicleInfo.VehicleType.Metro) { allowUnderground = true; allowUnderground2 = true; } else { allowUnderground = ((vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0); allowUnderground2 = false; } PathUnit.Position startPosA; PathUnit.Position startPosB; float startSqrDistA; float startSqrDistB; PathUnit.Position endPosA; PathUnit.Position endPosB; float endSqrDistA; float endSqrDistB; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out startSqrDistA, out startSqrDistB) && CustomPathManager.FindPathPosition(endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, allowUnderground2, false, 32f, out endPosA, out endPosB, out endSqrDistA, out endSqrDistB)) { if (!startBothWays || startSqrDistB > startSqrDistA * 1.2f) { startPosB = default(PathUnit.Position); } if (!endBothWays || endSqrDistB > endSqrDistA * 1.2f) { endPosB = default(PathUnit.Position); } uint path; if (CustomPathManager._instance.CreatePath((ExtVehicleType)vehicleType, vehicleID, ExtCitizenInstance.ExtPathType.None, out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, false, false, true, false)) { #if USEPATHWAITCOUNTER VehicleState state = VehicleStateManager.Instance._GetVehicleState(vehicleID); state.PathWaitCounter = 0; #endif if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
public long CheckNextChange(ushort segmentId, ExtVehicleType vehicleType, int lightType) { var curStep = CurrentStep; var nextStep = (CurrentStep + 1) % NumSteps(); var numFrames = Steps[CurrentStep].MaxTimeRemaining(); RoadBaseAI.TrafficLightState currentState; CustomSegmentLights segmentLights = CustomTrafficLights.GetSegmentLights(NodeId, segmentId); if (segmentLights == null) { Log._Debug($"CheckNextChange: No segment lights at node {NodeId}, segment {segmentId}"); return 99; } CustomSegmentLight segmentLight = segmentLights.GetCustomLight(vehicleType); if (segmentLight == null) { Log._Debug($"CheckNextChange: No segment light at node {NodeId}, segment {segmentId}"); return 99; } if (lightType == 0) currentState = segmentLight.GetLightMain(); else if (lightType == 1) currentState = segmentLight.GetLightLeft(); else if (lightType == 2) currentState = segmentLight.GetLightRight(); else currentState = segmentLights.PedestrianLightState == null ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)segmentLights.PedestrianLightState; while (true) { if (nextStep == curStep) { numFrames = 99; break; } var light = Steps[nextStep].GetLight(segmentId, vehicleType, lightType); if (light != currentState) { break; } else { numFrames += Steps[nextStep].maxTime; } nextStep = (nextStep + 1) % NumSteps(); } return numFrames; }
public bool CalculatePath(ExtVehicleType vehicleType, uint unit, bool skipQueue) { if (Singleton<PathManager>.instance.AddPathReference(unit)) { try { Monitor.Enter(QueueLock); if (skipQueue) { if (this.QueueLast == 0u) { this.QueueLast = unit; } else { this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_nextPathUnit = this.QueueFirst; } this.QueueFirst = unit; } else { if (this.QueueLast == 0u) { this.QueueFirst = unit; } else { this.PathUnits.m_buffer[(int)((UIntPtr)this.QueueLast)].m_nextPathUnit = unit; } this.QueueLast = unit; } this.PathUnits.m_buffer[unit].m_pathFindFlags |= 1; this.m_queuedPathFindCount++; pathUnitExtVehicleType[unit] = vehicleType; Monitor.Pulse(this.QueueLock); } finally { Monitor.Exit(this.QueueLock); } return true; } return false; }
// TODO improve & remove public void Housekeeping(bool mayDelete, bool calculateAutoPedLight) { #if DEBUGHK bool debug = DebugSwitch.TimedTrafficLights.Get() && DebugSettings.NodeId == NodeId; #endif // we intentionally never delete vehicle types (because we may want to retain traffic light states if a segment is upgraded or replaced) ICustomSegmentLight mainLight = MainSegmentLight; ushort nodeId = NodeId; HashSet <ExtVehicleType> setupLights = new HashSet <ExtVehicleType>(); IDictionary <byte, ExtVehicleType> allAllowedTypes = Constants.ManagerFactory.VehicleRestrictionsManager.GetAllowedVehicleTypesAsDict(SegmentId, nodeId, VehicleRestrictionsMode.Restricted); // TODO improve ExtVehicleType allAllowedMask = Constants.ManagerFactory.VehicleRestrictionsManager.GetAllowedVehicleTypes(SegmentId, nodeId, VehicleRestrictionsMode.Restricted); SeparateVehicleTypes = ExtVehicleType.None; #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping started @ seg. {SegmentId}, node {nodeId}, allAllowedTypes={allAllowedTypes.DictionaryToString()}, allAllowedMask={allAllowedMask}"); } #endif //bool addPedestrianLight = false; uint separateLanes = 0; int defaultLanes = 0; NetInfo segmentInfo = null; Constants.ServiceFactory.NetService.ProcessSegment(SegmentId, delegate(ushort segId, ref NetSegment segment) { VehicleTypeByLaneIndex = new ExtVehicleType?[segment.Info.m_lanes.Length]; segmentInfo = segment.Info; return(true); }); HashSet <byte> laneIndicesWithoutSeparateLights = new HashSet <byte>(allAllowedTypes.Keys); // TODO improve // check if separate traffic lights are required bool separateLightsRequired = false; foreach (KeyValuePair <byte, ExtVehicleType> e in allAllowedTypes) { if (e.Value != allAllowedMask) { separateLightsRequired = true; break; } } // set up vehicle-separated traffic lights if (separateLightsRequired) { foreach (KeyValuePair <byte, ExtVehicleType> e in allAllowedTypes) { byte laneIndex = e.Key; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; ExtVehicleType allowedTypes = e.Value; ExtVehicleType defaultMask = Constants.ManagerFactory.VehicleRestrictionsManager.GetDefaultAllowedVehicleTypes(SegmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Unrestricted); #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Processing lane {laneIndex} with allowedTypes={allowedTypes}, defaultMask={defaultMask}"); } #endif if (laneInfo.m_vehicleType == VehicleInfo.VehicleType.Car && allowedTypes == defaultMask) { #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}, lane {laneIndex}: Allowed types equal default mask. Ignoring lane."); } #endif // no vehicle restrictions applied, generic lights are handled further below ++defaultLanes; continue; } ExtVehicleType mask = allowedTypes & ~ExtVehicleType.Emergency; #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}, lane {laneIndex}: Trying to add {mask} light"); } #endif ICustomSegmentLight segmentLight; if (!CustomLights.TryGetValue(mask, out segmentLight)) { // add a new light segmentLight = new CustomSegmentLight(this, RoadBaseAI.TrafficLightState.Red); if (mainLight != null) { segmentLight.CurrentMode = mainLight.CurrentMode; segmentLight.SetStates(mainLight.LightMain, mainLight.LightLeft, mainLight.LightRight, false); } #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}, lane {laneIndex}: Light for mask {mask} does not exist. Created new light: {segmentLight} (mainLight: {mainLight})"); } #endif CustomLights.Add(mask, segmentLight); VehicleTypes.AddFirst(mask); } mainVehicleType = mask; VehicleTypeByLaneIndex[laneIndex] = mask; laneIndicesWithoutSeparateLights.Remove(laneIndex); ++separateLanes; //addPedestrianLight = true; setupLights.Add(mask); SeparateVehicleTypes |= mask; #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Finished processing lane {laneIndex}: mainVehicleType={mainVehicleType}, VehicleTypeByLaneIndex={VehicleTypeByLaneIndex.ArrayToString()}, laneIndicesWithoutSeparateLights={laneIndicesWithoutSeparateLights.CollectionToString()}, numLights={separateLanes}, SeparateVehicleTypes={SeparateVehicleTypes}"); } #endif } } if (separateLanes == 0 || defaultLanes > 0) { #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Adding default main vehicle light: {DEFAULT_MAIN_VEHICLETYPE}"); } #endif // generic traffic lights ICustomSegmentLight defaultSegmentLight; if (!CustomLights.TryGetValue(DEFAULT_MAIN_VEHICLETYPE, out defaultSegmentLight)) { defaultSegmentLight = new CustomSegmentLight(this, RoadBaseAI.TrafficLightState.Red); if (mainLight != null) { defaultSegmentLight.CurrentMode = mainLight.CurrentMode; defaultSegmentLight.SetStates(mainLight.LightMain, mainLight.LightLeft, mainLight.LightRight, false); } CustomLights.Add(DEFAULT_MAIN_VEHICLETYPE, defaultSegmentLight); VehicleTypes.AddFirst(DEFAULT_MAIN_VEHICLETYPE); } mainVehicleType = DEFAULT_MAIN_VEHICLETYPE; setupLights.Add(DEFAULT_MAIN_VEHICLETYPE); foreach (byte laneIndex in laneIndicesWithoutSeparateLights) { VehicleTypeByLaneIndex[laneIndex] = ExtVehicleType.None; } #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Added default main vehicle light: {defaultSegmentLight}"); } #endif //addPedestrianLight = true; } else { //addPedestrianLight = allAllowedMask == ExtVehicleType.None || (allAllowedMask & ~ExtVehicleType.RailVehicle) != ExtVehicleType.None; } #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Created all necessary lights. VehicleTypeByLaneIndex={VehicleTypeByLaneIndex.ArrayToString()}, CustomLights={CustomLights.DictionaryToString()}"); } #endif if (mayDelete) { // delete traffic lights for non-existing vehicle-separated configurations HashSet <ExtVehicleType> vehicleTypesToDelete = new HashSet <ExtVehicleType>(); foreach (KeyValuePair <ExtVehicleType, ICustomSegmentLight> e in CustomLights) { /*if (e.Key == DEFAULT_MAIN_VEHICLETYPE) { * continue; * }*/ if (!setupLights.Contains(e.Key)) { vehicleTypesToDelete.Add(e.Key); } } #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Going to delete unnecessary lights now: vehicleTypesToDelete={vehicleTypesToDelete.CollectionToString()}"); } #endif foreach (ExtVehicleType vehicleType in vehicleTypesToDelete) { CustomLights.Remove(vehicleType); VehicleTypes.Remove(vehicleType); } } if (CustomLights.ContainsKey(DEFAULT_MAIN_VEHICLETYPE) && VehicleTypes.First.Value != DEFAULT_MAIN_VEHICLETYPE) { VehicleTypes.Remove(DEFAULT_MAIN_VEHICLETYPE); VehicleTypes.AddFirst(DEFAULT_MAIN_VEHICLETYPE); } //if (addPedestrianLight) { #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: adding pedestrian light"); } #endif if (InternalPedestrianLightState == null) { InternalPedestrianLightState = RoadBaseAI.TrafficLightState.Red; } /*} else { * InternalPedestrianLightState = null; * }*/ OnChange(calculateAutoPedLight); #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Housekeeping complete. VehicleTypeByLaneIndex={VehicleTypeByLaneIndex.ArrayToString()} CustomLights={CustomLights.DictionaryToString()}"); } #endif }
public static bool IsAllowed(ExtVehicleType? allowedTypes, ExtVehicleType vehicleType) { return allowedTypes == null || ((ExtVehicleType)allowedTypes & vehicleType) != ExtVehicleType.None; }
// CitizenAI public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenData, Vector3 startPos, Vector3 endPos, VehicleInfo vehicleInfo) { CitizenManager citMan = Singleton <CitizenManager> .instance; if (citMan.m_citizens.m_buffer[citizenData.m_citizen].CurrentLocation == Citizen.Location.Home) { currentTransportMode[instanceID] = TransportMode.None; // reset currently used transport mode at home } SimulationManager simManager = Singleton <SimulationManager> .instance; Citizen.Wealth wealthLevel = citMan.m_citizens.m_buffer[citizenData.m_citizen].WealthLevel; bool couldUseTaxi = false; // could cim use a taxi if it was not forbidden because of randomization? bool couldUseCar = false; bool couldUseBike = false; bool wouldAffordTaxiVoluntarily = false; bool randomParking = false; if (vehicleInfo != null) { if (vehicleInfo.m_class.m_subService == ItemClass.SubService.PublicTransportTaxi) { if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTaxi) == CitizenInstance.Flags.None && Singleton <DistrictManager> .instance.m_districts.m_buffer[0].m_productionData.m_finalTaxiCapacity != 0u) { couldUseTaxi = true; if (currentTransportMode[instanceID] == TransportMode.Taxi || (currentTransportMode[instanceID] == TransportMode.None && ((simManager.m_isNightTime && simManager.m_randomizer.Int32(100) < NIGHT_TAXI_USAGE_PROBABILITY[(int)wealthLevel]) || (!simManager.m_isNightTime && simManager.m_randomizer.Int32(100) < DAY_TAXI_USAGE_PROBABILITY[(int)wealthLevel])))) { wouldAffordTaxiVoluntarily = true; // NON-STOCK CODE } } } else { // NON-STOCK CODE START if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { couldUseBike = true; } else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Car) { couldUseCar = true; } // NON-STOCK CODE END if (citizenData.m_targetBuilding != 0 && Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)citizenData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office) { randomParking = true; } } } byte districtId = Singleton <DistrictManager> .instance.GetDistrict(startPos); DistrictPolicies.Services servicePolicies = Singleton <DistrictManager> .instance.m_districts.m_buffer[(int)districtId].m_servicePolicies; int transportUsageProb = (servicePolicies & DistrictPolicies.Services.FreeTransport) != DistrictPolicies.Services.None ? FREE_TRANSPORT_USAGE_PROBABILITY[(int)wealthLevel] : TRANSPORT_USAGE_PROBABILITY[(int)wealthLevel]; bool useTaxi = false; bool useBike = false; bool useCar = false; bool usePublicTransport = false; if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None) // STOCK CODE { if (currentTransportMode[instanceID] == TransportMode.PublicTransport || useTaxi || (currentTransportMode[instanceID] == TransportMode.None && simManager.m_randomizer.Int32(100) < transportUsageProb)) { usePublicTransport = true; } } ushort parkedVehicle = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenData.m_citizen].m_parkedVehicle; bool couldUseParkedCar = false; // cims are not allowed to use pocket cars (unless we have no choice) PathUnit.Position vehiclePosition = default(PathUnit.Position); if (parkedVehicle != 0) { Vector3 position = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[(int)parkedVehicle].m_position; if (PathManager.FindPathPosition(position, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, false, false, 32f, out vehiclePosition)) { couldUseParkedCar = true; } } if (couldUseBike) { // everyone who has a bike may use it useBike = true; } if (!usePublicTransport) { if (couldUseParkedCar && currentTransportMode[instanceID] == TransportMode.Car) { useCar = true; } else if ((wouldAffordTaxiVoluntarily && currentTransportMode[instanceID] == TransportMode.Taxi) || couldUseTaxi) { useTaxi = true; } else if (couldUseCar) { // pocket car fallback useCar = true; } } ExtVehicleType extVehicleType = ExtVehicleType.None; NetInfo.LaneType laneType = NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleType = VehicleInfo.VehicleType.None; if (usePublicTransport) { currentTransportMode[instanceID] = TransportMode.PublicTransport; laneType |= NetInfo.LaneType.PublicTransport; extVehicleType |= ExtVehicleType.PublicTransport; } if (useBike && vehicleInfo != null) { laneType |= NetInfo.LaneType.Vehicle; vehicleType |= vehicleInfo.m_vehicleType; extVehicleType |= ExtVehicleType.Bicycle; } if (useTaxi && vehicleInfo != null) { currentTransportMode[instanceID] = TransportMode.Taxi; laneType |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); vehicleType |= vehicleInfo.m_vehicleType; extVehicleType |= ExtVehicleType.Taxi; } if (useCar && vehicleInfo != null) { currentTransportMode[instanceID] = TransportMode.Car; laneType |= NetInfo.LaneType.Vehicle; vehicleType |= vehicleInfo.m_vehicleType; extVehicleType |= ExtVehicleType.PassengerCar; } //Log._Debug($"Citizen {instanceID}: usePublicTransport={usePublicTransport} useCar={useCar} useTaxi={useTaxi} useBike={useBike} vehicleInfo.vehicleType={vehicleInfo?.m_vehicleType} laneType={laneType} vehicleType={vehicleType} extVehicleType={extVehicleType}"); bool allowUnderground = (citizenData.m_flags & (CitizenInstance.Flags.Underground | CitizenInstance.Flags.Transition)) != CitizenInstance.Flags.None; PathUnit.Position startPosA; PathUnit.Position endPosA; if (this.FindPathPosition(instanceID, ref citizenData, startPos, laneType, vehicleType, allowUnderground, out startPosA) && this.FindPathPosition(instanceID, ref citizenData, endPos, laneType, vehicleType, false, out endPosA)) { PathUnit.Position position2 = default(PathUnit.Position); uint path; #if DEBUG //Log._Debug($"CustomCitizenAI: citizen instance {instanceID}, id {citizenData.m_citizen}. vehicleType={vehicleType} laneType={laneType} extVehicleType={extVehicleType} usePublicTransport={usePublicTransport} useTaxi={useTaxi} useBike={useBike} useCar={useCar} wealthLevel={wealthLevel}"); #endif // NON-STOCK CODE END // if (Singleton <CustomPathManager> .instance.CreatePath(false, (ExtVehicleType)extVehicleType, null, out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, startPosA, position2, endPosA, position2, vehiclePosition, laneType, vehicleType, 20000f, false, false, false, false, randomParking)) { if (citizenData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(citizenData.m_path); } citizenData.m_path = path; citizenData.m_flags |= CitizenInstance.Flags.WaitingPath; return(true); } } return(false); }
public static bool IsPassengerTrainAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.PassengerTrain); }
/// <summary> /// coppies vehicle restrictions of the current segment /// and applies them to all segments until the next junction. /// </summary> /// <param name="sortedLaneIndex">if provided only current lane is considered</param> /// <param name="vehicleTypes"> /// if provided only bits for which vehicleTypes is set are considered. /// </param> private void ApplyRestrictionsToAllSegments( int?sortedLaneIndex = null, ExtVehicleType?vehicleTypes = null) { NetManager netManager = Singleton <NetManager> .instance; NetInfo selectedSegmentInfo = netManager.m_segments.m_buffer[SelectedSegmentId].Info; bool LaneVisitorFun(SegmentLaneVisitData data) { if (data.SegVisitData.Initial) { return(true); } if (sortedLaneIndex != null && data.SortedLaneIndex != sortedLaneIndex) { return(true); } ushort segmentId = data.SegVisitData.CurSeg.segmentId; NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info; byte selectedLaneIndex = data.InitLanePos.laneIndex; NetInfo.Lane selectedLaneInfo = selectedSegmentInfo.m_lanes[selectedLaneIndex]; uint laneId = data.CurLanePos.laneId; byte laneIndex = data.CurLanePos.laneIndex; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; // apply restrictions of selected segment & lane ExtVehicleType mask = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes( SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo, VehicleRestrictionsMode.Configured);; if (vehicleTypes != null) { ExtVehicleType currentMask = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Configured); // only apply changes where types is 1. that means: // for bits where types is 0, use currentMask, // for bits where types is 1, use initial mask. ExtVehicleType types2 = (ExtVehicleType)vehicleTypes; //cast mask = (types2 & mask) | (~types2 & currentMask); } VehicleRestrictionsManager.Instance.SetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, laneId, mask); RefreshCurrentRestrictedSegmentIds(segmentId); return(true); } SegmentLaneTraverser.Traverse( SelectedSegmentId, SegmentTraverser.TraverseDirection.AnyDirection, SegmentTraverser.TraverseSide.AnySide, SegmentLaneTraverser.LaneStopCriterion.LaneCount, SegmentTraverser.SegmentStopCriterion.Junction, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES, LaneVisitorFun); }
public RoadBaseAI.TrafficLightState GetLight(ushort segmentId, ExtVehicleType vehicleType, int lightType) { CustomSegmentLight segLight = segmentLights[segmentId].GetCustomLight(vehicleType); if (segLight != null) { switch (lightType) { case 0: return segLight.LightMain; case 1: return segLight.LightLeft; case 2: return segLight.LightRight; case 3: RoadBaseAI.TrafficLightState? pedState = segmentLights[segmentId].PedestrianLightState; return pedState == null ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)pedState; } } return RoadBaseAI.TrafficLightState.Green; }
private bool DrawVehicleRestrictionHandles(ushort segmentId, ref NetSegment segment, bool viewOnly, out bool stateUpdated) { stateUpdated = false; if (viewOnly && !Options.vehicleRestrictionsOverlay && MainTool.GetToolMode() != ToolMode.VehicleRestrictions) { return(false); } Vector3 center = segment.m_bounds.center; bool visible = GeometryUtil.WorldToScreenPoint(center, out Vector3 _); if (!visible) { return(false); } Vector3 camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; Vector3 diff = center - camPos; if (diff.sqrMagnitude > TrafficManagerTool.MAX_OVERLAY_DISTANCE_SQR) { return(false); // do not draw if too distant } int numLanes = GeometryUtil.GetSegmentNumVehicleLanes( segmentId, null, out int numDirections, VehicleRestrictionsManager.VEHICLE_TYPES); // draw vehicle restrictions over each lane NetInfo segmentInfo = segment.Info; Vector3 yu = (segment.m_endDirection - segment.m_startDirection).normalized; // if ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) // yu = -yu; Vector3 xu = Vector3.Cross(yu, new Vector3(0, 1f, 0)).normalized; float f = viewOnly ? 4f : 7f; // reserved sign size in game coordinates int maxNumSigns = 0; if (VehicleRestrictionsManager.Instance.IsRoadSegment(segmentInfo)) { maxNumSigns = RoadVehicleTypes.Length; } else if (VehicleRestrictionsManager.Instance.IsRailSegment(segmentInfo)) { maxNumSigns = RailVehicleTypes.Length; } // Vector3 zero = center - 0.5f * (float)(numLanes + numDirections - 1) * f * (xu + yu); // "bottom left" Vector3 zero = center - (0.5f * (numLanes - 1 + numDirections - 1) * f * xu) - (0.5f * maxNumSigns * f * yu); // "bottom left" // if (!viewOnly) // Log._Debug($"xu: {xu.ToString()} yu: {yu.ToString()} center: {center.ToString()} // zero: {zero.ToString()} numLanes: {numLanes} numDirections: {numDirections}");*/ uint x = 0; Color guiColor = GUI.color; IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes( segmentId, ref segment, null, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES); bool hovered = false; HashSet <NetInfo.Direction> directions = new HashSet <NetInfo.Direction>(); int sortedLaneIndex = -1; foreach (LanePos laneData in sortedLanes) { ++sortedLaneIndex; uint laneId = laneData.laneId; byte laneIndex = laneData.laneIndex; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if (!directions.Contains(laneInfo.m_finalDirection)) { if (directions.Count > 0) { ++x; // space between different directions } directions.Add(laneInfo.m_finalDirection); } ExtVehicleType[] possibleVehicleTypes; if (VehicleRestrictionsManager.Instance.IsRoadLane(laneInfo)) { possibleVehicleTypes = RoadVehicleTypes; } else if (VehicleRestrictionsManager.Instance.IsRailLane(laneInfo)) { possibleVehicleTypes = RailVehicleTypes; } else { ++x; continue; } ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Configured); uint y = 0; #if DEBUG_disabled_xxx Vector3 labelCenter = zero + f * (float)x * xu + f * (float)y * yu; // in game coordinates Vector3 labelScreenPos; bool visible = GeometryUtil.WorldToScreenPoint(labelCenter, out labelScreenPos); // BUGBUG: Using screen.height might be wrong, consider U.UIScaler.ScreenHeight (from UIView.fixedHeight) labelScreenPos.y = Screen.height - labelScreenPos.y; diff = labelCenter - camPos; var labelZoom = 1.0f / diff.magnitude * 100f; _counterStyle.fontSize = (int)(11f * labelZoom); _counterStyle.normal.textColor = new Color(1f, 1f, 0f); string labelStr = $"Idx {laneIndex}"; Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr)); Rect labelRect = new Rect(labelScreenPos.x - dim.x / 2f, labelScreenPos.y, dim.x, dim.y); GUI.Label(labelRect, labelStr, _counterStyle); ++y; #endif foreach (ExtVehicleType vehicleType in possibleVehicleTypes) { bool allowed = VehicleRestrictionsManager.Instance.IsAllowed(allowedTypes, vehicleType); if (allowed && viewOnly) { continue; // do not draw allowed vehicles in view-only mode } bool hoveredHandle = MainTool.DrawGenericSquareOverlayGridTexture( RoadUI.VehicleRestrictionTextures[vehicleType][allowed], camPos, zero, f, xu, yu, x, y, vehicleRestrictionsSignSize, !viewOnly); if (hoveredHandle) { hovered = true; renderData_.segmentId = segmentId; renderData_.laneId = laneId; renderData_.laneIndex = laneIndex; renderData_.laneInfo = laneInfo; renderData_.SortedLaneIndex = sortedLaneIndex; } if (hoveredHandle && MainTool.CheckClicked()) { // toggle vehicle restrictions // Log._Debug($"Setting vehicle restrictions of segment {segmentId}, lane // idx {laneIndex}, {vehicleType.ToString()} to {!allowed}"); VehicleRestrictionsManager.Instance.ToggleAllowedType( segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType, !allowed); stateUpdated = true; RefreshCurrentRestrictedSegmentIds(segmentId); if (RoadMode) { ApplyRestrictionsToAllSegments(sortedLaneIndex, vehicleType); } } ++y; } ++x; } guiColor.a = 1f; GUI.color = guiColor; return(hovered); }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { #if DEBUG //Log._Debug($"CustomCargoTruckAI.CustomStartPathFind called for vehicle {vehicleID}"); #endif #if BENCHMARK using (var bm = new Benchmark(null, "OnStartPathFind")) { #endif ExtVehicleType vehicleType = VehicleStateManager.Instance.OnStartPathFind(vehicleID, ref vehicleData, null); if (vehicleType == ExtVehicleType.None) { #if DEBUG Log.Warning($"CustomCargoTruck.CustomStartPathFind: Vehicle {vehicleID} does not have a valid vehicle type!"); #endif } #if BENCHMARK } #endif if ((vehicleData.m_flags & (Vehicle.Flags.TransferToSource | Vehicle.Flags.GoingBack)) != 0) { return(base.StartPathFind(vehicleID, ref vehicleData, startPos, endPos, startBothWays, endBothWays, undergroundTarget)); } bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; PathUnit.Position startPosA; PathUnit.Position startPosB; float startDistSqrA; float startDistSqrB; bool startPosFound = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, allowUnderground, false, 32f, out startPosA, out startPosB, out startDistSqrA, out startDistSqrB); PathUnit.Position startAltPosA; PathUnit.Position startAltPosB; float startAltDistSqrA; float startAltDistSqrB; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship, allowUnderground, false, 32f, out startAltPosA, out startAltPosB, out startAltDistSqrA, out startAltDistSqrB)) { if (!startPosFound || startAltDistSqrA < startDistSqrA) { startPosA = startAltPosA; startPosB = startAltPosB; startDistSqrA = startAltDistSqrA; startDistSqrB = startAltDistSqrB; } startPosFound = true; } PathUnit.Position endPosA; PathUnit.Position endPosB; float endDistSqrA; float endDistSqrB; bool endPosFound = CustomPathManager.FindPathPosition(endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, undergroundTarget, false, 32f, out endPosA, out endPosB, out endDistSqrA, out endDistSqrB); PathUnit.Position endAltPosA; PathUnit.Position endAltPosB; float endAltDistSqrA; float endAltDistSqrB; if (CustomPathManager.FindPathPosition(endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship, undergroundTarget, false, 32f, out endAltPosA, out endAltPosB, out endAltDistSqrA, out endAltDistSqrB)) { if (!endPosFound || endAltDistSqrA < endDistSqrA) { endPosA = endAltPosA; endPosB = endAltPosB; endDistSqrA = endAltDistSqrA; endDistSqrB = endAltDistSqrB; } endPosFound = true; } if (startPosFound && endPosFound) { CustomPathManager pathMan = CustomPathManager._instance; if (!startBothWays || startDistSqrA < 10f) { startPosB = default(PathUnit.Position); } if (!endBothWays || endDistSqrA < 10f) { endPosB = default(PathUnit.Position); } NetInfo.LaneType laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.CargoVehicle; VehicleInfo.VehicleType vehicleTypes = VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship; uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtCitizenInstance.ExtPathType.None; args.extVehicleType = ExtVehicleType.CargoVehicle; args.vehicleId = vehicleID; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default(PathUnit.Position); args.laneTypes = laneTypes; args.vehicleTypes = vehicleTypes; args.maxLength = 20000f; args.isHeavyVehicle = this.IsHeavyVehicle(); args.hasCombustionEngine = this.CombustionEngine(); args.ignoreBlocked = this.IgnoreBlocked(vehicleID, ref vehicleData); args.ignoreFlooded = false; args.ignoreCosts = false; args.randomParking = false; args.stablePath = false; args.skipQueue = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; if (pathMan.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { // NON-STOCK CODE END if (vehicleData.m_path != 0u) { pathMan.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
private void _guiVehicleRestrictionsWindow(int num) { if (GUILayout.Button(Translation.GetString("Invert"))) { // invert pattern NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes(SelectedSegmentId, ref Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId], null, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (LanePos laneData in sortedLanes) { uint laneId = laneData.laneId; byte laneIndex = laneData.laneIndex; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; ExtVehicleType baseMask = VehicleRestrictionsManager.Instance.GetBaseMask(laneInfo, VehicleRestrictionsMode.Configured); if (baseMask == ExtVehicleType.None) { continue; } ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Configured); allowedTypes = ~(allowedTypes & VehicleRestrictionsManager.EXT_VEHICLE_TYPES) & baseMask; VehicleRestrictionsManager.Instance.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, allowedTypes); } RefreshCurrentRestrictedSegmentIds(SelectedSegmentId); } GUILayout.BeginHorizontal(); if (GUILayout.Button(Translation.GetString("Allow_all_vehicles"))) { // allow all vehicle types NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes(SelectedSegmentId, ref Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId], null, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (LanePos laneData in sortedLanes) { uint laneId = laneData.laneId; byte laneIndex = laneData.laneIndex; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; ExtVehicleType baseMask = VehicleRestrictionsManager.Instance.GetBaseMask(laneInfo, VehicleRestrictionsMode.Configured); if (baseMask == ExtVehicleType.None) { continue; } VehicleRestrictionsManager.Instance.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, baseMask); } RefreshCurrentRestrictedSegmentIds(SelectedSegmentId); } if (GUILayout.Button(Translation.GetString("Ban_all_vehicles"))) { // ban all vehicle types NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes(SelectedSegmentId, ref Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId], null, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (LanePos laneData in sortedLanes) { uint laneId = laneData.laneId; byte laneIndex = laneData.laneIndex; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; ExtVehicleType baseMask = VehicleRestrictionsManager.Instance.GetBaseMask(laneInfo, VehicleRestrictionsMode.Configured); if (baseMask == ExtVehicleType.None) { continue; } VehicleRestrictionsManager.Instance.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, ~VehicleRestrictionsManager.EXT_VEHICLE_TYPES & baseMask); } RefreshCurrentRestrictedSegmentIds(SelectedSegmentId); } GUILayout.EndHorizontal(); if (GUILayout.Button(Translation.GetString("Apply_vehicle_restrictions_to_all_road_segments_between_two_junctions"))) { ApplyRestrictionsToAllSegments(); } DragWindow(ref windowRect); }
public static void setLaneAllowedVehicleTypes(uint laneId, ExtVehicleType vehicleTypes) { if (laneId <= 0) return; if (((NetLane.Flags)Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_flags & NetLane.Flags.Created) == NetLane.Flags.None) return; ushort segmentId = Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_segment; if (segmentId <= 0) return; if ((Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) return; NetInfo segmentInfo = Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].Info; uint curLaneId = Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].m_lanes; uint laneIndex = 0; while (laneIndex < segmentInfo.m_lanes.Length && curLaneId != 0u) { if (curLaneId == laneId) { setLaneAllowedVehicleTypes(segmentId, laneIndex, laneId, vehicleTypes); return; } laneIndex++; curLaneId = Singleton<NetManager>.instance.m_lanes.m_buffer[curLaneId].m_nextLane; } }
private bool drawVehicleRestrictionHandles(ushort segmentId, ref NetSegment segment, bool viewOnly, out bool stateUpdated) { stateUpdated = false; if (viewOnly && !Options.vehicleRestrictionsOverlay && MainTool.GetToolMode() != ToolMode.VehicleRestrictions) { return(false); } Vector3 center = segment.m_bounds.center; var screenPos = Camera.main.WorldToScreenPoint(center); screenPos.y = Screen.height - screenPos.y; if (screenPos.z < 0) { return(false); } var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = center - camPos; if (diff.magnitude > TrafficManagerTool.MaxOverlayDistance) { return(false); // do not draw if too distant } int numDirections; int numLanes = TrafficManagerTool.GetSegmentNumVehicleLanes(segmentId, null, out numDirections, VehicleRestrictionsManager.VEHICLE_TYPES); // draw vehicle restrictions over each lane NetInfo segmentInfo = segment.Info; Vector3 yu = (segment.m_endDirection - segment.m_startDirection).normalized; /*if ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) * yu = -yu;*/ Vector3 xu = Vector3.Cross(yu, new Vector3(0, 1f, 0)).normalized; float f = viewOnly ? 4f : 7f; // reserved sign size in game coordinates int maxNumSigns = 0; if (VehicleRestrictionsManager.Instance.IsRoadSegment(segmentInfo)) { maxNumSigns = roadVehicleTypes.Length; } else if (VehicleRestrictionsManager.Instance.IsRailSegment(segmentInfo)) { maxNumSigns = railVehicleTypes.Length; } //Vector3 zero = center - 0.5f * (float)(numLanes + numDirections - 1) * f * (xu + yu); // "bottom left" Vector3 zero = center - 0.5f * (float)(numLanes - 1 + numDirections - 1) * f * xu - 0.5f * (float)maxNumSigns * f * yu; // "bottom left" /*if (!viewOnly) * Log._Debug($"xu: {xu.ToString()} yu: {yu.ToString()} center: {center.ToString()} zero: {zero.ToString()} numLanes: {numLanes} numDirections: {numDirections}");*/ uint x = 0; var guiColor = GUI.color; IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes(segmentId, ref segment, null, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES); bool hovered = false; HashSet <NetInfo.Direction> directions = new HashSet <NetInfo.Direction>(); int sortedLaneIndex = -1; foreach (LanePos laneData in sortedLanes) { ++sortedLaneIndex; uint laneId = laneData.laneId; byte laneIndex = laneData.laneIndex; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if (!directions.Contains(laneInfo.m_finalDirection)) { if (directions.Count > 0) { ++x; // space between different directions } directions.Add(laneInfo.m_finalDirection); } ExtVehicleType[] possibleVehicleTypes = null; if (VehicleRestrictionsManager.Instance.IsRoadLane(laneInfo)) { possibleVehicleTypes = roadVehicleTypes; } else if (VehicleRestrictionsManager.Instance.IsRailLane(laneInfo)) { possibleVehicleTypes = railVehicleTypes; } else { ++x; continue; } ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Configured); uint y = 0; #if DEBUGx Vector3 labelCenter = zero + f * (float)x * xu + f * (float)y * yu; // in game coordinates var labelScreenPos = Camera.main.WorldToScreenPoint(labelCenter); labelScreenPos.y = Screen.height - labelScreenPos.y; diff = labelCenter - camPos; var labelZoom = 1.0f / diff.magnitude * 100f; _counterStyle.fontSize = (int)(11f * labelZoom); _counterStyle.normal.textColor = new Color(1f, 1f, 0f); string labelStr = $"Idx {laneIndex}"; Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr)); Rect labelRect = new Rect(labelScreenPos.x - dim.x / 2f, labelScreenPos.y, dim.x, dim.y); GUI.Label(labelRect, labelStr, _counterStyle); ++y; #endif foreach (ExtVehicleType vehicleType in possibleVehicleTypes) { bool allowed = VehicleRestrictionsManager.Instance.IsAllowed(allowedTypes, vehicleType); if (allowed && viewOnly) { continue; // do not draw allowed vehicles in view-only mode } bool hoveredHandle = MainTool.DrawGenericSquareOverlayGridTexture(TextureResources.VehicleRestrictionTextures[vehicleType][allowed], ref camPos, ref zero, f, ref xu, ref yu, x, y, vehicleRestrictionsSignSize, !viewOnly, 0.5f, 0.8f); if (hoveredHandle) { hovered = true; } if (hoveredHandle && MainTool.CheckClicked()) { // toggle vehicle restrictions //Log._Debug($"Setting vehicle restrictions of segment {segmentId}, lane idx {laneIndex}, {vehicleType.ToString()} to {!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)) { ApplyRestrictionsToAllSegments(sortedLaneIndex); } } ++y; } ++x; } guiColor.a = 1f; GUI.color = guiColor; return(hovered); }
internal void housekeeping(bool mayDelete, RoadBaseAI.TrafficLightState mainState = RoadBaseAI.TrafficLightState.Red, RoadBaseAI.TrafficLightState leftState = RoadBaseAI.TrafficLightState.Red, RoadBaseAI.TrafficLightState rightState = RoadBaseAI.TrafficLightState.Red, RoadBaseAI.TrafficLightState pedState = RoadBaseAI.TrafficLightState.Red) { // we intentionally never delete vehicle types (because we may want to retain traffic light states if a segment is upgraded or replaced) HashSet<ExtVehicleType> setupLights = new HashSet<ExtVehicleType>(); HashSet<ExtVehicleType> allAllowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypesAsSet(segmentId, nodeId); ExtVehicleType allAllowedMask = VehicleRestrictionsManager.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())}"); #endif bool addPedestrianLight = false; uint numLights = 0; foreach (ExtVehicleType allowedTypes in allAllowedTypes) { foreach (ExtVehicleType mask in singleLaneVehicleTypes) { if (setupLights.Contains(mask)) continue; if ((allowedTypes & mask) != ExtVehicleType.None && (allowedTypes & ~(mask | ExtVehicleType.Emergency)) == ExtVehicleType.None) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: adding {mask} light"); #endif if (!CustomLights.ContainsKey(mask)) { CustomLights.Add(mask, new TrafficLight.CustomSegmentLight(this, nodeId, segmentId, mainState, leftState, rightState)); VehicleTypes.AddFirst(mask); } ++numLights; addPedestrianLight = true; autoPedestrianVehicleType = mask; mainSegmentLight = CustomLights[mask]; setupLights.Add(mask); SeparateVehicleTypes |= mask; break; } } } if (allAllowedTypes.Count > numLights) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: adding main vehicle light: {mainVehicleType}"); #endif // traffic lights for cars if (!CustomLights.ContainsKey(mainVehicleType)) { CustomLights.Add(mainVehicleType, new TrafficLight.CustomSegmentLight(this, nodeId, segmentId, mainState, leftState, rightState)); VehicleTypes.AddFirst(mainVehicleType); } autoPedestrianVehicleType = mainVehicleType; mainSegmentLight = CustomLights[mainVehicleType]; addPedestrianLight = allAllowedMask == ExtVehicleType.None || (allAllowedMask & ~ExtVehicleType.RailVehicle) != ExtVehicleType.None; } else { addPedestrianLight = true; } #if DEBUGHK if (addPedestrianLight) { Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: adding ped. light"); } #endif if (mayDelete) { // delete traffic lights for non-existing configurations HashSet<ExtVehicleType> vehicleTypesToDelete = new HashSet<ExtVehicleType>(); foreach (KeyValuePair<ExtVehicleType, CustomSegmentLight> e in CustomLights) { if (e.Key == mainVehicleType) continue; if (!setupLights.Contains(e.Key)) vehicleTypesToDelete.Add(e.Key); } foreach (ExtVehicleType vehicleType in vehicleTypesToDelete) { #if DEBUGHK Log._Debug($"Deleting traffic light for {vehicleType} at segment {segmentId}, node {nodeId}"); #endif CustomLights.Remove(vehicleType); VehicleTypes.Remove(vehicleType); } } if (CustomLights.ContainsKey(mainVehicleType) && VehicleTypes.First.Value != mainVehicleType) { VehicleTypes.Remove(mainVehicleType); VehicleTypes.AddFirst(mainVehicleType); } if (addPedestrianLight) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: adding pedestrian light"); #endif if (pedestrianLightState == null) pedestrianLightState = pedState; } else { pedestrianLightState = null; } }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { #if DEBUG //Log._Debug($"CustomFireTruckAI.CustomStartPathFind called for vehicle {vehicleID}"); #endif ExtVehicleType vehicleType = ExtVehicleType.None; #if BENCHMARK using (var bm = new Benchmark(null, "OnStartPathFind")) { #endif vehicleType = VehicleStateManager.Instance.OnStartPathFind(vehicleID, ref vehicleData, (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0 ? ExtVehicleType.Emergency : ExtVehicleType.Service); #if BENCHMARK } #endif VehicleInfo info = this.m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; PathUnit.Position startPosA; PathUnit.Position startPosB; float startDistSqrA; float startDistSqrB; PathUnit.Position endPosA; PathUnit.Position endPosB; float endDistSqrA; float endDistSqrB; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out startDistSqrA, out startDistSqrB) && CustomPathManager.FindPathPosition(endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, undergroundTarget, false, 32f, out endPosA, out endPosB, out endDistSqrA, out endDistSqrB)) { if (!startBothWays || startDistSqrA < 10f) { startPosB = default(PathUnit.Position); } if (!endBothWays || endDistSqrA < 10f) { endPosB = default(PathUnit.Position); } uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtCitizenInstance.ExtPathType.None; args.extVehicleType = vehicleType; args.vehicleId = vehicleID; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default(PathUnit.Position); args.laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle; args.vehicleTypes = info.m_vehicleType; args.maxLength = 20000f; args.isHeavyVehicle = this.IsHeavyVehicle(); args.hasCombustionEngine = this.CombustionEngine(); args.ignoreBlocked = this.IgnoreBlocked(vehicleID, ref vehicleData); args.ignoreFlooded = false; args.randomParking = false; args.stablePath = false; args.skipQueue = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; if (CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { // NON-STOCK CODE END if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } else { PathfindFailure(vehicleID, ref vehicleData); } return(false); }
public static bool CustomStartPathFind(ushort segmentId, ref NetSegment data, ItemClass.Service netService, ItemClass.Service netService2, VehicleInfo.VehicleType vehicleType, bool skipQueue) { if (data.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(data.m_path); data.m_path = 0u; } NetManager netManager = Singleton <NetManager> .instance; if ((netManager.m_nodes.m_buffer[data.m_startNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None) { for (int i = 0; i < 8; i++) { ushort segment = netManager.m_nodes.m_buffer[data.m_startNode].GetSegment(i); if (segment != 0 && segment != segmentId && netManager.m_segments.m_buffer[segment].m_path != 0u) { return(true); } } } if ((netManager.m_nodes.m_buffer[data.m_endNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None) { for (int j = 0; j < 8; j++) { ushort segment2 = netManager.m_nodes.m_buffer[data.m_endNode].GetSegment(j); if (segment2 != 0 && segment2 != segmentId && netManager.m_segments.m_buffer[segment2].m_path != 0u) { return(true); } } } Vector3 position = netManager.m_nodes.m_buffer[data.m_startNode].m_position; Vector3 position2 = netManager.m_nodes.m_buffer[data.m_endNode].m_position; #if DEBUG bool logPathfind = DebugSwitch.TransportLinePathfind.Get(); ushort logStartNode = data.m_startNode; ushort logEndNode = data.m_endNode; Log._DebugIf( logPathfind, () => $"TransportLineAI.CustomStartPathFind({segmentId}, ..., {netService}, " + $"{netService2}, {vehicleType}, {skipQueue}): " + $"startNode={logStartNode} @ {position}, " + $"endNode={logEndNode} @ {position2} -- " + $"line: {netManager.m_nodes.m_buffer[logStartNode].m_transportLine}" + $"/{netManager.m_nodes.m_buffer[logEndNode].m_transportLine}"); #else var logPathfind = false; #endif if (!PathManager.FindPathPosition( position, netService, netService2, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, vehicleType, true, false, 32f, out PathUnit.Position startPosA, out PathUnit.Position startPosB, out _, out _)) { CheckSegmentProblems(segmentId, ref data); return(true); } if (!PathManager.FindPathPosition( position2, netService, netService2, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, vehicleType, true, false, 32f, out PathUnit.Position endPosA, out PathUnit.Position endPosB, out _, out _)) { CheckSegmentProblems(segmentId, ref data); return(true); } if ((netManager.m_nodes.m_buffer[data.m_startNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None) { startPosB = default; } if ((netManager.m_nodes.m_buffer[data.m_endNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None) { endPosB = default; } if (vehicleType != VehicleInfo.VehicleType.None) { startPosA.m_offset = 128; startPosB.m_offset = 128; endPosA.m_offset = 128; endPosB.m_offset = 128; } else { startPosA.m_offset = (byte)Mathf.Clamp(startPosA.m_offset, 1, 254); startPosB.m_offset = (byte)Mathf.Clamp(startPosB.m_offset, 1, 254); endPosA.m_offset = (byte)Mathf.Clamp(endPosA.m_offset, 1, 254); endPosB.m_offset = (byte)Mathf.Clamp(endPosB.m_offset, 1, 254); } bool stopLane = GetStopLane(ref startPosA, vehicleType); bool stopLane2 = GetStopLane(ref startPosB, vehicleType); bool stopLane3 = GetStopLane(ref endPosA, vehicleType); bool stopLane4 = GetStopLane(ref endPosB, vehicleType); if ((!stopLane && !stopLane2) || (!stopLane3 && !stopLane4)) { CheckSegmentProblems(segmentId, ref data); return(true); } ExtVehicleType extVehicleType = ExtVehicleType.None; if ((vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Bus; } if ((vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro | VehicleInfo.VehicleType.Monorail)) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.PassengerTrain; } if ((vehicleType & VehicleInfo.VehicleType.Tram) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Tram; } if ((vehicleType & VehicleInfo.VehicleType.Ship) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.PassengerShip; } if ((vehicleType & VehicleInfo.VehicleType.Plane) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.PassengerPlane; } if ((vehicleType & VehicleInfo.VehicleType.Ferry) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Ferry; } if ((vehicleType & VehicleInfo.VehicleType.Blimp) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Blimp; } if ((vehicleType & VehicleInfo.VehicleType.CableCar) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.CableCar; } if ((vehicleType & VehicleInfo.VehicleType.Trolleybus) != VehicleInfo.VehicleType.None) { extVehicleType = ExtVehicleType.Trolleybus; } // Log._Debug($"Transport line. extVehicleType={extVehicleType}"); // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtPathType.None; args.extVehicleType = extVehicleType; args.vehicleId = 0; args.spawned = true; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default; args.vehicleTypes = vehicleType; args.isHeavyVehicle = false; args.hasCombustionEngine = false; args.ignoreBlocked = true; args.ignoreFlooded = false; args.ignoreCosts = false; args.randomParking = false; args.stablePath = true; args.skipQueue = skipQueue; if (vehicleType == VehicleInfo.VehicleType.None) { args.laneTypes = NetInfo.LaneType.Pedestrian; args.maxLength = 160000f; } else { args.laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle; args.maxLength = 20000f; } if (CustomPathManager._instance.CustomCreatePath( out uint path, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { // NON-STOCK CODE END if (startPosA.m_segment != 0 && startPosB.m_segment != 0) { netManager.m_nodes.m_buffer[data.m_startNode].m_flags |= NetNode.Flags.Ambiguous; } else { netManager.m_nodes.m_buffer[data.m_startNode].m_flags &= ~NetNode.Flags.Ambiguous; } if (endPosA.m_segment != 0 && endPosB.m_segment != 0) { netManager.m_nodes.m_buffer[data.m_endNode].m_flags |= NetNode.Flags.Ambiguous; } else { netManager.m_nodes.m_buffer[data.m_endNode].m_flags &= ~NetNode.Flags.Ambiguous; } data.m_path = path; data.m_flags |= NetSegment.Flags.WaitingPath; Log._DebugIf( logPathfind, () => $"TransportLineAI.CustomStartPathFind({segmentId}, ..., {netService}, " + $"{netService2}, {vehicleType}, {skipQueue}): Started calculating " + $"path {path} for extVehicleType={extVehicleType}, " + $"startPosA=[seg={startPosA.m_segment}, lane={startPosA.m_lane}, " + $"off={startPosA.m_offset}], startPosB=[seg={startPosB.m_segment}, " + $"lane={startPosB.m_lane}, off={startPosB.m_offset}], " + $"endPosA=[seg={endPosA.m_segment}, lane={endPosA.m_lane}, " + $"off={endPosA.m_offset}], endPosB=[seg={endPosB.m_segment}, " + $"lane={endPosB.m_lane}, off={endPosB.m_offset}]"); return(false); } CheckSegmentProblems(segmentId, ref data); return(true); }
public bool ExtStartPathFind(ushort instanceID, ref CitizenInstance citizenData, ref ExtCitizenInstance extInstance, Vector3 startPos, Vector3 endPos, VehicleInfo vehicleInfo) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log.Warning($"CustomCitizenAI.ExtStartPathFind({instanceID}): called for citizen instance {instanceID}, citizen {citizenData.m_citizen}, startPos={startPos}, endPos={endPos}, sourceBuilding={citizenData.m_sourceBuilding}, targetBuilding={citizenData.m_targetBuilding}, pathMode={extInstance.pathMode}"); } #endif // NON-STOCK CODE START ExtVehicleType extVehicleType = ExtVehicleType.None; ushort parkedVehicleId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenData.m_citizen].m_parkedVehicle; //bool mayUseOwnPassengerCar = true; // allowed to use a passenger car? bool canUseOwnPassengerCar = false; // allowed to use a passenger car AND given vehicle type is a passenger car? CarUsagePolicy carUsageMode = CarUsagePolicy.Allowed; //bool forceUseCar = false; if (Options.prohibitPocketCars) { switch (extInstance.pathMode) { case ExtPathMode.RequiresWalkingPathToParkedCar: case ExtPathMode.CalculatingWalkingPathToParkedCar: case ExtPathMode.WalkingToParkedCar: case ExtPathMode.ApproachingParkedCar: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} has CurrentPathMode={extInstance.pathMode}. Switching to 'CalculatingWalkingPathToParkedCar'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToParkedCar; break; case ExtPathMode.RequiresWalkingPathToTarget: case ExtPathMode.CalculatingWalkingPathToTarget: case ExtPathMode.WalkingToTarget: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToTarget'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; break; case ExtPathMode.RequiresCarPath: case ExtPathMode.DrivingToTarget: case ExtPathMode.DrivingToKnownParkPos: case ExtPathMode.DrivingToAltParkPos: case ExtPathMode.CalculatingCarPathToAltParkPos: case ExtPathMode.CalculatingCarPathToKnownParkPos: case ExtPathMode.CalculatingCarPathToTarget: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} has CurrentPathMode={extInstance.pathMode}. Change to 'RequiresCarPath'."); } #endif extInstance.pathMode = ExtPathMode.RequiresCarPath; break; default: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} has CurrentPathMode={extInstance.pathMode}. Change to 'None'."); } #endif extInstance.Reset(); break; } // pathMode is now either CalculatingWalkingPathToParkedCar, CalculatingWalkingPathToTarget, RequiresCarPath or None. if (extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToParkedCar || extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToTarget) { // vehicle must not be used since we need a walking path vehicleInfo = null; carUsageMode = CarUsagePolicy.Forbidden; if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar) { // check if parked car is present if (parkedVehicleId == 0) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} should go to parked car (CurrentPathMode={extInstance.pathMode}) but parked vehicle could not be found. Setting CurrentPathMode='CalculatingWalkingPathToTarget'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; } else { endPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; #if DEBUG if (GlobalConfig.Instance.Debug.Switches[4]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} shall go to parked vehicle @ {endPos}"); } #endif } } } else if (parkedVehicleId != 0) { // reuse parked vehicle info vehicleInfo = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].Info; carUsageMode = CarUsagePolicy.Allowed; ushort homeId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenData.m_citizen].m_homeBuilding; if (homeId != 0 && citizenData.m_targetBuilding == homeId) { // check distance between home and parked car. if too far away: force to take the car back home float distHomeToParked = (Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position - Singleton <BuildingManager> .instance.m_buildings.m_buffer[homeId].m_position).magnitude; if (distHomeToParked > GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToHome) { // force to take car back home #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} will try to move parkedVehicleId={parkedVehicleId} towards home. distHomeToParked={distHomeToParked}"); } #endif carUsageMode = CarUsagePolicy.Forced; } } } else { carUsageMode = CarUsagePolicy.Allowed; } } /*if (Options.parkingRestrictionsEnabled && carUsageMode == CarUsagePolicy.Allowed && parkedVehicleId != 0) { * // force removal of illegaly parked vehicle * PathUnit.Position parkedPathPos; * if (PathManager.FindPathPosition(Singleton<VehicleManager>.instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position, ItemClass.Service.Road, NetInfo.LaneType.Parking, VehicleInfo.VehicleType.Car, false, false, 32f, out parkedPathPos)) { * if (! ParkingRestrictionsManager.Instance.IsParkingAllowed(parkedPathPos.m_segment, Singleton<NetManager>.instance.m_segments.m_buffer[parkedPathPos.m_segment].Info.m_lanes[parkedPathPos.m_lane].m_finalDirection)) { * carUsageMode = CarUsagePolicy.Forced; * vehicleInfo = Singleton<VehicleManager>.instance.m_parkedVehicles.m_buffer[parkedVehicleId].Info; * } * } * }*/ // NON-STOCK CODE END NetInfo.LaneType laneTypes = NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleType = VehicleInfo.VehicleType.None; bool randomParking = false; if (vehicleInfo != null) { if (vehicleInfo.m_class.m_subService == ItemClass.SubService.PublicTransportTaxi) { if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTaxi) == CitizenInstance.Flags.None && Singleton <DistrictManager> .instance.m_districts.m_buffer[0].m_productionData.m_finalTaxiCapacity != 0u) { SimulationManager instance = Singleton <SimulationManager> .instance; if (instance.m_isNightTime || instance.m_randomizer.Int32(2u) == 0) { laneTypes |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); vehicleType |= vehicleInfo.m_vehicleType; extVehicleType = ExtVehicleType.Taxi; // NON-STOCK CODE // NON-STOCK CODE START if (Options.prohibitPocketCars) { extInstance.pathMode = ExtPathMode.TaxiToTarget; } // NON-STOCK CODE END } } } else { // NON-STOCK CODE START if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Car) { if (carUsageMode == CarUsagePolicy.Allowed || carUsageMode == CarUsagePolicy.Forced) { extVehicleType = ExtVehicleType.PassengerCar; laneTypes |= NetInfo.LaneType.Vehicle; vehicleType |= vehicleInfo.m_vehicleType; canUseOwnPassengerCar = true; } } else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { extVehicleType = ExtVehicleType.Bicycle; laneTypes |= NetInfo.LaneType.Vehicle; vehicleType |= vehicleInfo.m_vehicleType; if (citizenData.m_targetBuilding != 0 && Singleton <BuildingManager> .instance.m_buildings.m_buffer[citizenData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office) { randomParking = true; } } // NON-STOCK CODE END } } NetInfo.LaneType startLaneType = laneTypes; PathUnit.Position vehiclePosition = default(PathUnit.Position); // NON-STOCK CODE START if (Options.prohibitPocketCars) { if (carUsageMode == CarUsagePolicy.Forced && !canUseOwnPassengerCar) { carUsageMode = CarUsagePolicy.Forbidden; } } PathUnit.Position endPosA = default(PathUnit.Position); bool calculateEndPos = true; bool allowRandomParking = true; if (Options.prohibitPocketCars) { // Parking AI if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.RequiresCarPath) { if (canUseOwnPassengerCar) { ushort homeId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenData.m_citizen].m_homeBuilding; startLaneType &= ~NetInfo.LaneType.Pedestrian; // force to use the car from the beginning startPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; // force to start from the parked car #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Setting startLaneType={startLaneType}, startPos={startPos} for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode}"); } #endif if (citizenData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[citizenData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) { // the citizen is starting their journey and the target is not an outside connection: find a suitable parking space near the target #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding parking space at target for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode} parkedVehicleId={parkedVehicleId}"); } #endif // find a parking space in the vicinity of the target bool calcEndPos; Vector3 parkPos; if (AdvancedParkingManager.Instance.FindParkingSpaceForCitizen(endPos, vehicleInfo, ref extInstance, homeId, citizenData.m_targetBuilding == homeId, 0, false, out parkPos, ref endPosA, out calcEndPos) && extInstance.CalculateReturnPath(parkPos, endPos)) { // success extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToKnownParkPos; calculateEndPos = calcEndPos; // if true, the end path position still needs to be calculated allowRandomParking = false; // find a direct path to the calculated parking position #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding known parking space for citizen instance {instanceID}, parked vehicle {parkedVehicleId} succeeded and return path {extInstance.returnPathId} ({extInstance.returnPathState}) is calculating. PathMode={extInstance.pathMode}"); } #endif /*if (! extInstance.CalculateReturnPath(parkPos, endPos)) { * // TODO retry? * if (GlobalConfig.Instance.Debug.Switches[2]) * Log._Debug($"CustomCitizenAI.CustomStartPathFind: [PFFAIL] Could not calculate return path for citizen instance {instanceID}, parked vehicle {parkedVehicleId}. Calling OnPathFindFailed."); * CustomHumanAI.OnPathFindFailure(extInstance); * return false; * }*/ } } if (extInstance.pathMode == ExtPathMode.RequiresCarPath) { // no known parking space found. calculate direct path to target #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} is still at CurrentPathMode={extInstance.pathMode} (no parking space found?). Setting it to CalculatingCarPath. parkedVehicleId={parkedVehicleId}"); } #endif extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToTarget; } } else if (extInstance.pathMode == ExtPathMode.RequiresCarPath) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} requires car path but no parked car present. Citizen will need to walk to target."); } #endif extInstance.Reset(); } } } if (canUseOwnPassengerCar) { if (allowRandomParking && citizenData.m_targetBuilding != 0 && Singleton <BuildingManager> .instance.m_buildings.m_buffer[citizenData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office) { randomParking = true; } } // determine path type ExtPathType extPathType = ExtPathType.None; if (Options.prohibitPocketCars) { extPathType = extInstance.GetPathType(); } // NON-STOCK CODE END if (parkedVehicleId != 0 && canUseOwnPassengerCar) { Vector3 position = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; CustomPathManager.FindPathPosition(position, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out vehiclePosition); } bool allowUnderground = (citizenData.m_flags & (CitizenInstance.Flags.Underground | CitizenInstance.Flags.Transition)) != CitizenInstance.Flags.None; #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Requesting path-finding for citizen instance {instanceID}, citizen {citizenData.m_citizen}, extVehicleType={extVehicleType}, extPathType={extPathType}, startPos={startPos}, endPos={endPos}, sourceBuilding={citizenData.m_sourceBuilding}, targetBuilding={citizenData.m_targetBuilding} pathMode={extInstance.pathMode}"); } #endif bool foundEndPos = !calculateEndPos || FindPathPosition(instanceID, ref citizenData, endPos, Options.prohibitPocketCars && (citizenData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[citizenData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) ? NetInfo.LaneType.Pedestrian : (laneTypes | NetInfo.LaneType.Pedestrian), vehicleType, false, out endPosA); // NON-STOCK CODE: with Parking AI enabled, the end position must be a pedestrian position bool foundStartPos = false; PathUnit.Position startPosA; if (Options.prohibitPocketCars && (extInstance.pathMode == ExtPathMode.CalculatingCarPathToTarget || extInstance.pathMode == ExtPathMode.CalculatingCarPathToKnownParkPos)) { foundStartPos = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, laneTypes & ~NetInfo.LaneType.Pedestrian, vehicleType, allowUnderground, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out startPosA); } else { foundStartPos = FindPathPosition(instanceID, ref citizenData, startPos, startLaneType, vehicleType, allowUnderground, out startPosA); } if (foundStartPos && // TODO probably fails if vehicle is parked too far away from road foundEndPos // NON-STOCK CODE ) { bool canUseTransport = (citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None; if (canUseTransport) { if (carUsageMode != CarUsagePolicy.Forced) // NON-STOCK CODE { laneTypes |= NetInfo.LaneType.PublicTransport; CitizenManager citizenManager = Singleton <CitizenManager> .instance; uint citizenId = citizenManager.m_instances.m_buffer[instanceID].m_citizen; if (citizenId != 0u && (citizenManager.m_citizens.m_buffer[citizenId].m_flags & Citizen.Flags.Evacuating) != Citizen.Flags.None) { laneTypes |= NetInfo.LaneType.EvacuationTransport; } } } else if (Options.prohibitPocketCars) // TODO check for incoming connection // cim tried to use public transport but waiting time was too long { if (citizenData.m_sourceBuilding != 0) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} cannot uses public transport from building {citizenData.m_sourceBuilding} to {citizenData.m_targetBuilding}. Incrementing public transport demand."); } #endif ExtBuildingManager.Instance.ExtBuildings[citizenData.m_sourceBuilding].AddPublicTransportDemand((uint)GlobalConfig.Instance.ParkingAI.PublicTransportDemandWaitingIncrement, true); } } PathUnit.Position dummyPathPos = default(PathUnit.Position); uint path; bool res = CustomPathManager._instance.CreatePath(extVehicleType, 0, extPathType, out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, startPosA, dummyPathPos, endPosA, dummyPathPos, vehiclePosition, laneTypes, vehicleType, 20000f, false, false, false, false, randomParking, false); if (res) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Path-finding starts for citizen instance {instanceID}, path={path}, extVehicleType={extVehicleType}, startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, laneType={laneTypes}, vehicleType={vehicleType}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, vehiclePos.m_segment={vehiclePosition.m_segment}, vehiclePos.m_lane={vehiclePosition.m_lane}, vehiclePos.m_offset={vehiclePosition.m_offset}"); } #endif if (citizenData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(citizenData.m_path); } citizenData.m_path = path; citizenData.m_flags |= CitizenInstance.Flags.WaitingPath; return(true); } } #if DEBUG if (Options.prohibitPocketCars) { if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): CustomCitizenAI.CustomStartPathFind: [PFFAIL] failed for citizen instance {instanceID} (CurrentPathMode={extInstance.pathMode}). startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, startPosA.offset={startPosA.m_offset}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, endPosA.offset={endPosA.m_offset}, foundStartPos={foundStartPos}, foundEndPos={foundEndPos}"); } } #endif return(false); }
internal void ChangeLightMode(ushort segmentId, ExtVehicleType vehicleType, CustomSegmentLight.Mode mode) { foreach (TimedTrafficLightsStep step in Steps) { step.ChangeLightMode(segmentId, vehicleType, mode); } }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log.Warning($"CustomCarAI.CustomStartPathFind({vehicleID}): called for vehicle {vehicleID}, startPos={startPos}, endPos={endPos}, startBothWays={startBothWays}, endBothWays={endBothWays}, undergroundTarget={undergroundTarget}"); } #endif ExtVehicleType vehicleType = ExtVehicleType.None; #if BENCHMARK using (var bm = new Benchmark(null, "OnStartPathFind")) { #endif vehicleType = VehicleStateManager.Instance.OnStartPathFind(vehicleID, ref vehicleData, null); if (vehicleType == ExtVehicleType.None) { #if DEBUG Log.Warning($"CustomCarAI.CustomStartPathFind({vehicleID}): Vehicle {vehicleID} does not have a valid vehicle type!"); #endif vehicleType = ExtVehicleType.RoadVehicle; } #if BENCHMARK } #endif VehicleInfo info = this.m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; PathUnit.Position startPosA; PathUnit.Position startPosB; float startDistSqrA; float startDistSqrB; PathUnit.Position endPosA; PathUnit.Position endPosB; float endDistSqrA; float endDistSqrB; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out startDistSqrA, out startDistSqrB) && CustomPathManager.FindPathPosition(endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, undergroundTarget, false, 32f, out endPosA, out endPosB, out endDistSqrA, out endDistSqrB)) { if (!startBothWays || startDistSqrA < 10f) { startPosB = default(PathUnit.Position); } if (!endBothWays || endDistSqrA < 10f) { endPosB = default(PathUnit.Position); } uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtCitizenInstance.ExtPathType.None; args.extVehicleType = vehicleType; args.vehicleId = vehicleID; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default(PathUnit.Position); args.laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle; args.vehicleTypes = info.m_vehicleType; args.maxLength = 20000f; args.isHeavyVehicle = this.IsHeavyVehicle(); args.hasCombustionEngine = this.CombustionEngine(); args.ignoreBlocked = this.IgnoreBlocked(vehicleID, ref vehicleData); args.ignoreFlooded = false; args.randomParking = false; args.stablePath = false; args.skipQueue = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; if (CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomCarAI.CustomStartPathFind({vehicleID}): Path-finding starts for vehicle {vehicleID}, path={path}, extVehicleType={vehicleType}, startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, info.m_vehicleType={info.m_vehicleType}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}"); } #endif // NON-STOCK CODE END if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
/// <summary> /// Sets the allowed vehicle types for the given segment and lane. /// </summary> /// <param name="segmentId"></param> /// <param name="laneIndex"></param> /// <param name="laneId"></param> /// <param name="allowedTypes"></param> /// <returns></returns> internal static bool SetAllowedVehicleTypes(ushort segmentId, uint laneIndex, uint laneId, ExtVehicleType allowedTypes) { if (segmentId == 0) return false; if ((Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) return false; if (((NetLane.Flags)Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_flags & NetLane.Flags.Created) == NetLane.Flags.None) return false; Flags.setLaneAllowedVehicleTypes(segmentId, laneIndex, laneId, allowedTypes); return true; }
public bool ExtStartPathFind(ushort instanceID, ref CitizenInstance instanceData, ref ExtCitizenInstance extInstance, ref ExtCitizen extCitizen, Vector3 startPos, Vector3 endPos, VehicleInfo vehicleInfo, bool enableTransport, bool ignoreCost) { #if DEBUG bool citDebug = (GlobalConfig.Instance.Debug.CitizenInstanceId == 0 || GlobalConfig.Instance.Debug.CitizenInstanceId == instanceID) && (GlobalConfig.Instance.Debug.CitizenId == 0 || GlobalConfig.Instance.Debug.CitizenId == instanceData.m_citizen) && (GlobalConfig.Instance.Debug.SourceBuildingId == 0 || GlobalConfig.Instance.Debug.SourceBuildingId == instanceData.m_sourceBuilding) && (GlobalConfig.Instance.Debug.TargetBuildingId == 0 || GlobalConfig.Instance.Debug.TargetBuildingId == instanceData.m_targetBuilding) ; bool debug = GlobalConfig.Instance.Debug.Switches[2] && citDebug; bool fineDebug = GlobalConfig.Instance.Debug.Switches[4] && citDebug; if (debug) { Log.Warning($"CustomCitizenAI.ExtStartPathFind({instanceID}): called for citizen {instanceData.m_citizen}, startPos={startPos}, endPos={endPos}, sourceBuilding={instanceData.m_sourceBuilding}, targetBuilding={instanceData.m_targetBuilding}, pathMode={extInstance.pathMode}, enableTransport={enableTransport}, ignoreCost={ignoreCost}"); } #endif // NON-STOCK CODE START CitizenManager citizenManager = Singleton <CitizenManager> .instance; ushort parkedVehicleId = citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_parkedVehicle; ushort homeId = citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_homeBuilding; CarUsagePolicy carUsageMode = CarUsagePolicy.Allowed; #if BENCHMARK using (var bm = new Benchmark(null, "ParkingAI.Preparation")) { #endif bool startsAtOutsideConnection = false; if (Options.prohibitPocketCars) { switch (extInstance.pathMode) { case ExtPathMode.RequiresWalkingPathToParkedCar: case ExtPathMode.CalculatingWalkingPathToParkedCar: case ExtPathMode.WalkingToParkedCar: case ExtPathMode.ApproachingParkedCar: if (parkedVehicleId == 0) { /* * Parked vehicle not present but citizen wants to reach it * -> Reset path mode */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode} but no parked vehicle present. Change to 'None'."); } #endif extInstance.Reset(); } else { /* * Parked vehicle is present and citizen wants to reach it * -> Prohibit car usage */ #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToParkedCar'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToParkedCar; carUsageMode = CarUsagePolicy.Forbidden; } break; case ExtPathMode.RequiresWalkingPathToTarget: case ExtPathMode.CalculatingWalkingPathToTarget: case ExtPathMode.WalkingToTarget: /* * Citizen walks to target * -> Reset path mode */ #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToTarget'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; carUsageMode = CarUsagePolicy.Forbidden; break; case ExtPathMode.RequiresCarPath: case ExtPathMode.RequiresMixedCarPathToTarget: case ExtPathMode.DrivingToTarget: case ExtPathMode.DrivingToKnownParkPos: case ExtPathMode.DrivingToAltParkPos: case ExtPathMode.CalculatingCarPathToAltParkPos: case ExtPathMode.CalculatingCarPathToKnownParkPos: case ExtPathMode.CalculatingCarPathToTarget: if (parkedVehicleId == 0) { /* * Citizen wants to drive to target but parked vehicle is not present * -> Reset path mode */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode} but no parked vehicle present. Change to 'None'."); } #endif extInstance.Reset(); } else { /* * Citizen wants to drive to target and parked vehicle is present * -> Force parked car usage */ #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'RequiresCarPath'."); } #endif extInstance.pathMode = ExtPathMode.RequiresCarPath; carUsageMode = CarUsagePolicy.ForcedParked; startPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; // force to start from the parked car } break; default: #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'None'."); } #endif extInstance.Reset(); break; } startsAtOutsideConnection = Constants.ManagerFactory.ExtCitizenInstanceManager.IsAtOutsideConnection(instanceID, ref instanceData, ref extInstance, startPos); if (extInstance.pathMode == ExtPathMode.None) { if ((instanceData.m_flags & CitizenInstance.Flags.OnTour) != CitizenInstance.Flags.None || ignoreCost) { /* * Citizen is on a walking tour or is a mascot * -> Prohibit car usage */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen ignores cost ({ignoreCost}) or is on a walking tour ({(instanceData.m_flags & CitizenInstance.Flags.OnTour) != CitizenInstance.Flags.None}): Setting path mode to 'CalculatingWalkingPathToTarget'"); } #endif carUsageMode = CarUsagePolicy.Forbidden; extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; } else { /* * Citizen is not on a walking tour and is not a mascot * -> Check if citizen is located at an outside connection and make them obey Parking AI restrictions */ if (instanceData.m_sourceBuilding != 0) { ItemClass.Service sourceBuildingService = Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_sourceBuilding].Info.m_class.m_service; if (startsAtOutsideConnection) { if (sourceBuildingService == ItemClass.Service.Road) { if (vehicleInfo != null) { /* * Citizen is located at a road outside connection and can spawn a car * -> Force car usage */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is located at a road outside connection: Setting path mode to 'RequiresCarPath' and carUsageMode to 'ForcedPocket'"); } #endif extInstance.pathMode = ExtPathMode.RequiresCarPath; carUsageMode = CarUsagePolicy.ForcedPocket; } else { /* * Citizen is located at a non-road outside connection and cannot spawn a car * -> Path-finding fails */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is located at a road outside connection but does not have a car template: ABORTING PATH-FINDING"); } #endif extInstance.Reset(); return(false); } } else { /* * Citizen is located at a non-road outside connection * -> Prohibit car usage */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is located at a non-road outside connection: Setting path mode to 'CalculatingWalkingPathToTarget'"); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; carUsageMode = CarUsagePolicy.Forbidden; } } } } } if ((carUsageMode == CarUsagePolicy.Allowed || carUsageMode == CarUsagePolicy.ForcedParked) && parkedVehicleId != 0) { /* * Reuse parked vehicle info */ vehicleInfo = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].Info; /* * Check if the citizen should return their car back home */ if (extInstance.pathMode == ExtPathMode.None && // initiating a new path homeId != 0 && // home building present instanceData.m_targetBuilding == homeId // current target is home ) { /* * citizen travels back home * -> check if their car should be returned */ if ((extCitizen.lastTransportMode & ExtCitizen.ExtTransportMode.Car) != ExtCitizen.ExtTransportMode.None) { /* * citizen travelled by car * -> return car back home */ extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar; carUsageMode = CarUsagePolicy.Forbidden; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen used their car before and is not at home. Forcing to walk to parked car."); } #endif } else { /* * citizen travelled by other means of transport * -> check distance between home and parked car. if too far away: force to take the car back home */ float distHomeToParked = (Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position - Singleton <BuildingManager> .instance.m_buildings.m_buffer[homeId].m_position).magnitude; if (distHomeToParked > GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToHome) { /* * force to take car back home */ extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar; carUsageMode = CarUsagePolicy.Forbidden; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen wants to go home and parked car is too far away ({distHomeToParked}). Forcing walking to parked car."); } #endif } } } } /* * The following holds: * - pathMode is now either CalculatingWalkingPathToParkedCar, CalculatingWalkingPathToTarget, RequiresCarPath or None. * - if pathMode is CalculatingWalkingPathToParkedCar or RequiresCarPath: parked car is present and citizen is not on a walking tour * - carUsageMode is valid * - if pathMode is RequiresCarPath: carUsageMode is either ForcedParked or ForcedPocket */ /* * modify path-finding constraints (vehicleInfo, endPos) if citizen is forced to walk */ if (extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToParkedCar || extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToTarget) { /* * vehicle must not be used since we need a walking path to either * 1. a parked car or * 2. the target building */ if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar) { /* * walk to parked car * -> end position is parked car */ endPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen shall go to parked vehicle @ {endPos}"); } #endif } } } #if BENCHMARK } #endif #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is allowed to drive their car? {carUsageMode}"); } #endif // NON-STOCK CODE END /* * semi-stock code: determine path-finding parameters (laneTypes, vehicleTypes, extVehicleType, etc.) */ NetInfo.LaneType laneTypes = NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleTypes = VehicleInfo.VehicleType.None; bool randomParking = false; bool combustionEngine = false; ExtVehicleType extVehicleType = ExtVehicleType.None; if (vehicleInfo != null) { if (vehicleInfo.m_class.m_subService == ItemClass.SubService.PublicTransportTaxi) { if ((instanceData.m_flags & CitizenInstance.Flags.CannotUseTaxi) == CitizenInstance.Flags.None && Singleton <DistrictManager> .instance.m_districts.m_buffer[0].m_productionData.m_finalTaxiCapacity != 0u) { SimulationManager instance = Singleton <SimulationManager> .instance; if (instance.m_isNightTime || instance.m_randomizer.Int32(2u) == 0) { laneTypes |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); vehicleTypes |= vehicleInfo.m_vehicleType; extVehicleType = ExtVehicleType.Taxi; // NON-STOCK CODE // NON-STOCK CODE START if (Options.prohibitPocketCars) { extInstance.pathMode = ExtPathMode.TaxiToTarget; } // NON-STOCK CODE END } } } else // NON-STOCK CODE START if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Car) { if (carUsageMode != CarUsagePolicy.Forbidden) { extVehicleType = ExtVehicleType.PassengerCar; laneTypes |= NetInfo.LaneType.Vehicle; vehicleTypes |= vehicleInfo.m_vehicleType; combustionEngine = vehicleInfo.m_class.m_subService == ItemClass.SubService.ResidentialLow; } } else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { extVehicleType = ExtVehicleType.Bicycle; laneTypes |= NetInfo.LaneType.Vehicle; vehicleTypes |= vehicleInfo.m_vehicleType; } // NON-STOCK CODE END } // NON-STOCK CODE START ExtPathType extPathType = ExtPathType.None; PathUnit.Position endPosA = default(PathUnit.Position); bool calculateEndPos = true; bool allowRandomParking = true; #if BENCHMARK using (var bm = new Benchmark(null, "ParkingAI.Main")) { #endif if (Options.prohibitPocketCars) { // Parking AI if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.RequiresCarPath) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Setting startPos={startPos} for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode}"); } #endif if ( instanceData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None ) { /* * the citizen is starting their journey and the target is not an outside connection * -> find a suitable parking space near the target */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding parking space at target for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode} parkedVehicleId={parkedVehicleId}"); } #endif // find a parking space in the vicinity of the target bool calcEndPos; Vector3 parkPos; if ( AdvancedParkingManager.Instance.FindParkingSpaceForCitizen(endPos, vehicleInfo, ref extInstance, homeId, instanceData.m_targetBuilding == homeId, 0, false, out parkPos, ref endPosA, out calcEndPos) && extInstance.CalculateReturnPath(parkPos, endPos) ) { // success extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToKnownParkPos; calculateEndPos = calcEndPos; // if true, the end path position still needs to be calculated allowRandomParking = false; // find a direct path to the calculated parking position #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding known parking space for citizen instance {instanceID}, parked vehicle {parkedVehicleId} succeeded and return path {extInstance.returnPathId} ({extInstance.returnPathState}) is calculating. PathMode={extInstance.pathMode}"); } #endif /*if (! extInstance.CalculateReturnPath(parkPos, endPos)) { * // TODO retry? * if (debug) * Log._Debug($"CustomCitizenAI.CustomStartPathFind: [PFFAIL] Could not calculate return path for citizen instance {instanceID}, parked vehicle {parkedVehicleId}. Calling OnPathFindFailed."); * CustomHumanAI.OnPathFindFailure(extInstance); * return false; * }*/ } } if (extInstance.pathMode == ExtPathMode.RequiresCarPath) { /* * no known parking space found (pathMode has not been updated in the block above) * -> calculate direct path to target */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} is still at CurrentPathMode={extInstance.pathMode} (no parking space found?). Setting it to CalculatingCarPath. parkedVehicleId={parkedVehicleId}"); } #endif extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToTarget; } } /* * determine path type from path mode */ extPathType = extInstance.GetPathType(); extInstance.atOutsideConnection = startsAtOutsideConnection; /* * the following holds: * - pathMode is now either CalculatingWalkingPathToParkedCar, CalculatingWalkingPathToTarget, CalculatingCarPathToTarget, CalculatingCarPathToKnownParkPos or None. */ } #if BENCHMARK } #endif /* * enable random parking if exact parking space was not calculated yet */ if (extVehicleType == ExtVehicleType.PassengerCar || extVehicleType == ExtVehicleType.Bicycle) { if (allowRandomParking && instanceData.m_targetBuilding != 0 && ( Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office || (instanceData.m_flags & CitizenInstance.Flags.TargetIsNode) != 0 )) { randomParking = true; } } // NON-STOCK CODE END /* * determine the path position of the parked vehicle */ PathUnit.Position parkedVehiclePathPos = default(PathUnit.Position); if (parkedVehicleId != 0 && extVehicleType == ExtVehicleType.PassengerCar) { Vector3 position = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; CustomPathManager.FindPathPositionWithSpiralLoop(position, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out parkedVehiclePathPos); } bool allowUnderground = (instanceData.m_flags & (CitizenInstance.Flags.Underground | CitizenInstance.Flags.Transition)) != CitizenInstance.Flags.None; #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Requesting path-finding for citizen instance {instanceID}, citizen {instanceData.m_citizen}, extVehicleType={extVehicleType}, extPathType={extPathType}, startPos={startPos}, endPos={endPos}, sourceBuilding={instanceData.m_sourceBuilding}, targetBuilding={instanceData.m_targetBuilding} pathMode={extInstance.pathMode}"); } #endif /* * determine start & end path positions */ bool foundEndPos = !calculateEndPos || FindPathPosition(instanceID, ref instanceData, endPos, Options.prohibitPocketCars && (instanceData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) ? NetInfo.LaneType.Pedestrian : laneTypes, vehicleTypes, false, out endPosA); // NON-STOCK CODE: with Parking AI enabled, the end position must be a pedestrian position bool foundStartPos = false; PathUnit.Position startPosA; if (Options.prohibitPocketCars && (extInstance.pathMode == ExtPathMode.CalculatingCarPathToTarget || extInstance.pathMode == ExtPathMode.CalculatingCarPathToKnownParkPos)) { /* * citizen will enter their car now * -> find a road start position */ foundStartPos = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, laneTypes & ~NetInfo.LaneType.Pedestrian, vehicleTypes, allowUnderground, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out startPosA); } else { foundStartPos = FindPathPosition(instanceID, ref instanceData, startPos, laneTypes, vehicleTypes, allowUnderground, out startPosA); } /* * start path-finding */ if (foundStartPos && // TODO probably fails if vehicle is parked too far away from road foundEndPos // NON-STOCK CODE ) { if (enableTransport) { /* * public transport usage is allowed for this path */ if ((instanceData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None) { /* * citizen may use public transport */ laneTypes |= NetInfo.LaneType.PublicTransport; uint citizenId = instanceData.m_citizen; if (citizenId != 0u && (citizenManager.m_citizens.m_buffer[citizenId].m_flags & Citizen.Flags.Evacuating) != Citizen.Flags.None) { laneTypes |= NetInfo.LaneType.EvacuationTransport; } } else if (Options.prohibitPocketCars) // TODO check for incoming connection /* * citizen tried to use public transport but waiting time was too long * -> add public transport demand for source building */ { if (instanceData.m_sourceBuilding != 0) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} cannot uses public transport from building {instanceData.m_sourceBuilding} to {instanceData.m_targetBuilding}. Incrementing public transport demand."); } #endif ExtBuildingManager.Instance.ExtBuildings[instanceData.m_sourceBuilding].AddPublicTransportDemand((uint)GlobalConfig.Instance.ParkingAI.PublicTransportDemandWaitingIncrement, true); } } } PathUnit.Position dummyPathPos = default(PathUnit.Position); uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = extPathType; args.extVehicleType = extVehicleType; args.vehicleId = 0; args.spawned = (instanceData.m_flags & CitizenInstance.Flags.Character) != CitizenInstance.Flags.None; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = dummyPathPos; args.endPosA = endPosA; args.endPosB = dummyPathPos; args.vehiclePosition = parkedVehiclePathPos; args.laneTypes = laneTypes; args.vehicleTypes = vehicleTypes; args.maxLength = 20000f; args.isHeavyVehicle = false; args.hasCombustionEngine = combustionEngine; args.ignoreBlocked = false; args.ignoreFlooded = false; args.ignoreCosts = ignoreCost; args.randomParking = randomParking; args.stablePath = false; args.skipQueue = false; if ((instanceData.m_flags & CitizenInstance.Flags.OnTour) != 0) { args.stablePath = true; args.maxLength = 160000f; //args.laneTypes &= ~(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); } else { args.stablePath = false; args.maxLength = 20000f; } bool res = CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args); // NON-STOCK CODE END if (res) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Path-finding starts for citizen instance {instanceID}, path={path}, extVehicleType={extVehicleType}, extPathType={extPathType}, startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, laneType={laneTypes}, vehicleType={vehicleTypes}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, vehiclePos.m_segment={parkedVehiclePathPos.m_segment}, vehiclePos.m_lane={parkedVehiclePathPos.m_lane}, vehiclePos.m_offset={parkedVehiclePathPos.m_offset}"); } #endif if (instanceData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(instanceData.m_path); } instanceData.m_path = path; instanceData.m_flags |= CitizenInstance.Flags.WaitingPath; return(true); } } #if DEBUG if (Options.prohibitPocketCars) { if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): CustomCitizenAI.CustomStartPathFind: [PFFAIL] failed for citizen instance {instanceID} (CurrentPathMode={extInstance.pathMode}). startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, startPosA.offset={startPosA.m_offset}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, endPosA.offset={endPosA.m_offset}, foundStartPos={foundStartPos}, foundEndPos={foundEndPos}"); } extInstance.Reset(); } #endif return(false); }
public static void ToggleAllowedType(ushort segmentId, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType, bool add) { if (add) AddAllowedType(segmentId, laneIndex, laneId, laneInfo, vehicleType); else RemoveAllowedType(segmentId, laneIndex, laneId, laneInfo, vehicleType); }
/// <summary> /// Removes the given vehicle type from the set of allowed vehicles at the specified lane /// </summary> /// <param name="segmentId"></param> /// <param name="laneIndex"></param> /// <param name="laneId"></param> /// <param name="laneInfo"></param> /// <param name="road"></param> /// <param name="vehicleType"></param> public void RemoveAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType) { if (!Services.NetService.IsLaneValid(laneId)) { return; } if (!Services.NetService.IsSegmentValid(segmentId)) { // TODO we do not need the segmentId given here. Lane is enough return; } ExtVehicleType allowedTypes = GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Configured); allowedTypes &= ~vehicleType; allowedTypes &= GetBaseMask(segmentInfo.m_lanes[laneIndex], VehicleRestrictionsMode.Configured); // ensure default base mask Flags.setLaneAllowedVehicleTypes(segmentId, laneIndex, laneId, allowedTypes); NotifyStartEndNode(segmentId); if (OptionsManager.Instance.MayPublishSegmentChanges()) { Services.NetService.PublishSegmentChanges(segmentId); } }
public static bool IsBusAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Bus); }
public void ToggleAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType, bool add) { if (add) { AddAllowedType(segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType); } else { RemoveAllowedType(segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType); } }
public static bool IsEmergencyAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Emergency); }
public bool IsAllowed(ExtVehicleType?allowedTypes, ExtVehicleType vehicleType) { return(allowedTypes == null || ((ExtVehicleType)allowedTypes & vehicleType) != ExtVehicleType.None); }
public static bool IsServiceAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Service); }
private void _guiVehicleRestrictionsWindow(int num) { if (GUILayout.Button(Translation.GetString("Invert"))) { // invert pattern NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (object[] laneData in sortedLanes) { uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; ExtVehicleType baseMask = VehicleRestrictionsManager.GetBaseMask(laneInfo); if (baseMask == ExtVehicleType.None) { continue; } ExtVehicleType allowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo); allowedTypes = ~allowedTypes & baseMask; VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, allowedTypes); } } GUILayout.BeginHorizontal(); if (GUILayout.Button(Translation.GetString("Allow_all_vehicles"))) { // allow all vehicle types NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (object[] laneData in sortedLanes) { uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; ExtVehicleType baseMask = VehicleRestrictionsManager.GetBaseMask(laneInfo); if (baseMask == ExtVehicleType.None) { continue; } VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, baseMask); } } if (GUILayout.Button(Translation.GetString("Ban_all_vehicles"))) { // ban all vehicle types NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (object[] laneData in sortedLanes) { uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, ExtVehicleType.None); } } GUILayout.EndHorizontal(); if (GUILayout.Button(Translation.GetString("Apply_vehicle_restrictions_to_all_road_segments_between_two_junctions"))) { ApplyRestrictionsToAllSegments(); } }
public static bool IsRoadVehicleAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.RoadVehicle); }
private bool drawVehicleRestrictionHandles(ushort segmentId, bool viewOnly) { if (!LoadingExtension.IsPathManagerCompatible) { return(false); } if (viewOnly && !Options.vehicleRestrictionsOverlay && TrafficManagerTool.GetToolMode() != ToolMode.VehicleRestrictions) { return(false); } Vector3 center = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_bounds.center; var screenPos = Camera.main.WorldToScreenPoint(center); screenPos.y = Screen.height - screenPos.y; if (screenPos.z < 0) { return(false); } var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = center - camPos; if (diff.magnitude > TrafficManagerTool.PriorityCloseLod) { return(false); // do not draw if too distant } int numDirections; int numLanes = TrafficManagerTool.GetSegmentNumVehicleLanes(segmentId, null, out numDirections); // draw vehicle restrictions over each lane NetInfo segmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].Info; Vector3 yu = (Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection - Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection).normalized; if ((Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) { yu = -yu; } Vector3 xu = Vector3.Cross(yu, new Vector3(0, 1f, 0)).normalized; float f = viewOnly ? 4f : 7f; ItemClass connectionClass = segmentInfo.GetConnectionClass(); int maxNumSigns = 0; if (connectionClass.m_service == ItemClass.Service.Road) { maxNumSigns = roadVehicleTypes.Length; } else if (connectionClass.m_service == ItemClass.Service.PublicTransport && connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain) { maxNumSigns = railVehicleTypes.Length; } //Vector3 zero = center - 0.5f * (float)(numLanes + numDirections - 1) * f * (xu + yu); // "bottom left" Vector3 zero = center - 0.5f * (float)(numLanes - 1 + numDirections - 1) * f * xu - 0.5f * (float)maxNumSigns * f * yu; // "bottom left" /*if (!viewOnly) * Log._Debug($"xu: {xu.ToString()} yu: {yu.ToString()} center: {center.ToString()} zero: {zero.ToString()} numLanes: {numLanes} numDirections: {numDirections}");*/ uint x = 0; var guiColor = GUI.color; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(segmentId, segmentInfo, null); bool hovered = false; HashSet <NetInfo.Direction> directions = new HashSet <NetInfo.Direction>(); int sortedLaneIndex = -1; foreach (object[] laneData in sortedLanes) { ++sortedLaneIndex; uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if (!directions.Contains(laneInfo.m_direction)) { if (directions.Count > 0) { ++x; // space between different directions } directions.Add(laneInfo.m_direction); } ExtVehicleType[] possibleVehicleTypes = null; if (VehicleRestrictionsManager.IsRoadLane(laneInfo)) { possibleVehicleTypes = roadVehicleTypes; } else if (VehicleRestrictionsManager.IsRailLane(laneInfo)) { possibleVehicleTypes = railVehicleTypes; } else { ++x; continue; } ExtVehicleType allowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); uint y = 0; #if DEBUGx Vector3 labelCenter = zero + f * (float)x * xu + f * (float)y * yu; // in game coordinates var labelScreenPos = Camera.main.WorldToScreenPoint(labelCenter); labelScreenPos.y = Screen.height - labelScreenPos.y; diff = labelCenter - camPos; var labelZoom = 1.0f / diff.magnitude * 100f; _counterStyle.fontSize = (int)(11f * labelZoom); _counterStyle.normal.textColor = new Color(1f, 1f, 0f); string labelStr = $"Idx {laneIndex}"; Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr)); Rect labelRect = new Rect(labelScreenPos.x - dim.x / 2f, labelScreenPos.y, dim.x, dim.y); GUI.Label(labelRect, labelStr, _counterStyle); ++y; #endif foreach (ExtVehicleType vehicleType in possibleVehicleTypes) { bool allowed = VehicleRestrictionsManager.IsAllowed(allowedTypes, vehicleType); if (allowed && viewOnly) { continue; // do not draw allowed vehicles in view-only mode } bool hoveredHandle; DrawRestrictionsSign(viewOnly, camPos, out diff, xu, yu, f, zero, x, y, ref guiColor, TrafficLightToolTextureResources.VehicleRestrictionTextures[vehicleType][allowed], out hoveredHandle); if (hoveredHandle) { hovered = true; } 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); // TODO use SegmentTraverser if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { ApplyRestrictionsToAllSegments(sortedLaneIndex); } } ++y; } ++x; } guiColor.a = 1f; GUI.color = guiColor; return(hovered); }
internal void ChangeLightMode(ushort segmentId, ExtVehicleType vehicleType, CustomSegmentLight.Mode mode) { CustomSegmentLight light = segmentLights[segmentId].GetCustomLight(vehicleType); if (light != null) light.CurrentMode = mode; }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays) { #if DEBUG //Log._Debug($"CustomShipAI.CustomStartPathFind called for vehicle {vehicleID}"); #endif /// NON-STOCK CODE START /// ExtVehicleType vehicleType = ExtVehicleType.None; #if BENCHMARK using (var bm = new Benchmark(null, "vehicleType")) { #endif vehicleType = vehicleData.Info.m_vehicleAI is PassengerShipAI ? ExtVehicleType.PassengerShip : ExtVehicleType.CargoVehicle; #if BENCHMARK } #endif /// NON-STOCK CODE END /// VehicleInfo info = this.m_info; PathUnit.Position startPosA; PathUnit.Position startPosB; float startSqrDistA; float startSqrDistB; PathUnit.Position endPosA; PathUnit.Position endPosB; float endSqrDistA; float endSqrDistB; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, false, false, 64f, out startPosA, out startPosB, out startSqrDistA, out startSqrDistB) && CustomPathManager.FindPathPosition(endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, false, false, 64f, out endPosA, out endPosB, out endSqrDistA, out endSqrDistB)) { if (!startBothWays || startSqrDistA < 10f) { startPosB = default(PathUnit.Position); } if (!endBothWays || endSqrDistA < 10f) { endPosB = default(PathUnit.Position); } uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtCitizenInstance.ExtPathType.None; args.extVehicleType = vehicleType; args.vehicleId = vehicleID; args.spawned = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default(PathUnit.Position); args.laneTypes = NetInfo.LaneType.Vehicle; args.vehicleTypes = info.m_vehicleType; args.maxLength = 20000f; args.isHeavyVehicle = false; args.hasCombustionEngine = false; args.ignoreBlocked = false; args.ignoreFlooded = false; args.ignoreCosts = false; args.randomParking = false; args.stablePath = false; args.skipQueue = false; if (CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { // NON-STOCK CODE END if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }