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;
		}
Exemplo n.º 3
0
		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);
        }
Exemplo n.º 5
0
		/// <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);
        }
Exemplo n.º 11
0
    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);
        }
Exemplo n.º 12
0
 public LaneVehicleTypes(uint laneId, ExtVehicleType vehicleTypes)
 {
     this.laneId       = laneId;
     this.vehicleTypes = vehicleTypes;
 }
Exemplo n.º 13
0
        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;
		}
Exemplo n.º 16
0
		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;
		}
Exemplo n.º 17
0
        // 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);
		}
Exemplo n.º 21
0
        /// <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;
		}
Exemplo n.º 23
0
        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);
        }
Exemplo n.º 26
0
		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;
			}
		}
Exemplo n.º 29
0
        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);
			}
		}
Exemplo n.º 33
0
        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);
		}
Exemplo n.º 37
0
        /// <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);
		}
Exemplo n.º 39
0
 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);
		}
Exemplo n.º 41
0
 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;
		}
Exemplo n.º 47
0
        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);
        }