Beispiel #1
0
        internal void OnReleaseVehicle(ushort vehicleId)
        {
#if DEBUG
            //Log._Debug($"VehicleStateManager.OnReleaseVehicle({vehicleId}) called.");
#endif
            VehicleState state = _GetVehicleState(vehicleId);
            state.VehicleType = ExtVehicleType.None;
            ExtCitizenInstance driverExtInstance = state.GetDriverExtInstance();
            if (driverExtInstance != null)
            {
                //driverExtInstance.FailedParkingAttempts = 0;
                driverExtInstance.Reset();
            }
            //state.DriverInstanceId = 0;
#if USEPATHWAITCOUNTER
            state.PathWaitCounter = 0;
#endif
            state.Valid = false;
            //VehicleStates[vehicleId].Reset();
        }
Beispiel #2
0
        public bool ExtStartPathFind(ushort vehicleID, ref Vehicle vehicleData, ushort driverInstanceId, ref ExtCitizenInstance driverExtInstance, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget)
        {
#if DEBUG
            bool citDebug  = GlobalConfig.Instance.Debug.CitizenId == 0 || GlobalConfig.Instance.Debug.CitizenId == driverExtInstance.GetCitizenId();
            bool debug     = GlobalConfig.Instance.Debug.Switches[2] && citDebug;
            bool fineDebug = GlobalConfig.Instance.Debug.Switches[4] && citDebug;

            if (debug)
            {
                Log.Warning($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): called for vehicle {vehicleID}, driverInstanceId={driverInstanceId}, startPos={startPos}, endPos={endPos}, sourceBuilding={vehicleData.m_sourceBuilding}, targetBuilding={vehicleData.m_targetBuilding} pathMode={driverExtInstance.pathMode}");
            }
#endif

            PathUnit.Position startPosA = default(PathUnit.Position);
            PathUnit.Position startPosB = default(PathUnit.Position);
            PathUnit.Position endPosA   = default(PathUnit.Position);
            float sqrDistA = 0f;
            float sqrDistB;

            CitizenManager citizenManager = Singleton <CitizenManager> .instance;
            ushort targetBuildingId       = citizenManager.m_instances.m_buffer[(int)driverInstanceId].m_targetBuilding;
            uint driverCitizenId          = citizenManager.m_instances.m_buffer[(int)driverInstanceId].m_citizen;

            // NON-STOCK CODE START
            bool calculateEndPos    = true;
            bool allowRandomParking = true;
            bool movingToParkingPos = false;
            bool foundStartingPos   = false;
            bool skipQueue          = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0;
            ExtPathType extPathType = ExtPathType.None;
#if BENCHMARK
            using (var bm = new Benchmark(null, "ParkingAI")) {
#endif
            if (Options.prohibitPocketCars)
            {
                //if (driverExtInstance != null) {
#if DEBUG
                if (debug)
                {
                    Log.Warning($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): PathMode={driverExtInstance.pathMode} for vehicle {vehicleID}, driver citizen instance {driverExtInstance.instanceId}!");
                }
#endif

                if (targetBuildingId != 0 && (Singleton <BuildingManager> .instance.m_buildings.m_buffer[targetBuildingId].m_flags & Building.Flags.IncomingOutgoing) != Building.Flags.None)
                {
                    // target is outside connection
                    driverExtInstance.pathMode = ExtPathMode.CalculatingCarPathToTarget;
                }
                else
                {
                    if (driverExtInstance.pathMode == ExtPathMode.DrivingToTarget || driverExtInstance.pathMode == ExtPathMode.DrivingToKnownParkPos || driverExtInstance.pathMode == ExtPathMode.ParkingFailed)
                    {
                        skipQueue = true;
                    }

                    bool allowTourists = false;
                    if (driverExtInstance.pathMode == ExtPathMode.ParkingFailed)
                    {
                        // previous parking attempt failed
                        driverExtInstance.pathMode = ExtPathMode.CalculatingCarPathToAltParkPos;
                        allowTourists = true;

#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): Vehicle {vehicleID} shall move to an alternative parking position! CurrentPathMode={driverExtInstance.pathMode} FailedParkingAttempts={driverExtInstance.failedParkingAttempts}");
                        }
#endif

                        if (driverExtInstance.parkingPathStartPosition != null)
                        {
                            startPosA        = (PathUnit.Position)driverExtInstance.parkingPathStartPosition;
                            foundStartingPos = true;
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): Setting starting pos for {vehicleID} to segment={startPosA.m_segment}, laneIndex={startPosA.m_lane}, offset={startPosA.m_offset}");
                            }
#endif
                        }
                        startBothWays = false;

                        if (driverExtInstance.failedParkingAttempts > GlobalConfig.Instance.ParkingAI.MaxParkingAttempts)
                        {
                            // maximum number of parking attempts reached
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): Reached maximum number of parking attempts for vehicle {vehicleID}! GIVING UP.");
                            }
#endif
                            driverExtInstance.Reset();

                            // pocket car fallback
                            //vehicleData.m_flags |= Vehicle.Flags.Parking;
                            return(false);
                        }
                        else
                        {
#if DEBUG
                            if (fineDebug)
                            {
                                Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): Increased number of parking attempts for vehicle {vehicleID}: {driverExtInstance.failedParkingAttempts}/{GlobalConfig.Instance.ParkingAI.MaxParkingAttempts}");
                            }
#endif
                        }
                    }
                    else
                    {
                        driverExtInstance.pathMode = ExtPathMode.CalculatingCarPathToKnownParkPos;
                    }

                    ushort homeId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[driverCitizenId].m_homeBuilding;
                    bool calcEndPos;
                    Vector3 parkPos;

                    if (AdvancedParkingManager.Instance.FindParkingSpaceForCitizen(endPos, vehicleData.Info, ref driverExtInstance, homeId, targetBuildingId == homeId, vehicleID, allowTourists, out parkPos, ref endPosA, out calcEndPos))
                    {
                        calculateEndPos    = calcEndPos;
                        allowRandomParking = false;
                        movingToParkingPos = true;

                        if (!driverExtInstance.CalculateReturnPath(parkPos, endPos))
                        {
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): Could not calculate return path for citizen instance {driverExtInstance.instanceId}, vehicle {vehicleID}. Resetting instance.");
                            }
#endif
                            driverExtInstance.Reset();
                            return(false);
                        }
                    }
                    else if (driverExtInstance.pathMode == ExtPathMode.CalculatingCarPathToAltParkPos)
                    {
                        // no alternative parking spot found: abort
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): No alternative parking spot found for vehicle {vehicleID}, citizen instance {driverExtInstance.instanceId} with CurrentPathMode={driverExtInstance.pathMode}! GIVING UP.");
                        }
#endif
                        driverExtInstance.Reset();
                        return(false);
                    }
                    else
                    {
                        // calculate a direct path to target
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): No alternative parking spot found for vehicle {vehicleID}, citizen instance {driverExtInstance.instanceId} with CurrentPathMode={driverExtInstance.pathMode}! Setting CurrentPathMode to 'CalculatingCarPath'.");
                        }
#endif
                        driverExtInstance.pathMode = ExtPathMode.CalculatingCarPathToTarget;
                    }
                }

                extPathType = driverExtInstance.GetPathType();

                /*} else {
                 #if DEBUG
                 *      if (debug)
                 *              Log.Warning($"CustomPassengerCarAI.CustomStartPathFind: No driver citizen instance found for vehicle {vehicleID}!");
                 #endif
                 * }*/
            }
#if BENCHMARK
        }
#endif

            NetInfo.LaneType laneTypes = NetInfo.LaneType.Vehicle;
            if (!movingToParkingPos)
            {
                laneTypes |= NetInfo.LaneType.Pedestrian;
            }
            // NON-STOCK CODE END

            VehicleInfo.VehicleType vehicleTypes = this.m_info.m_vehicleType;
            bool allowUnderground = (vehicleData.m_flags & Vehicle.Flags.Underground) != 0;
            bool randomParking    = false;
            bool combustionEngine = this.m_info.m_class.m_subService == ItemClass.SubService.ResidentialLow;
            if (allowRandomParking &&             // NON-STOCK CODE
                !movingToParkingPos &&
                targetBuildingId != 0 &&
                (
                    Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)targetBuildingId].Info.m_class.m_service > ItemClass.Service.Office ||
                    (citizenManager.m_instances.m_buffer[driverInstanceId].m_flags & CitizenInstance.Flags.TargetIsNode) != CitizenInstance.Flags.None
                ))
            {
                randomParking = true;
            }

#if DEBUG
            if (fineDebug)
            {
                Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): Requesting path-finding for passenger car {vehicleID}, startPos={startPos}, endPos={endPos}, extPathType={extPathType}");
            }
#endif

            // NON-STOCK CODE START
            if (!foundStartingPos)
            {
                foundStartingPos = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, vehicleTypes, allowUnderground, false, 32f, out startPosA, out startPosB, out sqrDistA, out sqrDistB);
            }

            bool foundEndPos = !calculateEndPos || citizenManager.m_instances.m_buffer[(int)driverInstanceId].Info.m_citizenAI.FindPathPosition(driverInstanceId, ref citizenManager.m_instances.m_buffer[(int)driverInstanceId], endPos, Options.prohibitPocketCars && (targetBuildingId == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[targetBuildingId].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) ? NetInfo.LaneType.Pedestrian : (laneTypes | NetInfo.LaneType.Pedestrian), vehicleTypes, undergroundTarget, out endPosA);
            // NON-STOCK CODE END

            if (foundStartingPos &&
                foundEndPos)                   // NON-STOCK CODE

            {
                if (!startBothWays || sqrDistA < 10f)
                {
                    startPosB = default(PathUnit.Position);
                }
                PathUnit.Position endPosB = default(PathUnit.Position);
                SimulationManager simMan  = Singleton <SimulationManager> .instance;
                uint path;
                PathUnit.Position dummyPathPos = default(PathUnit.Position);
                // NON-STOCK CODE START
                PathCreationArgs args;
                args.extPathType         = extPathType;
                args.extVehicleType      = ExtVehicleType.PassengerCar;
                args.vehicleId           = vehicleID;
                args.buildIndex          = simMan.m_currentBuildIndex;
                args.startPosA           = startPosA;
                args.startPosB           = startPosB;
                args.endPosA             = endPosA;
                args.endPosB             = endPosB;
                args.vehiclePosition     = dummyPathPos;
                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       = randomParking;
                args.stablePath          = false;
                args.skipQueue           = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0;

                if (CustomPathManager._instance.CreatePath(out path, ref simMan.m_randomizer, args))
                {
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomPassengerCarAI.ExtStartPathFind({vehicleID}): Path-finding starts for passenger car {vehicleID}, path={path}, startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, laneType={laneTypes}, vehicleType={vehicleTypes}, 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);
        }
        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.CitizenId == 0 || GlobalConfig.Instance.Debug.CitizenId == instanceData.m_citizen;
            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}");
            }
#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;

            // disallow car usage if citizen is on a walking tour
            if ((instanceData.m_flags & CitizenInstance.Flags.OnTour) != CitizenInstance.Flags.None)
            {
                carUsageMode = CarUsagePolicy.Forbidden;
                vehicleInfo  = null;                // TODO check if citizens may use bikes on walking tours
            }

#if BENCHMARK
            using (var bm = new Benchmark(null, "ParkingAI.Preparation")) {
#endif
            if (Options.prohibitPocketCars)
            {
                switch (extInstance.pathMode)
                {
                case ExtPathMode.RequiresWalkingPathToParkedCar:
                case ExtPathMode.CalculatingWalkingPathToParkedCar:
                case ExtPathMode.WalkingToParkedCar:
                case ExtPathMode.ApproachingParkedCar:
                    if (parkedVehicleId == 0 || carUsageMode == CarUsagePolicy.Forbidden)
                    {
                        // parked vehicle not present or citizen is on a walking tour
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode} but no parked vehicle present OR citizen is on a walking tour (carUsageMode={carUsageMode}). Change to 'None'.");
                        }
#endif

                        extInstance.Reset();
                    }
                    else
                    {
#if DEBUG
                        if (fineDebug)
                        {
                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}.  Change to 'CalculatingWalkingPathToParkedCar'.");
                        }
#endif
                        extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToParkedCar;
                    }
                    break;

                case ExtPathMode.RequiresWalkingPathToTarget:
                case ExtPathMode.CalculatingWalkingPathToTarget:
                case ExtPathMode.WalkingToTarget:
#if DEBUG
                    if (fineDebug)
                    {
                        Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen 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 (parkedVehicleId == 0 || carUsageMode == CarUsagePolicy.Forbidden)
                    {
                        // parked vehicle not present or citizen is on a walking tour

#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode} but no parked vehicle present OR citizen is on a walking tour (carUsageMode={carUsageMode}). Change to 'None'.");
                        }
#endif

                        extInstance.Reset();
                    }
                    else
                    {
#if DEBUG
                        if (fineDebug)
                        {
                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}.  Change to 'RequiresCarPath'.");
                        }
#endif

                        extInstance.pathMode = ExtPathMode.RequiresCarPath;
                    }
                    break;

                default:
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'None'.");
                    }
#endif
                    extInstance.Reset();
                    break;
                }

                /*
                 * 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
                 */

                /*
                 * reuse parked vehicle info
                 */
                if (parkedVehicleId != 0)
                {
                    vehicleInfo = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].Info;
                }

                /*
                 * check if the citizen must use their car on their current path
                 */
                if (parkedVehicleId != 0 &&                         // parked car present
                    carUsageMode != CarUsagePolicy.Forbidden &&     // cititzen is not on a walking tour
                    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;

#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;

#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
                        }
                    }
                }

                /*
                 * 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
                     */
                    vehicleInfo  = null;
                    carUsageMode = CarUsagePolicy.Forbidden;

                    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
                    }
                }
                else if (extInstance.pathMode == ExtPathMode.RequiresCarPath)
                {
                    /*
                     * citizen stands in front of their parked vehicle
                     * -> find a car-only path now
                     */
                    carUsageMode = CarUsagePolicy.Forced;
                    startPos     = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position;                       // force to start from the parked car

#if DEBUG
                    if (fineDebug)
                    {
                        Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is forced to drive their car");
                    }
#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();

                /*
                 * 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)
                    {
                        if (carUsageMode != CarUsagePolicy.Forced)                           // NON-STOCK CODE

                        /*
                         * 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.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}, 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}");
                }
            }
#endif
            return(false);
        }
Beispiel #4
0
        internal bool ExtSimulationStep(ushort instanceID, ref CitizenInstance instanceData, ref ExtCitizenInstance extInstance, Vector3 physicsLodRefPos)
        {
            // check if the citizen has reached a parked car or target
            if (extInstance.pathMode == ExtPathMode.WalkingToParkedCar || extInstance.pathMode == ExtPathMode.ApproachingParkedCar)
            {
                ushort parkedVehicleId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[instanceData.m_citizen].m_parkedVehicle;
                if (parkedVehicleId == 0)
                {
                    // citizen is reaching their parked car but does not own a parked car
#if DEBUG
                    if (GlobalConfig.Instance.Debug.Switches[2])
                    {
                        Log.Warning($"CustomHumanAI.CustomSimulationStep({instanceID}): Citizen instance {instanceID} was walking to / reaching their parked car ({extInstance.pathMode}) but parked car has disappeared. RESET.");
                    }
#endif

                    extInstance.Reset();

                    instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath;
                    instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering);
                    this.InvalidPath(instanceID, ref instanceData);
                    return(true);
                }
                else
                {
                    ParkedCarApproachState approachState = AdvancedParkingManager.Instance.CitizenApproachingParkedCarSimulationStep(instanceID, ref instanceData, ref extInstance, physicsLodRefPos, ref Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId]);
                    switch (approachState)
                    {
                    case ParkedCarApproachState.None:
                    default:
                        break;

                    case ParkedCarApproachState.Approaching:
                        // citizen approaches their parked car
                        return(true);

                    case ParkedCarApproachState.Approached:
                        // citizen reached their parked car
#if DEBUG
                        if (GlobalConfig.Instance.Debug.Switches[4])
                        {
                            Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Citizen instance {instanceID} arrived at parked car. PathMode={extInstance.pathMode}");
                        }
#endif
                        if (instanceData.m_path != 0)
                        {
                            Singleton <PathManager> .instance.ReleasePath(instanceData.m_path);

                            instanceData.m_path = 0;
                        }
                        instanceData.m_flags = instanceData.m_flags & (CitizenInstance.Flags.Created | CitizenInstance.Flags.Cheering | CitizenInstance.Flags.Deleted | CitizenInstance.Flags.Underground | CitizenInstance.Flags.CustomName | CitizenInstance.Flags.Character | CitizenInstance.Flags.BorrowCar | CitizenInstance.Flags.HangAround | CitizenInstance.Flags.InsideBuilding | CitizenInstance.Flags.WaitingPath | CitizenInstance.Flags.TryingSpawnVehicle | CitizenInstance.Flags.CannotUseTransport | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.OnPath | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.AtTarget | CitizenInstance.Flags.RequireSlowStart | CitizenInstance.Flags.Transition | CitizenInstance.Flags.RidingBicycle | CitizenInstance.Flags.OnBikeLane | CitizenInstance.Flags.CannotUseTaxi | CitizenInstance.Flags.CustomColor | CitizenInstance.Flags.Blown | CitizenInstance.Flags.Floating | CitizenInstance.Flags.TargetFlags);
                        if (!this.StartPathFind(instanceID, ref instanceData))
                        {
                            instanceData.Unspawn(instanceID);
                            extInstance.Reset();
                        }

                        return(true);

                    case ParkedCarApproachState.Failure:
#if DEBUG
                        if (GlobalConfig.Instance.Debug.Switches[2])
                        {
                            Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Citizen instance {instanceID} failed to arrive at parked car. PathMode={extInstance.pathMode}");
                        }
#endif
                        // repeat path-finding
                        instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath;
                        instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering);
                        this.InvalidPath(instanceID, ref instanceData);
                        return(true);
                    }
                }
            }
            else if ((extInstance.pathMode == ExtCitizenInstance.ExtPathMode.WalkingToTarget ||
                      extInstance.pathMode == ExtCitizenInstance.ExtPathMode.PublicTransportToTarget ||
                      extInstance.pathMode == ExtCitizenInstance.ExtPathMode.TaxiToTarget)
                     )
            {
                AdvancedParkingManager.Instance.CitizenApproachingTargetSimulationStep(instanceID, ref instanceData, ref extInstance);
            }
            return(false);
        }
        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 BENCHMARK
            using (var bm = new Benchmark(null, "ParkingAI.Preparation")) {
#endif
            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 BENCHMARK
        }
#endif

            /*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 vehicleTypes = VehicleInfo.VehicleType.None;
            bool randomParking    = false;
            bool combustionEngine = 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);
                            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.Allowed || carUsageMode == CarUsagePolicy.Forced)
                        {
                            extVehicleType        = ExtVehicleType.PassengerCar;
                            laneTypes            |= NetInfo.LaneType.Vehicle;
                            vehicleTypes         |= vehicleInfo.m_vehicleType;
                            combustionEngine      = vehicleInfo.m_class.m_subService == ItemClass.SubService.ResidentialLow;
                            canUseOwnPassengerCar = true;
                        }
                    }
                    else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle)
                    {
                        extVehicleType = ExtVehicleType.Bicycle;
                        laneTypes     |= NetInfo.LaneType.Vehicle;
                        vehicleTypes  |= 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 BENCHMARK
            using (var bm = new Benchmark(null, "ParkingAI.Main")) {
#endif
            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 BENCHMARK
        }
#endif

            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), 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))
            {
                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 citizenData, startPos, startLaneType, vehicleTypes, 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;
                // NON-STOCK CODE START
                PathCreationArgs args;
                args.extPathType         = extPathType;
                args.extVehicleType      = extVehicleType;
                args.vehicleId           = 0;
                args.buildIndex          = Singleton <SimulationManager> .instance.m_currentBuildIndex;
                args.startPosA           = startPosA;
                args.startPosB           = dummyPathPos;
                args.endPosA             = endPosA;
                args.endPosB             = dummyPathPos;
                args.vehiclePosition     = vehiclePosition;
                args.laneTypes           = laneTypes;
                args.vehicleTypes        = vehicleTypes;
                args.maxLength           = 20000f;
                args.isHeavyVehicle      = false;
                args.hasCombustionEngine = combustionEngine;
                args.ignoreBlocked       = false;
                args.ignoreFlooded       = false;
                args.randomParking       = randomParking;
                args.stablePath          = false;
                args.skipQueue           = false;

                bool res = CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args);
                // NON-STOCK CODE END

                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={vehicleTypes}, 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);
        }