diff --git a/README.md b/README.md index f8733571..8b67720b 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ A work-in-progress modification for **Cities: Skylines** to add additional traff User manual: http://www.viathinksoft.de/tmpe # Changelog +1.8.3, 12/4/2016 +- Bugfix: Despite having the Parking AI activated, cims sometimes still spawn pocket cars. +- Bugfix: When the Parking AI is active, bicycle lanes are not used (thanks to @informmanuel for reporting this issue) +- Tweaked u-turn behavior +- Improved info views + 1.8.2, 12/3/2016 - Bugfix: Taxis were not used (thanks to @[Delta ²k5] for reporting) - Bugfix: Minor UI fix in Default speed limits dialog diff --git a/TLM/TLM/Custom/AI/CustomCitizenAI.cs b/TLM/TLM/Custom/AI/CustomCitizenAI.cs index 22fda717..6c241a5a 100644 --- a/TLM/TLM/Custom/AI/CustomCitizenAI.cs +++ b/TLM/TLM/Custom/AI/CustomCitizenAI.cs @@ -173,7 +173,7 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa } // NON-STOCK CODE END - NetInfo.LaneType laneType = NetInfo.LaneType.Pedestrian; + NetInfo.LaneType laneTypes = NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleType = VehicleInfo.VehicleType.None; bool randomParking = false; if (vehicleInfo != null) { @@ -181,7 +181,7 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa 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) { - laneType |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); + laneTypes |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); vehicleType |= vehicleInfo.m_vehicleType; extVehicleType = ExtVehicleType.Taxi; // NON-STOCK CODE // NON-STOCK CODE START @@ -197,13 +197,13 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Car) { if (mayUseOwnPassengerCar) { extVehicleType = ExtVehicleType.PassengerCar; - laneType |= NetInfo.LaneType.Vehicle; + laneTypes |= NetInfo.LaneType.Vehicle; vehicleType |= vehicleInfo.m_vehicleType; canUseOwnPassengerCar = true; } } else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { extVehicleType = ExtVehicleType.Bicycle; - laneType |= NetInfo.LaneType.Vehicle; + 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; @@ -212,7 +212,7 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa // NON-STOCK CODE END } } - NetInfo.LaneType startLaneType = laneType; + NetInfo.LaneType startLaneType = laneTypes; PathUnit.Position vehiclePosition = default(PathUnit.Position); // NON-STOCK CODE START @@ -306,7 +306,7 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa Log._Debug($"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}"); #endif - bool foundEndPos = !calculateEndPos || FindPathPosition(instanceID, ref citizenData, endPos, laneType, vehicleType, false, out endPosA); // NON-STOCK CODE + bool foundEndPos = !calculateEndPos || FindPathPosition(instanceID, ref citizenData, endPos, Options.prohibitPocketCars ? NetInfo.LaneType.Pedestrian : (laneTypes | NetInfo.LaneType.Pedestrian), vehicleType, false, out endPosA); // NON-STOCK CODE PathUnit.Position startPosA; if (FindPathPosition(instanceID, ref citizenData, startPos, startLaneType, vehicleType, allowUnderground, out startPosA) && @@ -323,17 +323,30 @@ public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenDa } } - if (!forceUseCar && (citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None) { - laneType |= NetInfo.LaneType.PublicTransport; + bool canUseTransport = (citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None; + if (canUseTransport) { + if (!forceUseCar) { + laneTypes |= NetInfo.LaneType.PublicTransport; + } + } else if (Options.prohibitPocketCars) { + // cim tried to use public transport but waiting time was too long + if (citizenData.m_sourceBuilding != 0) { +#if DEBUG + if (GlobalConfig.Instance.DebugSwitches[2]) + Log._Debug($"Citizen instance {instanceID} cannot uses public transport from building {citizenData.m_sourceBuilding} to {citizenData.m_targetBuilding}. Incrementing public transport demand."); +#endif + ExtBuildingManager.Instance.GetExtBuilding(citizenData.m_sourceBuilding).AddPublicTransportDemand((uint)GlobalConfig.Instance.PublicTransportDemandWaitingIncrement, true); + } } + PathUnit.Position dummyPathPos = default(PathUnit.Position); uint path; - bool res = CustomPathManager._instance.CreatePath(false, extVehicleType, 0, extPathType, out path, ref Singleton<SimulationManager>.instance.m_randomizer, Singleton<SimulationManager>.instance.m_currentBuildIndex, startPosA, dummyPathPos, endPosA, dummyPathPos, vehiclePosition, laneType, vehicleType, 20000f, false, false, false, false, randomParking, false, allowEscapeTransport); + bool res = CustomPathManager._instance.CreatePath(false, 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, allowEscapeTransport); if (res) { #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) - Log._Debug($"Path-finding starts for citizen instance {instanceID}, path={path}, extVehicleType={extVehicleType}, startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, laneType={laneType}, 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}, allowEscapeTransport={allowEscapeTransport}"); + Log._Debug($"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}, allowEscapeTransport={allowEscapeTransport}"); #endif if (citizenData.m_path != 0u) { @@ -402,7 +415,7 @@ protected static bool TrySpawnParkedPassengerCarBuilding(uint citizenId, ushort Quaternion parkRot = Quaternion.identity; float parkOffset; - if (CustomPassengerCarAI.FindParkingSpaceBuilding(vehicleInfo, homeId, 0, 0, refPos, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, out parkPos, out parkRot, out parkOffset)) { + if (CustomPassengerCarAI.FindParkingSpaceBuilding(vehicleInfo, homeId, 0, 0, refPos, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, out parkPos, out parkRot, out parkOffset)) { // position found, spawn a parked vehicle ushort parkedVehicleId; if (Singleton<VehicleManager>.instance.CreateParkedVehicle(out parkedVehicleId, ref Singleton<SimulationManager>.instance.m_randomizer, vehicleInfo, parkPos, parkRot, citizenId)) { diff --git a/TLM/TLM/Custom/AI/CustomHumanAI.cs b/TLM/TLM/Custom/AI/CustomHumanAI.cs index 3262bf78..5e8e08ba 100644 --- a/TLM/TLM/Custom/AI/CustomHumanAI.cs +++ b/TLM/TLM/Custom/AI/CustomHumanAI.cs @@ -66,7 +66,7 @@ public void CustomSimulationStep(ushort instanceID, ref CitizenInstance instance if (pathFindSucceeded) { bool handleSoftPathFindFailure; - if (!CustomHumanAI.OnPathFindSuccess(instanceID, ref instanceData, out handleSoftPathFindFailure, out handleSuccess)) { + if (!CustomHumanAI.OnPathFindSuccess(instanceID, ref instanceData, ref Singleton<CitizenManager>.instance.m_citizens.m_buffer[instanceData.m_citizen], out handleSoftPathFindFailure, out handleSuccess)) { #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) { ushort parkedVehicleId = Singleton<CitizenManager>.instance.m_citizens.m_buffer[instanceData.m_citizen].m_parkedVehicle; @@ -201,6 +201,7 @@ internal static bool OnPathFindFailure(ushort instanceID, ref CitizenInstance in case ExtPathMode.None: case ExtPathMode.CalculatingWalkingPathToParkedCar: case ExtPathMode.CalculatingWalkingPathToTarget: + case ExtPathMode.TaxiToTarget: if ((instanceData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None) { if (instanceData.m_targetBuilding != 0) { ExtBuildingManager.Instance.GetExtBuilding(instanceData.m_targetBuilding).AddPublicTransportDemand((uint)GlobalConfig.Instance.PublicTransportDemandIncrement, false); @@ -247,32 +248,46 @@ internal static bool OnPathFindFailure(ushort instanceID, ref CitizenInstance in return ret; } - internal static bool OnPathFindSuccess(ushort instanceID, ref CitizenInstance instanceData, out bool handleSoftPathFindFailure, out bool handleSuccess) { + internal static bool OnPathFindSuccess(ushort instanceID, ref CitizenInstance instanceData, ref Citizen citizenData, out bool handleSoftPathFindFailure, out bool handleSuccess) { handleSoftPathFindFailure = false; handleSuccess = true; #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) - Log._Debug($"CustomHumanAI.OnPathFindSuccess: Path-finding succeeded for citizen instance {instanceID}. Path: {instanceData.m_path} vehicle={Singleton<CitizenManager>.instance.m_citizens.m_buffer[instanceData.m_citizen].m_vehicle}"); + Log._Debug($"CustomHumanAI.OnPathFindSuccess: Path-finding succeeded for citizen instance {instanceID}. Path: {instanceData.m_path} vehicle={citizenData.m_vehicle}"); #endif - if (Singleton<CitizenManager>.instance.m_citizens.m_buffer[instanceData.m_citizen].m_vehicle == 0) { + if (citizenData.m_vehicle == 0) { ExtCitizenInstance extInstance = ExtCitizenInstanceManager.Instance.GetExtInstance(instanceID); if (extInstance.PathMode == ExtPathMode.TaxiToTarget) { + // cim uses taxi + if (instanceData.m_sourceBuilding != 0) + ExtBuildingManager.Instance.GetExtBuilding(instanceData.m_sourceBuilding).RemovePublicTransportDemand((uint)GlobalConfig.Instance.PublicTransportDemandUsageDecrement, true); + if (instanceData.m_targetBuilding != 0) + ExtBuildingManager.Instance.GetExtBuilding(instanceData.m_targetBuilding).RemovePublicTransportDemand((uint)GlobalConfig.Instance.PublicTransportDemandUsageDecrement, false); + return true; } - ushort parkedVehicleId = Singleton<CitizenManager>.instance.m_citizens.m_buffer[instanceData.m_citizen].m_parkedVehicle; + ushort parkedVehicleId = citizenData.m_parkedVehicle; float sqrDistToParkedVehicle = 0f; if (parkedVehicleId != 0) { sqrDistToParkedVehicle = (instanceData.GetLastFramePosition() - Singleton<VehicleManager>.instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position).sqrMagnitude; } byte laneTypes = CustomPathManager._instance.m_pathUnits.m_buffer[instanceData.m_path].m_laneTypes; + byte vehicleTypes = CustomPathManager._instance.m_pathUnits.m_buffer[instanceData.m_path].m_vehicleTypes; bool usesPublicTransport = (laneTypes & (byte)(NetInfo.LaneType.PublicTransport)) != 0; - bool usesCar = (laneTypes & (byte)(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0; + bool usesCar = (laneTypes & (byte)(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0 && (vehicleTypes & (byte)(VehicleInfo.VehicleType.Car)) != 0; if (usesPublicTransport && usesCar && extInstance.PathMode == ExtPathMode.CalculatingCarPathToKnownParkPos) { + /* + * when using public transport together with a car (assuming a "source -> walk -> drive -> walk -> use public transport -> walk -> target" path) + * discard parking space information since the cim has to park near the public transport stop + * (instead of parking in the vicinity of the target building). + * + * TODO we could check if the path looks like "source -> walk -> use public transport -> walk -> drive -> [walk ->] target" (in this case parking space information would still be valid) + */ extInstance.PathMode = ExtPathMode.CalculatingCarPathToTarget; extInstance.ParkingSpaceLocation = ExtParkingSpaceLocation.None; extInstance.ParkingSpaceLocationId = 0; @@ -298,6 +313,8 @@ internal static bool OnPathFindSuccess(ushort instanceID, ref CitizenInstance in ushort sourceBuildingId = instanceData.m_sourceBuilding; if (sourceBuildingId != 0) { isAtOutsideConnection = (Singleton<BuildingManager>.instance.m_buildings.m_buffer[sourceBuildingId].m_flags & Building.Flags.IncomingOutgoing) != Building.Flags.None;// Info.m_buildingAI is OutsideConnectionAI; + if (isAtOutsideConnection && (instanceData.GetLastFramePosition() - Singleton<BuildingManager>.instance.m_buildings.m_buffer[sourceBuildingId].m_position).magnitude > GlobalConfig.Instance.MaxBuildingToPedestrianLaneDistance) + isAtOutsideConnection = false; //isAtOutsideConnection = Singleton<BuildingManager>.instance.m_buildings.m_buffer[sourceBuildingId].Info.m_buildingAI is OutsideConnectionAI; } diff --git a/TLM/TLM/Custom/AI/CustomPassengerCarAI.cs b/TLM/TLM/Custom/AI/CustomPassengerCarAI.cs index 3c1e372a..831b1a61 100644 --- a/TLM/TLM/Custom/AI/CustomPassengerCarAI.cs +++ b/TLM/TLM/Custom/AI/CustomPassengerCarAI.cs @@ -206,7 +206,7 @@ public static ushort GetDriverInstance(ushort vehicleID, ref Vehicle data) { // public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) - Log._Debug($"CustomPassengerCarAI.CustomStartPathFind: called for vehicle {vehicleID}, startPos={startPos}, endPos={endPos}, sourceBuilding={vehicleData.m_sourceBuilding}, targetBuilding={vehicleData.m_targetBuilding}"); + Log.Warning($"CustomPassengerCarAI.CustomStartPathFind: called for vehicle {vehicleID}, startPos={startPos}, endPos={endPos}, sourceBuilding={vehicleData.m_sourceBuilding}, targetBuilding={vehicleData.m_targetBuilding}"); #endif #if PATHRECALC @@ -230,6 +230,11 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto VehicleState state = VehicleStateManager.Instance._GetVehicleState(vehicleData.GetFirstVehicle(vehicleID)); ExtCitizenInstance driverExtInstance = state.GetDriverExtInstance(); if (driverExtInstance != null) { +#if DEBUG + if (GlobalConfig.Instance.DebugSwitches[2]) + Log.Warning($"CustomPassengerCarAI.CustomStartPathFind: PathMode={driverExtInstance.PathMode} for vehicle {vehicleID}, driver citizen instance {driverExtInstance.InstanceId}!"); +#endif + switch (driverExtInstance.PathMode) { case ExtPathMode.None: case ExtPathMode.ParkedCarReached: @@ -310,6 +315,11 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto } extPathType = driverExtInstance.GetPathType(); + } else { +#if DEBUG + if (GlobalConfig.Instance.DebugSwitches[2]) + Log.Warning($"CustomPassengerCarAI.CustomStartPathFind: No driver citizen instance found for vehicle {vehicleID}!"); +#endif } } // NON-STOCK CODE END @@ -349,7 +359,7 @@ public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vecto foundStartingPos = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out sqrDistA, out sqrDistB); } - bool foundEndPos = !calculateEndPos || citizenInfo.m_citizenAI.FindPathPosition(driverInstance, ref instance.m_instances.m_buffer[(int)driverInstance], endPos, laneTypes | NetInfo.LaneType.Pedestrian, vehicleType, undergroundTarget, out endPosA); + bool foundEndPos = !calculateEndPos || citizenInfo.m_citizenAI.FindPathPosition(driverInstance, ref instance.m_instances.m_buffer[(int)driverInstance], endPos, Options.prohibitPocketCars ? NetInfo.LaneType.Pedestrian : (laneTypes | NetInfo.LaneType.Pedestrian), vehicleType, undergroundTarget, out endPosA); // NON-STOCK CODE END if (foundStartingPos && @@ -415,7 +425,7 @@ public static bool FindParkingSpaceInVicinity(Vector3 targetPos, VehicleInfo veh float buildingParkOffset; ushort parkingSpaceSegmentId = CustomPassengerCarAI.FindParkingSpaceAtRoadSide(0, targetPos, vehicleInfo.m_generatedInfo.m_size.x, vehicleInfo.m_generatedInfo.m_size.z, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, true, out roadParkPos, out roadParkRot, out roadParkOffset); - ushort parkingBuildingId = CustomPassengerCarAI.FindParkingSpaceAtBuilding(vehicleInfo, homeId, 0, 0, targetPos, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, true, out buildingParkPos, out buildingParkRot, out buildingParkOffset); + ushort parkingBuildingId = CustomPassengerCarAI.FindParkingSpaceAtBuilding(vehicleInfo, homeId, 0, 0, targetPos, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, true, out buildingParkPos, out buildingParkRot, out buildingParkOffset); if (parkingSpaceSegmentId != 0) { if (parkingBuildingId != 0) { @@ -506,18 +516,18 @@ internal static bool FindParkingSpaceProp(ushort ignoreParked, PropInfo info, Ve return false; } - internal static bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, ushort homeID, ushort ignoreParked, ushort segmentId, Vector3 refPos, float maxDistance, out Vector3 parkPos, out Quaternion parkRot, out float parkOffset) { - return FindParkingSpaceAtBuilding(vehicleInfo, homeID, ignoreParked, segmentId, refPos, maxDistance, false, out parkPos, out parkRot, out parkOffset) != 0; + internal static bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, ushort homeID, ushort ignoreParked, ushort segmentId, Vector3 refPos, float maxBuildingDistance, float maxParkingSpaceDistance, out Vector3 parkPos, out Quaternion parkRot, out float parkOffset) { + return FindParkingSpaceAtBuilding(vehicleInfo, homeID, ignoreParked, segmentId, refPos, maxBuildingDistance, maxParkingSpaceDistance, false, out parkPos, out parkRot, out parkOffset) != 0; } - protected static ushort FindParkingSpaceAtBuilding(VehicleInfo vehicleInfo, ushort homeID, ushort ignoreParked, ushort segmentId, Vector3 refPos, float maxDistance, bool randomize, out Vector3 parkPos, out Quaternion parkRot, out float parkOffset) { + protected static ushort FindParkingSpaceAtBuilding(VehicleInfo vehicleInfo, ushort homeID, ushort ignoreParked, ushort segmentId, Vector3 refPos, float maxBuildingDistance, float maxParkingSpaceDistance, bool randomize, out Vector3 parkPos, out Quaternion parkRot, out float parkOffset) { parkPos = Vector3.zero; parkRot = Quaternion.identity; parkOffset = -1f; int centerI = (int)(refPos.z / (float)BuildingManager.BUILDINGGRID_CELL_SIZE + (float)BuildingManager.BUILDINGGRID_RESOLUTION / 2f); int centerJ = (int)(refPos.x / (float)BuildingManager.BUILDINGGRID_CELL_SIZE + (float)BuildingManager.BUILDINGGRID_RESOLUTION / 2f); - int radius = Math.Max(1, (int)(maxDistance / ((float)BuildingManager.BUILDINGGRID_CELL_SIZE / 2f)) + 1); + int radius = Math.Max(1, (int)(maxBuildingDistance / ((float)BuildingManager.BUILDINGGRID_CELL_SIZE / 2f)) + 1); BuildingManager buildingMan = Singleton<BuildingManager>.instance; Randomizer rng = Singleton<SimulationManager>.instance.m_randomizer; @@ -533,7 +543,7 @@ protected static ushort FindParkingSpaceAtBuilding(VehicleInfo vehicleInfo, usho #if DEBUG if (GlobalConfig.Instance.DebugSwitches[4]) { - Log._Debug($"FindParkingSpaceBuilding: Checking building grid @ i={i}, j={j}, index={i * BuildingManager.BUILDINGGRID_RESOLUTION + j} for {refPos}, homeID {homeID}, segment {segmentId}, maxDistance {maxDistance}"); + //Log._Debug($"FindParkingSpaceBuilding: Checking building grid @ i={i}, j={j}, index={i * BuildingManager.BUILDINGGRID_RESOLUTION + j} for {refPos}, homeID {homeID}, segment {segmentId}, maxDistance {maxDistance}"); } #endif @@ -543,14 +553,15 @@ protected static ushort FindParkingSpaceAtBuilding(VehicleInfo vehicleInfo, usho Vector3 innerParkPos; Quaternion innerParkRot; float innerParkOffset; #if DEBUG if (GlobalConfig.Instance.DebugSwitches[4]) { - Log._Debug($"FindParkingSpaceBuilding: Checking building {buildingId} @ i={i}, j={j}, index={i * BuildingManager.BUILDINGGRID_RESOLUTION + j}, for {refPos}, homeID {homeID}, segment {segmentId}, maxDistance {maxDistance}."); + //Log._Debug($"FindParkingSpaceBuilding: Checking building {buildingId} @ i={i}, j={j}, index={i * BuildingManager.BUILDINGGRID_RESOLUTION + j}, for {refPos}, homeID {homeID}, segment {segmentId}, maxDistance {maxDistance}."); } #endif - if (FindParkingSpaceBuilding(vehicleInfo, homeID, ignoreParked, buildingId, ref buildingMan.m_buildings.m_buffer[(int)buildingId], segmentId, refPos, ref maxDistance, out innerParkPos, out innerParkRot, out innerParkOffset)) { + if (FindParkingSpaceBuilding(vehicleInfo, homeID, ignoreParked, buildingId, ref buildingMan.m_buildings.m_buffer[(int)buildingId], segmentId, refPos, ref maxParkingSpaceDistance, randomize, out innerParkPos, out innerParkRot, out innerParkOffset)) { #if DEBUG - if (GlobalConfig.Instance.DebugSwitches[4] && homeID != 0) + /*/if (GlobalConfig.Instance.DebugSwitches[4] && homeID != 0) Log._Debug($"FindParkingSpaceBuilding: Found a parking space for {refPos}, homeID {homeID} @ building {buildingId}, {myParkPos}, offset {myParkOffset}!"); + */ #endif foundBuildingId = buildingId; myParkPos = innerParkPos; @@ -679,7 +690,7 @@ internal static ushort FindParkingSpaceAtRoadSide(ushort ignoreParked, Vector3 r /// <param name="parkRot"></param> /// <param name="parkOffset"></param> /// <returns></returns> - public static bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, ushort homeID, ushort ignoreParked, ushort buildingID, ref Building building, ushort segmentId, Vector3 refPos, ref float maxDistance, out Vector3 parkPos, out Quaternion parkRot, out float parkOffset) { + public static bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, ushort homeID, ushort ignoreParked, ushort buildingID, ref Building building, ushort segmentId, Vector3 refPos, ref float maxDistance, bool randomize, out Vector3 parkPos, out Quaternion parkRot, out float parkOffset) { int buildingWidth = building.Width; int buildingLength = building.Length; @@ -712,50 +723,17 @@ public static bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, ushort home return false; } - if (segmentId != 0) { - // check if building is accessible from the given segment -#if DEBUG - if (GlobalConfig.Instance.DebugSwitches[4]) - Log._Debug($"Checking if building {buildingID} is accessible from segment {segmentId}."); -#endif - - Vector3 unspawnPos; - Vector3 unspawnTargetPos; - building.Info.m_buildingAI.CalculateUnspawnPosition(buildingID, ref building, ref Singleton<SimulationManager>.instance.m_randomizer, vehicleInfo, out unspawnPos, out unspawnTargetPos); - - Vector3 lanePos; uint laneId; int laneIndex; float laneOffset; - // calculate segment offset - if (Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].GetClosestLanePosition(unspawnPos, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, out lanePos, out laneId, out laneIndex, out laneOffset)) { - float dist = (lanePos - unspawnPos).magnitude; -#if DEBUG - if (GlobalConfig.Instance.DebugSwitches[4]) - Log._Debug($"Succeeded in finding unspawn position lane offset for building {buildingID}, segment {segmentId}, unspawnPos={unspawnPos}! lanePos={lanePos}, dist={dist}, laneId={laneId}, laneIndex={laneIndex}, laneOffset={laneOffset}"); -#endif - - /*if (dist > 16f) { - if (GlobalConfig.Instance.DebugSwitches[2]) - Log._Debug($"Distance between unspawn position and lane position is too big! {dist} unspawnPos={unspawnPos} lanePos={lanePos}"); - return false; - }*/ - - parkOffset = laneOffset; - } else { -#if DEBUG - if (GlobalConfig.Instance.DebugSwitches[4]) - Log.Warning($"Could not find unspawn position lane offset for building {buildingID}, segment {segmentId}, unspawnPos={unspawnPos}!"); -#endif - } - } else { + /*else { // NON-STOCK CODE END float diagWidth = Mathf.Sqrt((float)(buildingWidth * buildingWidth + buildingLength * buildingLength)) * 8f; - if (VectorUtils.LengthXZ(building.m_position - refPos) >= maxDistance + diagWidth) { + if (VectorUtils.LengthXZ(building.m_position - refPos) >= maxDistance + diagWidth) {*/ #if DEBUG - if (GlobalConfig.Instance.DebugSwitches[4]) - Log._Debug($"Refusing to find parking space at building {buildingID}! {VectorUtils.LengthXZ(building.m_position - refPos)} >= {maxDistance + diagWidth} (maxDistance={maxDistance})"); + /*if (GlobalConfig.Instance.DebugSwitches[4]) + Log._Debug($"Refusing to find parking space at building {buildingID}! {VectorUtils.LengthXZ(building.m_position - refPos)} >= {maxDistance + diagWidth} (maxDistance={maxDistance})");*/ #endif - return false; + /*return false; } - } // NON-STOCK CODE + }*/ // NON-STOCK CODE Randomizer rng = Singleton<SimulationManager>.instance.m_randomizer; // NON-STOCK CODE @@ -765,13 +743,13 @@ public static bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, ushort home bool result = false; if (buildingInfo.m_class.m_service == ItemClass.Service.Residential && buildingID != homeID && rng.Int32((uint)Options.getRecklessDriverModulo()) != 0) { // NON-STOCK CODE #if DEBUG - if (GlobalConfig.Instance.DebugSwitches[4]) - Log._Debug($"Refusing to find parking space at building {buildingID}! Building is a residential building which does not match home id {homeID}."); + /*if (GlobalConfig.Instance.DebugSwitches[4]) + Log._Debug($"Refusing to find parking space at building {buildingID}! Building is a residential building which does not match home id {homeID}.");*/ #endif - return result; + return false; } - float propMaxDistance = 9999f; // NON-STOCK CODE + float propMinDistance = 9999f; // NON-STOCK CODE if (buildingInfo.m_props != null && (buildingInfo.m_hasParkingSpaces & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { for (int i = 0; i < buildingInfo.m_props.Length; i++) { @@ -789,8 +767,10 @@ public static bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, ushort home transformMatrix.SetTRS(pos, q, Vector3.one); } Vector3 position = transformMatrix.MultiplyPoint(prop.m_position); - if (FindParkingSpaceProp(ignoreParked, propInfo, position, building.m_angle + prop.m_radAngle, prop.m_fixedHeight, refPos, vehicleInfo.m_generatedInfo.m_size.x, vehicleInfo.m_generatedInfo.m_size.z, ref propMaxDistance, ref parkPos, ref parkRot)) { // NON-STOCK CODE + if (FindParkingSpaceProp(ignoreParked, propInfo, position, building.m_angle + prop.m_radAngle, prop.m_fixedHeight, refPos, vehicleInfo.m_generatedInfo.m_size.x, vehicleInfo.m_generatedInfo.m_size.z, ref propMinDistance, ref parkPos, ref parkRot)) { // NON-STOCK CODE result = true; + if (randomize && propMinDistance <= maxDistance && rng.Int32(GlobalConfig.Instance.VicinityParkingSpaceSelectionRand) != 0) + break; } } } @@ -798,9 +778,57 @@ public static bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, ushort home } } - maxDistance = propMaxDistance; // NON-STOCK CODE + if (result && propMinDistance <= maxDistance) { + maxDistance = propMinDistance; // NON-STOCK CODE +#if DEBUG + if (GlobalConfig.Instance.DebugSwitches[4]) + Log._Debug($"Found parking space prop in range ({maxDistance}) at building {buildingID}."); +#endif + if (segmentId != 0) { + // check if building is accessible from the given segment +#if DEBUG + if (GlobalConfig.Instance.DebugSwitches[4]) + Log._Debug($"Calculating unspawn position of building {buildingID} for segment {segmentId}."); +#endif + + Vector3 unspawnPos; + Vector3 unspawnTargetPos; + building.Info.m_buildingAI.CalculateUnspawnPosition(buildingID, ref building, ref Singleton<SimulationManager>.instance.m_randomizer, vehicleInfo, out unspawnPos, out unspawnTargetPos); + + Vector3 lanePos; + uint laneId; + int laneIndex; + float laneOffset; + // calculate segment offset + if (Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].GetClosestLanePosition(unspawnPos, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, out lanePos, out laneId, out laneIndex, out laneOffset)) { +#if DEBUG + if (GlobalConfig.Instance.DebugSwitches[4]) + Log._Debug($"Succeeded in finding unspawn position lane offset for building {buildingID}, segment {segmentId}, unspawnPos={unspawnPos}! lanePos={lanePos}, dist={(lanePos - unspawnPos).magnitude}, laneId={laneId}, laneIndex={laneIndex}, laneOffset={laneOffset}"); +#endif - return result; + /*if (dist > 16f) { + if (GlobalConfig.Instance.DebugSwitches[2]) + Log._Debug($"Distance between unspawn position and lane position is too big! {dist} unspawnPos={unspawnPos} lanePos={lanePos}"); + return false; + }*/ + + parkOffset = laneOffset; + } else { +#if DEBUG + if (GlobalConfig.Instance.DebugSwitches[2]) + Log.Warning($"Could not find unspawn position lane offset for building {buildingID}, segment {segmentId}, unspawnPos={unspawnPos}!"); +#endif + } + } + + return true; + } else { +#if DEBUG + if (result && GlobalConfig.Instance.DebugSwitches[2]) + Log._Debug($"Could not find parking space prop in range ({maxDistance}) at building {buildingID}."); +#endif + return false; + } } /// <summary> @@ -886,7 +914,7 @@ public bool CustomParkVehicle(ushort vehicleID, ref Vehicle vehicleData, PathUni if (Options.prohibitPocketCars) { state = VehicleStateManager.Instance._GetVehicleState(vehicleData.GetFirstVehicle(vehicleID)); driverExtInstance = ExtCitizenInstanceManager.Instance.GetExtInstance(driverCitizenInstanceId); - prohibitPocketCars = driverExtInstance != null; + prohibitPocketCars = driverExtInstance != null; // TODO why would this be null?? } uint laneID = PathManager.GetLaneID(pathPos); @@ -922,7 +950,7 @@ public bool CustomParkVehicle(ushort vehicleID, ref Vehicle vehicleData, PathUni if (prohibitPocketCars) { #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) - Log._Debug($"Vehicle {vehicleID} tries to park on a parking position now! path={vehicleData.m_path} pathPositionIndex={vehicleData.m_pathPositionIndex} segmentId={pathPos.m_segment} laneIndex={pathPos.m_lane} offset={pathPos.m_offset} nextPath={nextPath} refPos={refPos} searchDir={searchDir} home={homeID}"); + Log._Debug($"Vehicle {vehicleID} tries to park on a parking position now (flags: {vehicleData.m_flags})! CurrentPathMode={driverExtInstance.PathMode} path={vehicleData.m_path} pathPositionIndex={vehicleData.m_pathPositionIndex} segmentId={pathPos.m_segment} laneIndex={pathPos.m_lane} offset={pathPos.m_offset} nextPath={nextPath} refPos={refPos} searchDir={searchDir} home={homeID}"); #endif if (driverExtInstance.PathMode == ExtCitizenInstance.ExtPathMode.DrivingToAltParkPos || driverExtInstance.PathMode == ExtCitizenInstance.ExtPathMode.DrivingToKnownParkPos) { @@ -947,7 +975,7 @@ public bool CustomParkVehicle(ushort vehicleID, ref Vehicle vehicleData, PathUni if (GlobalConfig.Instance.DebugSwitches[2]) Log._Debug($"Vehicle {vehicleID} wants to park @ building {driverExtInstance.ParkingSpaceLocationId}"); #endif - foundParkingSpace = FindParkingSpaceBuilding(this.m_info, homeID, 0, driverExtInstance.ParkingSpaceLocationId, ref Singleton<BuildingManager>.instance.m_buildings.m_buffer[driverExtInstance.ParkingSpaceLocationId], pathPos.m_segment, refPos, ref maxDist, out parkPos, out parkRot, out parkOffset); + foundParkingSpace = FindParkingSpaceBuilding(this.m_info, homeID, 0, driverExtInstance.ParkingSpaceLocationId, ref Singleton<BuildingManager>.instance.m_buildings.m_buffer[driverExtInstance.ParkingSpaceLocationId], pathPos.m_segment, refPos, ref maxDist, true, out parkPos, out parkRot, out parkOffset); break; default: #if DEBUG @@ -960,9 +988,9 @@ public bool CustomParkVehicle(ushort vehicleID, ref Vehicle vehicleData, PathUni } if (! foundParkingSpace) { - foundParkingSpace = Options.prohibitPocketCars ? + foundParkingSpace = prohibitPocketCars ? CustomFindParkingSpace(this.m_info, homeID, refPos, searchDir, pathPos.m_segment, out parkPos, out parkRot, out parkOffset) : - foundParkingSpace = FindParkingSpace(homeID, refPos, searchDir, pathPos.m_segment, this.m_info.m_generatedInfo.m_size.x, this.m_info.m_generatedInfo.m_size.z, out parkPos, out parkRot, out parkOffset); + FindParkingSpace(homeID, refPos, searchDir, pathPos.m_segment, this.m_info.m_generatedInfo.m_size.x, this.m_info.m_generatedInfo.m_size.z, out parkPos, out parkRot, out parkOffset); } // NON-STOCK CODE END @@ -996,19 +1024,20 @@ public bool CustomParkVehicle(ushort vehicleID, ref Vehicle vehicleData, PathUni } else if (prohibitPocketCars) { // could not find parking space. vehicle would despawn. + // Find parking space in the vicinity, redo path-finding to the parking space, park the vehicle and do citizen path-finding to the current target + if ((driverExtInstance.PathMode == ExtCitizenInstance.ExtPathMode.DrivingToAltParkPos || driverExtInstance.PathMode == ExtCitizenInstance.ExtPathMode.DrivingToKnownParkPos) && targetBuildingId != 0) { // increase parking space demand of target building - ExtBuildingManager.Instance.GetExtBuilding(targetBuildingId).AddParkingSpaceDemand(GlobalConfig.Instance.FailedParkingSpaceDemandIncrement); + ExtBuildingManager.Instance.GetExtBuilding(targetBuildingId).AddParkingSpaceDemand(GlobalConfig.Instance.FailedParkingSpaceDemandIncrement * (uint)driverExtInstance.FailedParkingAttempts); } - // Find parking space in the vicinity, redo path-finding to the parking space, park the vehicle and do citizen path-finding to the current target ++driverExtInstance.FailedParkingAttempts; driverExtInstance.PathMode = ExtCitizenInstance.ExtPathMode.ParkingFailed; // TODO if NOT ... ? driverExtInstance.ParkingPathStartPosition = pathPos; #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) - Log._Debug($"Parking failed for vehicle {vehicleID}! pathPos segment={pathPos.m_segment}, lane={pathPos.m_lane}, offset={pathPos.m_offset}. Trying to find parking space in the vicinity. FailedParkingAttempts={driverExtInstance.FailedParkingAttempts}, CurrentPathMode={driverExtInstance.PathMode} foundParkingSpace={foundParkingSpace}"); + Log._Debug($"Parking failed for vehicle {vehicleID}! (flags: {vehicleData.m_flags}) pathPos segment={pathPos.m_segment}, lane={pathPos.m_lane}, offset={pathPos.m_offset}. Trying to find parking space in the vicinity. FailedParkingAttempts={driverExtInstance.FailedParkingAttempts}, CurrentPathMode={driverExtInstance.PathMode} foundParkingSpace={foundParkingSpace}"); #endif // invalidate paths of all passengers in order to force path recalculation @@ -1021,10 +1050,21 @@ public bool CustomParkVehicle(ushort vehicleID, ref Vehicle vehicleData, PathUni if (curCitizenId != 0u) { ushort citizenInstanceId = citizenManager.m_citizens.m_buffer[curCitizenId].m_instance; if (citizenInstanceId != 0) { + #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) Log._Debug($"Releasing path for citizen instance {citizenInstanceId} sitting in vehicle {vehicleID} (was {citizenManager.m_instances.m_buffer[citizenInstanceId].m_path})."); #endif + if (citizenInstanceId != driverCitizenInstanceId) { + ExtCitizenInstance extPassengerInstance = ExtCitizenInstanceManager.Instance.GetExtInstance(citizenInstanceId); +#if DEBUG + if (GlobalConfig.Instance.DebugSwitches[2]) + Log._Debug($"Resetting pathmode for passenger citizen instance {citizenInstanceId} sitting in vehicle {vehicleID} (was {extPassengerInstance.PathMode})."); +#endif + + extPassengerInstance.Reset(); + } + if (citizenManager.m_instances.m_buffer[citizenInstanceId].m_path != 0) { Singleton<PathManager>.instance.ReleasePath(citizenManager.m_instances.m_buffer[citizenInstanceId].m_path); citizenManager.m_instances.m_buffer[citizenInstanceId].m_path = 0u; @@ -1108,7 +1148,7 @@ public bool CustomParkVehicle(ushort vehicleID, ref Vehicle vehicleData, PathUni } private static bool CustomFindParkingSpace(VehicleInfo vehicleInfo, ushort homeID, Vector3 refPos, Vector3 searchDir, ushort segment, out Vector3 parkPos, out Quaternion parkRot, out float parkOffset) { - float searchRadius = 16f; + float searchRadius = Options.prohibitPocketCars ? 32f : 16f; uint chanceOfParkingOffRoad = 3u; Vector3 searchMagnitude = refPos + searchDir * 16f; @@ -1139,11 +1179,11 @@ private static bool CustomFindParkingSpace(VehicleInfo vehicleInfo, ushort homeI if (FindParkingSpaceRoadSide(0, segment, refPos, width - 0.2f, length, out parkPos, out parkRot, out parkOffset)) { return true; } - if (FindParkingSpaceBuilding(vehicleInfo, homeID, 0, segment, refPos2, searchRadius, out parkPos, out parkRot, out parkOffset)) { + if (FindParkingSpaceBuilding(vehicleInfo, homeID, 0, segment, refPos2, GlobalConfig.Instance.MaxBuildingToPedestrianLaneDistance, searchRadius, out parkPos, out parkRot, out parkOffset)) { return true; } } else { - if (FindParkingSpaceBuilding(vehicleInfo, homeID, 0, segment, refPos2, searchRadius, out parkPos, out parkRot, out parkOffset)) { + if (FindParkingSpaceBuilding(vehicleInfo, homeID, 0, segment, refPos2, GlobalConfig.Instance.MaxBuildingToPedestrianLaneDistance, searchRadius, out parkPos, out parkRot, out parkOffset)) { return true; } diff --git a/TLM/TLM/Custom/AI/CustomResidentAI.cs b/TLM/TLM/Custom/AI/CustomResidentAI.cs index 3787b0ae..d041c8d9 100644 --- a/TLM/TLM/Custom/AI/CustomResidentAI.cs +++ b/TLM/TLM/Custom/AI/CustomResidentAI.cs @@ -132,7 +132,13 @@ public VehicleInfo CustomGetVehicleInfo(ushort instanceID, ref CitizenInstance c } // NON-STOCK CODE START + bool forceTaxi = false; if (Options.prohibitPocketCars) { + ExtCitizenInstance extInstance = ExtCitizenInstanceManager.Instance.GetExtInstance(instanceID); + if (extInstance.PathMode == ExtPathMode.TaxiToTarget) { + forceTaxi = true; + } + ushort parkedVehicleId = Singleton<CitizenManager>.instance.m_citizens.m_buffer[citizenData.m_citizen].m_parkedVehicle; if (parkedVehicleId != 0) { #if DEBUG @@ -149,7 +155,11 @@ public VehicleInfo CustomGetVehicleInfo(ushort instanceID, ref CitizenInstance c int carProb; int bikeProb; int taxiProb; - if (forceProbability || (citizenData.m_flags & CitizenInstance.Flags.BorrowCar) != CitizenInstance.Flags.None) { + if (forceTaxi) { + carProb = 0; + bikeProb = 0; + taxiProb = 100; + } else if (forceProbability || (citizenData.m_flags & CitizenInstance.Flags.BorrowCar) != CitizenInstance.Flags.None) { carProb = 100; bikeProb = 0; taxiProb = 0; diff --git a/TLM/TLM/Custom/PathFinding/CustomPathFind.cs b/TLM/TLM/Custom/PathFinding/CustomPathFind.cs index 87d89fcc..d382bf01 100644 --- a/TLM/TLM/Custom/PathFinding/CustomPathFind.cs +++ b/TLM/TLM/Custom/PathFinding/CustomPathFind.cs @@ -31,6 +31,7 @@ private struct BufferItem { public uint m_laneID; public NetInfo.Direction m_direction; public NetInfo.LaneType m_lanesUsed; + public VehicleInfo.VehicleType m_vehiclesUsed; public uint m_numSegmentsToJunction; } @@ -106,6 +107,7 @@ private bool Terminated { private ushort? _vehicleId; private ExtCitizenInstance.ExtPathType? _extPathType; private bool _allowEscapeTransport; + private bool _leftHandDrive; //private bool _extPublicTransport; private float _vehicleCosts; private static ushort laneChangeRandCounter = 0; @@ -323,6 +325,7 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { this._vehicleId = CustomPathManager._instance.pathUnitVehicleIds[unit]; this._extPathType = CustomPathManager._instance.pathUnitPathTypes[unit]; this._allowEscapeTransport = CustomPathManager._instance.pathUnitEscapeTransport[unit]; + this._leftHandDrive = TrafficPriorityManager.IsLeftHandDrive(); //this._extPublicTransport = _extVehicleType != null && (_extVehicleType & ExtVehicleType.PublicTransport) != ExtVehicleType.None; #if DEBUGPF //Log._Debug($"CustomPathFind.PathFindImplementation: path unit {unit}, type {_extVehicleType}"); @@ -346,7 +349,7 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { this._startOffsetA = data.m_position00.m_offset; bufferItemStartA.m_laneID = this._startLaneA; bufferItemStartA.m_position = data.m_position00; - this.GetLaneDirection(data.m_position00, out bufferItemStartA.m_direction, out bufferItemStartA.m_lanesUsed); + this.GetLaneDirection(data.m_position00, out bufferItemStartA.m_direction, out bufferItemStartA.m_lanesUsed, out bufferItemStartA.m_vehiclesUsed); bufferItemStartA.m_comparisonValue = 0f; bufferItemStartA.m_numSegmentsToJunction = 0; } else { @@ -362,7 +365,7 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { this._startOffsetB = data.m_position02.m_offset; bufferItemStartB.m_laneID = this._startLaneB; bufferItemStartB.m_position = data.m_position02; - this.GetLaneDirection(data.m_position02, out bufferItemStartB.m_direction, out bufferItemStartB.m_lanesUsed); + this.GetLaneDirection(data.m_position02, out bufferItemStartB.m_direction, out bufferItemStartB.m_lanesUsed, out bufferItemStartB.m_vehiclesUsed); bufferItemStartB.m_comparisonValue = 0f; bufferItemStartB.m_numSegmentsToJunction = 0; } else { @@ -376,7 +379,7 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { this._endLaneA = PathManager.GetLaneID(data.m_position01); bufferItemEndA.m_laneID = this._endLaneA; bufferItemEndA.m_position = data.m_position01; - this.GetLaneDirection(data.m_position01, out bufferItemEndA.m_direction, out bufferItemEndA.m_lanesUsed); + this.GetLaneDirection(data.m_position01, out bufferItemEndA.m_direction, out bufferItemEndA.m_lanesUsed, out bufferItemEndA.m_vehiclesUsed); bufferItemEndA.m_methodDistance = 0.01f; bufferItemEndA.m_comparisonValue = 0f; bufferItemEndA.m_numSegmentsToJunction = 0; @@ -389,7 +392,7 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { this._endLaneB = PathManager.GetLaneID(data.m_position03); bufferItemEndB.m_laneID = this._endLaneB; bufferItemEndB.m_position = data.m_position03; - this.GetLaneDirection(data.m_position03, out bufferItemEndB.m_direction, out bufferItemEndB.m_lanesUsed); + this.GetLaneDirection(data.m_position03, out bufferItemEndB.m_direction, out bufferItemEndB.m_lanesUsed, out bufferItemEndB.m_vehiclesUsed); bufferItemEndB.m_methodDistance = 0.01f; bufferItemEndB.m_comparisonValue = 0f; bufferItemEndB.m_numSegmentsToJunction = 0; @@ -538,9 +541,10 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { float totalPathLength = finalBufferItem.m_comparisonValue * this._maxLength; this.PathUnits.m_buffer[unit].m_length = totalPathLength; this.PathUnits.m_buffer[unit].m_laneTypes = (byte)finalBufferItem.m_lanesUsed; // NON-STOCK CODE + this.PathUnits.m_buffer[unit].m_vehicleTypes = (byte)finalBufferItem.m_vehiclesUsed; // NON-STOCK CODE #if DEBUG if (_conf.DebugSwitches[4]) - Log._Debug($"Lane types of path unit {unit}: {finalBufferItem.m_lanesUsed}"); + Log._Debug($"Lane/Vehicle types of path unit {unit}: {finalBufferItem.m_lanesUsed} / {finalBufferItem.m_vehiclesUsed}"); #endif uint currentPathUnitId = unit; int currentItemPositionCount = 0; @@ -626,6 +630,7 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { this.PathUnits.m_buffer[currentPathUnitId].m_nextPathUnit = createdPathUnitId; this.PathUnits.m_buffer[currentPathUnitId].m_positionCount = (byte)currentItemPositionCount; this.PathUnits.m_buffer[currentPathUnitId].m_laneTypes = (byte)finalBufferItem.m_lanesUsed; // NON-STOCK CODE (this is not accurate!) + this.PathUnits.m_buffer[currentPathUnitId].m_vehicleTypes = (byte)finalBufferItem.m_vehiclesUsed; // NON-STOCK CODE (this is not accurate!) sumOfPositionCounts += currentItemPositionCount; Singleton<PathManager>.instance.m_pathUnitCount = (int)(this.PathUnits.ItemCount() - 1u); } catch (Exception e) { @@ -664,11 +669,13 @@ protected void PathFindImplementation(uint unit, ref PathUnit data) { // 1 private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSegment, ushort nextNodeId, ref NetNode nextNode, byte connectOffset, bool isMiddle) { -#if DEBUGPF +#if DEBUGPF && DEBUG //bool debug = _conf.DebugSwitches[0] && item.m_position.m_segment == 1459 && nextNodeId == 19630; //bool debug = _conf.DebugSwitches[0] && (item.m_position.m_segment == 3833 || item.m_position.m_segment == 9649); bool debug = _conf.DebugSwitches[0] && nextNodeId == _conf.PathFindDebugNodeId; //bool debug = _conf.DebugSwitches[0] && ((nextNodeId == 27237 && item.m_position.m_segment == 5699) || (nextNodeId == 16068 && item.m_position.m_segment == 24398) || (nextNodeId == 12825 && item.m_position.m_segment == 17008)); +#else + bool debug = false; #endif #if DEBUGPF /*if (m_queuedPathFindCount > 100 && _conf.DebugSwitches[0]) @@ -680,9 +687,6 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe List<String> logBuf = null; if (debug) logBuf = new List<String>(); - //bool debug = nextNodeId == 12732; -#else - bool debug = false; #endif #if DEBUGPF2 @@ -920,22 +924,26 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe bool nextIsJunction = (nextNode.m_flags & NetNode.Flags.Junction) != NetNode.Flags.None; bool nextIsTransition = (nextNode.m_flags & NetNode.Flags.Transition) != NetNode.Flags.None; bool nextIsStartNodeOfPrevSegment = prevSegment.m_startNode == nextNodeId; - //NetInfo.Direction normDirection = NetInfo.Direction.Backward;// TrafficPriority.IsLeftHandDrive() ? NetInfo.Direction.Forward : NetInfo.Direction.Backward; // direction to normalize indices to - bool isStrictLaneArrowPolicyEnabled = - (_extVehicleType != ExtVehicleType.Emergency || _conf.DebugSwitches[3]) && + bool isStrictLaneArrowPolicyEnabled = + (_extVehicleType != ExtVehicleType.Emergency +#if DEBUG + || _conf.DebugSwitches[3] +#endif + ) && (nextIsJunction || nextIsTransition) && - //!Options.allRelaxed && - !(Options.allRelaxed || (Options.relaxedBusses && _extVehicleType == ExtVehicleType.Bus)) && + !( +#if DEBUG + Options.allRelaxed || +#endif + (Options.relaxedBusses && _extVehicleType == ExtVehicleType.Bus)) && (this._vehicleTypes & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None; // get segment geometry - //SegmentGeometry geometry = IsMasterPathFind ? SegmentGeometry.Get(prevSegmentId, nextNodeId) : SegmentGeometry.Get(prevSegmentId); SegmentGeometry prevGeometry = SegmentGeometry.Get(prevSegmentId); bool nextIsRealJunction = prevGeometry.CountOtherSegments(nextIsStartNodeOfPrevSegment) > 1; bool prevIsOutgoingOneWay = prevGeometry.IsOutgoingOneWay(nextIsStartNodeOfPrevSegment); bool prevIsHighway = prevGeometry.IsHighway(); - bool prevHasBusLane = prevGeometry.HasBusLane(); bool nextAreOnlyOneWayHighways = prevGeometry.HasOnlyHighways(nextIsStartNodeOfPrevSegment); short prevOuterSimilarLaneIndex; @@ -953,6 +961,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe int totalIncomingLanes = 0; // running number of next incoming lanes (number is updated at each segment iteration) int totalOutgoingLanes = 0; // running number of next outgoing lanes (number is updated at each segment iteration) + // determine incoming segment ids ushort[] incomingStraightSegments = null; // ids of incoming straight segments ushort[] incomingRightSegments = null; // ids of incoming right segments ushort[] incomingLeftSegments = null; // ids of incoming left segments @@ -973,11 +982,12 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe (_extVehicleType & ExtVehicleType.RoadVehicle) != ExtVehicleType.None); bool nextIsSimpleJunction = false; - if (Options.highwayRules && (netManager.m_nodes.m_buffer[nextNodeId].m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None) { + if (Options.highwayRules && (nextNode.m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None) { // determine if junction is a simple junction (highway rules only apply to simple junctions) nextIsSimpleJunction = NodeGeometry.Get(nextNodeId).IsSimpleJunction; } + // determine if highway rules should be applied bool applyHighwayRules = Options.highwayRules && nextIsSimpleJunction && nextAreOnlyOneWayHighways && prevIsOutgoingOneWay && prevIsHighway; bool applyHighwayRulesAtJunction = applyHighwayRules && nextIsRealJunction; @@ -985,7 +995,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe if (explorePrevSegment) { nextSegmentId = prevSegmentId; } else { - if (TrafficPriorityManager.IsLeftHandDrive()) { + if (_leftHandDrive) { nextSegmentId = prevSegment.GetLeftSegment(nextNodeId); } else { nextSegmentId = prevSegment.GetRightSegment(nextNodeId); @@ -1089,6 +1099,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe bool nextIsHighway = nextGeometry.IsHighway(); bool nextIsStartNodeOfNextSegment = netManager.m_segments.m_buffer[nextSegmentId].m_startNode == nextNodeId; + // determine next segment direction by evaluating the geometry information if (nextSegmentId != prevSegmentId) { for (int j = 0; j < incomingStraightSegments.Length; ++j) { if (incomingStraightSegments[j] == nextSegmentId) @@ -1146,21 +1157,6 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe // determine valid lanes based on lane arrows NetInfo.Lane nextLane = nextSegmentInfo.m_lanes[laneIndex]; - - bool nextHasOutgoingConnections = false; - bool nextIsConnectedWithPrev = true; - if (Options.laneConnectorEnabled) { - nextHasOutgoingConnections = laneConnManager.HasConnections(curLaneId, nextIsStartNodeOfNextSegment); - if (nextHasOutgoingConnections) { - hasLaneConnections = true; - nextIsConnectedWithPrev = laneConnManager.AreLanesConnected(curLaneId, item.m_laneID, nextIsStartNodeOfNextSegment); - } -#if DEBUGPF - if (debug) { - logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment} (lane {item.m_laneID}), lane id {item.m_position.m_lane}, {prevOuterSimilarLaneIndex} from outer: Lane Iteration {laneIndex}. nextSegmentId={nextSegmentId}, curLaneId={curLaneId}, nextHasOutgoingConnections={nextHasOutgoingConnections}, nextIsConnectedWithPrev={nextIsConnectedWithPrev}"); - } -#endif - } #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevOuterSimilarLaneIndex} from outer: Lane Iteration {laneIndex}. nextSegmentId={nextSegmentId}, curLaneId={curLaneId} nextIsIncomingLane={(byte)(nextLane.m_finalDirection & nextDir2) != 0} nextIsCompatibleLane={nextLane.CheckType(drivingEnabledLaneTypes, _vehicleTypes)}"); @@ -1185,67 +1181,73 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe nextInnerSimilarLaneIndex = (byte)(nextLane.m_similarLaneCount - nextLane.m_similarLaneIndex - 1); } - /*bool nextIsBusLane = (nextLane.m_laneType == NetInfo.LaneType.TransportVehicle && (nextLane.m_vehicleType & this._vehicleTypes & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None); - if (nextIsBusLane && (Options.relaxedBusses && _extVehicleType == ExtVehicleType.Bus)) { - // busses may ignore lane arrows at the next lane - if (ProcessItemCosts(true, true, debug, item, nextNodeId, nextSegmentId, ref netManager.m_segments.m_buffer[nextSegmentId], ref similarLaneIndexFromInner, connectOffset, true, false, laneIndex, curLaneId, out foundForced)) { - mayTurnAround = true; + // check for drag&drop lane connections + bool nextHasOutgoingConnections = false; + bool nextIsConnectedWithPrev = true; + if (Options.laneConnectorEnabled) { + nextHasOutgoingConnections = laneConnManager.HasConnections(curLaneId, nextIsStartNodeOfNextSegment); + if (nextHasOutgoingConnections) { + hasLaneConnections = true; + nextIsConnectedWithPrev = laneConnManager.AreLanesConnected(curLaneId, item.m_laneID, nextIsStartNodeOfNextSegment); } - } else {*/ - bool hasLeftArrow = ((NetLane.Flags)netManager.m_lanes.m_buffer[curLaneId].m_flags & NetLane.Flags.Left) == NetLane.Flags.Left; - bool hasRightArrow = ((NetLane.Flags)netManager.m_lanes.m_buffer[curLaneId].m_flags & NetLane.Flags.Right) == NetLane.Flags.Right; - bool hasForwardArrow = ((NetLane.Flags)netManager.m_lanes.m_buffer[curLaneId].m_flags & NetLane.Flags.Forward) != NetLane.Flags.None || ((NetLane.Flags)netManager.m_lanes.m_buffer[curLaneId].m_flags & NetLane.Flags.LeftForwardRight) == NetLane.Flags.None; #if DEBUGPF if (debug) { - if (hasLeftArrow) { - logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has LEFT arrow. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); - } - - if (hasRightArrow) { - logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has RIGHT arrow. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); - } - - if (hasForwardArrow) { - logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has FORWARD arrow. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); - } + logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment} (lane {item.m_laneID}), lane id {item.m_position.m_lane}, {prevOuterSimilarLaneIndex} from outer: Lane Iteration {laneIndex}. nextSegmentId={nextSegmentId}, curLaneId={curLaneId}, nextHasOutgoingConnections={nextHasOutgoingConnections}, nextIsConnectedWithPrev={nextIsConnectedWithPrev}"); } #endif + } - /*bool isValidIncomingRight = isIncomingRight && hasLeftArrow; - bool isValidIncomingLeft = isIncomingLeft && hasRightArrow; - bool isValidIncomingStraight = isIncomingStraight && hasForwardArrow; - bool isValidIncomingTurn = isIncomingTurn && ((TrafficPriority.IsLeftHandDrive() && hasRightArrow) || (!TrafficPriority.IsLeftHandDrive() && hasLeftArrow));*/ - + // check for lane arrows + bool hasLeftArrow = false; + bool hasRightArrow = false; + bool hasForwardArrow = false; + if (!nextHasOutgoingConnections) { + NetLane.Flags curLaneFlags = (NetLane.Flags)netManager.m_lanes.m_buffer[curLaneId].m_flags; + hasLeftArrow = (curLaneFlags & NetLane.Flags.Left) == NetLane.Flags.Left; + hasRightArrow = (curLaneFlags & NetLane.Flags.Right) == NetLane.Flags.Right; + hasForwardArrow = (curLaneFlags & NetLane.Flags.Forward) != NetLane.Flags.None || (curLaneFlags & NetLane.Flags.LeftForwardRight) == NetLane.Flags.None; + } #if DEBUGPF - /*if (debug) - logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex}. isValidIncomingRight? {isValidIncomingRight}, isValidIncomingLeft? {isValidIncomingLeft}, isValidIncomingStraight? {isValidIncomingStraight} isValidIncomingTurn? {isValidIncomingTurn}");*/ -#endif + if (debug) { + if (hasLeftArrow) { + logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has LEFT arrow and was not touched by the lane connector. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); + } - // add valid next lanes - if ( - (nextHasOutgoingConnections && nextIsConnectedWithPrev) || // lanes are connected - applyHighwayRules || // highway rules enabled - (isIncomingRight && hasLeftArrow) || // valid incoming right - (isIncomingLeft && hasRightArrow) || // valid incoming left - (isIncomingStraight && hasForwardArrow) || // valid incoming straight - (isIncomingTurn && ((TrafficPriorityManager.IsLeftHandDrive() && hasRightArrow) || (!TrafficPriorityManager.IsLeftHandDrive() && hasLeftArrow))) // valid turning lane - ) { // valid incoming turn + if (hasRightArrow) { + logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has RIGHT arrow and was not touched by the lane connector. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); + } - laneIndexes[curLaneI] = laneIndex; - laneIds[curLaneI] = curLaneId; - nextOuterLaneSimilarIndexes[curLaneI] = nextOuterSimilarLaneIndex; - nextInnerLaneSimilarIndexes[curLaneI] = nextInnerSimilarLaneIndex; - laneIndexByOuterSimilarIndex[nextOuterSimilarLaneIndex] = curLaneI; - hasOutgoingConnections[curLaneI] = nextHasOutgoingConnections; - nextIsConnectedWithPrevious[curLaneI] = nextIsConnectedWithPrev; - compatibleOuterSimilarIndexesMask |= POW2MASKS[nextOuterSimilarLaneIndex]; + if (hasForwardArrow) { + logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has FORWARD arrow and was not touched by the lane connector. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); + } + } +#endif + + // add valid next lanes + if ( + (nextHasOutgoingConnections && nextIsConnectedWithPrev) || // lanes are connected manually + (!nextHasOutgoingConnections && ( // lane does not have manual connections + applyHighwayRules || // highway rules enabled + (isIncomingRight && hasLeftArrow) || // valid incoming right + (isIncomingLeft && hasRightArrow) || // valid incoming left + (isIncomingStraight && hasForwardArrow) || // valid incoming straight + (isIncomingTurn && ((_leftHandDrive && hasRightArrow) || (!_leftHandDrive && hasLeftArrow))))) // valid turning lane + ) { // valid incoming turn + + laneIndexes[curLaneI] = laneIndex; + laneIds[curLaneI] = curLaneId; + nextOuterLaneSimilarIndexes[curLaneI] = nextOuterSimilarLaneIndex; + nextInnerLaneSimilarIndexes[curLaneI] = nextInnerSimilarLaneIndex; + laneIndexByOuterSimilarIndex[nextOuterSimilarLaneIndex] = curLaneI; + hasOutgoingConnections[curLaneI] = nextHasOutgoingConnections; + nextIsConnectedWithPrevious[curLaneI] = nextIsConnectedWithPrev; + compatibleOuterSimilarIndexesMask |= POW2MASKS[nextOuterSimilarLaneIndex]; #if DEBUGPF - if (debug) - logBuf.Add($"Adding lane #{curLaneI} (id {curLaneId}, idx {laneIndex}), outer sim. idx: {nextOuterSimilarLaneIndex}, inner sim. idx.: {nextInnerSimilarLaneIndex}"); + if (debug) + logBuf.Add($"Adding lane #{curLaneI} (id {curLaneId}, idx {laneIndex}), outer sim. idx: {nextOuterSimilarLaneIndex}, inner sim. idx.: {nextInnerSimilarLaneIndex}"); #endif - curLaneI++; - } - //} + ++curLaneI; + } } else { ++outgoingVehicleLanes; } @@ -1422,7 +1424,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe #if DEBUGPF if (debug) - logBuf.Add($"Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane idx {item.m_position.m_lane}, {prevOuterSimilarLaneIndex} from outer. There are {curLaneI} candidate lanes. We choose lane {nextLaneI} (index {nextLaneIndex}, {nextOuterSimilarIndex} compatible from outer). lhd: {TrafficPriorityManager.IsLeftHandDrive()}, ped: {allowPedSwitch}, magical flag4: {mayTurnAround}"); + logBuf.Add($"Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane idx {item.m_position.m_lane}, {prevOuterSimilarLaneIndex} from outer. There are {curLaneI} candidate lanes. We choose lane {nextLaneI} (index {nextLaneIndex}, {nextOuterSimilarIndex} compatible from outer). lhd: {_leftHandDrive}, ped: {allowPedSwitch}, magical flag4: {mayTurnAround}"); #endif #if DEBUGPF @@ -1482,9 +1484,10 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe bool mayChangeLanes = isIncomingStraight && Flags.getStraightLaneChangingAllowed(nextSegmentId, nextIsStartNodeOfPrevSegment); #if DEBUGPF if (debug) - logBuf.Add($"Next is real junction. minNextOuterSimilarIndex={minNextOuterSimilarIndex}, maxNextOuterSimilarIndex={maxNextOuterSimilarIndex} prevHasBusLane={prevHasBusLane} mayChangeLanes={mayChangeLanes}"); + logBuf.Add($"Next is real junction. minNextOuterSimilarIndex={minNextOuterSimilarIndex}, maxNextOuterSimilarIndex={maxNextOuterSimilarIndex} prevHasBusLane={prevGeometry.HasBusLane()} mayChangeLanes={mayChangeLanes}"); #endif if (!mayChangeLanes) { + bool prevHasBusLane = prevGeometry.HasBusLane(); bool nextHasBusLane = nextGeometry.HasBusLane(); if (nextHasBusLane && !prevHasBusLane) { // allow vehicles on the bus lane AND on the next lane to merge on this lane @@ -1554,7 +1557,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe #if DEBUGPF if (debug) - logBuf.Add($"Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane idx {item.m_position.m_lane}, {prevOuterSimilarLaneIndex} from outer. There are {curLaneI} candidate lanes. We choose lane {nextLaneI} (index {nextLaneIndex}, {nextOuterSimilarIndex} compatible from outer). lhd: {TrafficPriorityManager.IsLeftHandDrive()}, ped: {allowPedSwitch}, magical flag4: {mayTurnAround}"); + logBuf.Add($"Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane idx {item.m_position.m_lane}, {prevOuterSimilarLaneIndex} from outer. There are {curLaneI} candidate lanes. We choose lane {nextLaneI} (index {nextLaneIndex}, {nextOuterSimilarIndex} compatible from outer). lhd: {_leftHandDrive}, ped: {allowPedSwitch}, magical flag4: {mayTurnAround}"); #endif #if DEBUGPF if (debug) { @@ -1685,7 +1688,7 @@ private void ProcessItemMain(uint unitId, BufferItem item, ref NetSegment prevSe if (nextSegmentId == prevSegmentId) similarLaneIndexFromInner = firstSimilarLaneIndexFromInner; // u-turning does not "consume" a lane - if (TrafficPriorityManager.IsLeftHandDrive()) { + if (_leftHandDrive) { nextSegmentId = netManager.m_segments.m_buffer[nextSegmentId].GetLeftSegment(nextNodeId); } else { nextSegmentId = netManager.m_segments.m_buffer[nextSegmentId].GetRightSegment(nextNodeId); @@ -2056,6 +2059,7 @@ private void ProcessItemPublicTransport(BufferItem item, ushort targetNodeId, bo } nextItem.m_laneID = nextLane; nextItem.m_lanesUsed = (item.m_lanesUsed | nextLaneInfo.m_laneType); + nextItem.m_vehiclesUsed = (item.m_vehiclesUsed | nextLaneInfo.m_vehicleType); this.AddBufferItem(nextItem, item.m_position); } } @@ -2113,7 +2117,11 @@ private bool ProcessItemCosts(bool allowAdvancedAI, bool ignoreLaneArrows, bool }*/ // NON-STOCK CODE END - if (_extVehicleType == ExtVehicleType.Emergency && !_conf.DebugSwitches[3]) { + if (_extVehicleType == ExtVehicleType.Emergency +#if DEBUG + && !_conf.DebugSwitches[3] +#endif + ) { // lane changing costs are not calculated for emergency vehicles allowAdvancedAI = false; } @@ -2712,7 +2720,11 @@ private bool ProcessItemCosts(bool allowAdvancedAI, bool ignoreLaneArrows, bool !nextIsRealJunction && // no lane changing at junctions laneDist > 0 && // lane would be changed //!(prevIsHighway && nextIsHighway && _isHeavyVehicle && relLaneDist > 0) && // heavy vehicles always prefer using outer lanes on highways - (_extVehicleType != ExtVehicleType.Emergency || _conf.DebugSwitches[3]) && // emergency vehicles may do everything + (_extVehicleType != ExtVehicleType.Emergency +#if DEBUG + || _conf.DebugSwitches[3] +#endif + ) && // emergency vehicles may do everything (!wantToChangeLane || laneDist > 1 || prevIsCongested)) { // randomized lane changing // multiply with lane distance if distance > 1 or if vehicle does not like to change lanes @@ -2731,7 +2743,11 @@ private bool ProcessItemCosts(bool allowAdvancedAI, bool ignoreLaneArrows, bool // avoid lane changing before junctions: multiply with inverted distance to next junction if (//allowLaneChangingCosts && //(!prevIsHighway || !nextIsHighway) && !nextIsRealJunction && - (_extVehicleType != ExtVehicleType.Emergency || _conf.DebugSwitches[3]) && + (_extVehicleType != ExtVehicleType.Emergency +#if DEBUG + || _conf.DebugSwitches[3] +#endif + ) && laneDist > 0) { uint dist = _pathRandomizer.UInt32(3, 10); if (nextItem.m_numSegmentsToJunction < dist) { @@ -2821,6 +2837,7 @@ private bool ProcessItemCosts(bool allowAdvancedAI, bool ignoreLaneArrows, bool // NON-STOCK CODE END // nextItem.m_lanesUsed = (item.m_lanesUsed | nextLaneInfo.m_laneType); + nextItem.m_vehiclesUsed = (item.m_vehiclesUsed | nextLaneInfo.m_vehicleType); nextItem.m_laneID = curLaneId; #if DEBUGPF if (debug) @@ -2964,7 +2981,7 @@ private void ProcessItemPedBicycle(BufferItem item, ushort targetNodeId, ushort float methodDistance = item.m_methodDistance + offsetLength; float comparisonValue = item.m_comparisonValue + offsetLength / (prevSpeed * this._maxLength); if (laneIndex < num) { - NetInfo.Lane nextLane = nextSegmentInfo.m_lanes[laneIndex]; + NetInfo.Lane nextLaneInfo = nextSegmentInfo.m_lanes[laneIndex]; BufferItem nextItem; // NON-STOCK CODE START // if (prevIsJunction) @@ -2975,7 +2992,7 @@ private void ProcessItemPedBicycle(BufferItem item, ushort targetNodeId, ushort nextItem.m_position.m_segment = nextSegmentId; nextItem.m_position.m_lane = (byte)laneIndex; nextItem.m_position.m_offset = offset; - if ((byte)(nextLane.m_laneType & laneType) == 0) { + if ((byte)(nextLaneInfo.m_laneType & laneType) == 0) { nextItem.m_methodDistance = 0f; } else { if (item.m_methodDistance == 0f) { @@ -2983,19 +3000,19 @@ private void ProcessItemPedBicycle(BufferItem item, ushort targetNodeId, ushort } nextItem.m_methodDistance = methodDistance + distance; } - float nextMaxSpeed = GetLaneSpeedLimit(nextSegmentId, (uint)laneIndex, lane, nextLane); // NON-STOCK CODE - if (nextLane.m_laneType != NetInfo.LaneType.Pedestrian || nextItem.m_methodDistance < 1000f) { + float nextMaxSpeed = GetLaneSpeedLimit(nextSegmentId, (uint)laneIndex, lane, nextLaneInfo); // NON-STOCK CODE + if (nextLaneInfo.m_laneType != NetInfo.LaneType.Pedestrian || nextItem.m_methodDistance < 1000f) { nextItem.m_comparisonValue = comparisonValue + distance / ((prevMaxSpeed + nextMaxSpeed) * 0.25f * this._maxLength); if ((nextSegment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) { - nextItem.m_direction = NetInfo.InvertDirection(nextLane.m_finalDirection); + nextItem.m_direction = NetInfo.InvertDirection(nextLaneInfo.m_finalDirection); } else { - nextItem.m_direction = nextLane.m_finalDirection; + nextItem.m_direction = nextLaneInfo.m_finalDirection; } if (lane == this._startLaneA) { if (((byte)(nextItem.m_direction & NetInfo.Direction.Forward) == 0 || nextItem.m_position.m_offset < this._startOffsetA) && ((byte)(nextItem.m_direction & NetInfo.Direction.Backward) == 0 || nextItem.m_position.m_offset > this._startOffsetA)) { return; } - float nextSpeed = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetA, nextItem.m_position.m_offset, ref nextSegment, nextLane); // NON-STOCK CODE + float nextSpeed = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetA, nextItem.m_position.m_offset, ref nextSegment, nextLaneInfo); // NON-STOCK CODE float nextOffset = (float)Mathf.Abs((int)(nextItem.m_position.m_offset - this._startOffsetA)) * 0.003921569f; nextItem.m_comparisonValue += nextOffset * nextSegment.m_averageLength / (nextSpeed * this._maxLength); } @@ -3003,12 +3020,13 @@ private void ProcessItemPedBicycle(BufferItem item, ushort targetNodeId, ushort if (((byte)(nextItem.m_direction & NetInfo.Direction.Forward) == 0 || nextItem.m_position.m_offset < this._startOffsetB) && ((byte)(nextItem.m_direction & NetInfo.Direction.Backward) == 0 || nextItem.m_position.m_offset > this._startOffsetB)) { return; } - float nextSpeed = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetB, nextItem.m_position.m_offset, ref nextSegment, nextLane); // NON-STOCK CODE + float nextSpeed = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetB, nextItem.m_position.m_offset, ref nextSegment, nextLaneInfo); // NON-STOCK CODE float nextOffset = (float)Mathf.Abs((int)(nextItem.m_position.m_offset - this._startOffsetB)) * 0.003921569f; nextItem.m_comparisonValue += nextOffset * nextSegment.m_averageLength / (nextSpeed * this._maxLength); } nextItem.m_laneID = lane; - nextItem.m_lanesUsed = (item.m_lanesUsed | nextLane.m_laneType); + nextItem.m_lanesUsed = (item.m_lanesUsed | nextLaneInfo.m_laneType); + nextItem.m_vehiclesUsed = (item.m_vehiclesUsed | nextLaneInfo.m_vehicleType); this.AddBufferItem(nextItem, item.m_position); } } @@ -3087,18 +3105,20 @@ private void AddBufferItem(BufferItem item, PathUnit.Position target) { _laneTarget[item.m_laneID] = target; } - private void GetLaneDirection(PathUnit.Position pathPos, out NetInfo.Direction direction, out NetInfo.LaneType type) { + private void GetLaneDirection(PathUnit.Position pathPos, out NetInfo.Direction direction, out NetInfo.LaneType laneType, out VehicleInfo.VehicleType vehicleType) { NetManager instance = Singleton<NetManager>.instance; NetInfo info = instance.m_segments.m_buffer[pathPos.m_segment].Info; if (info.m_lanes.Length > pathPos.m_lane) { direction = info.m_lanes[pathPos.m_lane].m_finalDirection; - type = info.m_lanes[pathPos.m_lane].m_laneType; + laneType = info.m_lanes[pathPos.m_lane].m_laneType; + vehicleType = info.m_lanes[pathPos.m_lane].m_vehicleType; if ((instance.m_segments.m_buffer[pathPos.m_segment].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) { direction = NetInfo.InvertDirection(direction); } } else { direction = NetInfo.Direction.None; - type = NetInfo.LaneType.None; + laneType = NetInfo.LaneType.None; + vehicleType = VehicleInfo.VehicleType.None; } } diff --git a/TLM/TLM/State/GlobalConfig.cs b/TLM/TLM/State/GlobalConfig.cs index b904873e..978a3782 100644 --- a/TLM/TLM/State/GlobalConfig.cs +++ b/TLM/TLM/State/GlobalConfig.cs @@ -14,7 +14,7 @@ namespace TrafficManager.State { public class GlobalConfig { public const string FILENAME = "TMPE_GlobalConfig.xml"; public const string BACKUP_FILENAME = FILENAME + ".bak"; - private static int LATEST_VERSION = 1; + private static int LATEST_VERSION = 2; #if DEBUG private static uint lastModificationCheckFrame = 0; #endif @@ -117,7 +117,7 @@ internal static void OnLevelUnloading() { /// <summary> /// artifical lane distance for u-turns /// </summary> - public int UturnLaneDistance = 2; + public int UturnLaneDistance = 8; /// <summary> /// lane density random interval @@ -222,6 +222,11 @@ internal static void OnLevelUnloading() { /// </summary> public uint PublicTransportDemandIncrement = 10u; + /// <summary> + /// public transport demand increment if waiting time was exceeded + /// </summary> + public uint PublicTransportDemandWaitingIncrement = 3u; + /// <summary> /// public transport demand decrement on simulation step /// </summary> @@ -230,7 +235,7 @@ internal static void OnLevelUnloading() { /// <summary> /// public transport demand decrement on path-find success /// </summary> - public uint PublicTransportDemandUsageDecrement = 5u; + public uint PublicTransportDemandUsageDecrement = 7u; /// <summary> /// parking space demand decrement on simulation step @@ -240,7 +245,7 @@ internal static void OnLevelUnloading() { /// <summary> /// minimum parking space demand delta when a passenger car could be spawned /// </summary> - public int MinSpawnedCarParkingSpaceDemandDelta = -5; + public int MinSpawnedCarParkingSpaceDemandDelta = -10; /// <summary> /// maximum parking space demand delta when a passenger car could be spawned @@ -250,7 +255,7 @@ internal static void OnLevelUnloading() { /// <summary> /// minimum parking space demand delta when a parking spot could be found /// </summary> - public int MinFoundParkPosParkingSpaceDemandDelta = -5; + public int MinFoundParkPosParkingSpaceDemandDelta = -10; /// <summary> /// maximum parking space demand delta when a parking spot could be found @@ -260,12 +265,12 @@ internal static void OnLevelUnloading() { /// <summary> /// parking space demand increment when no parking spot could be found while trying to park /// </summary> - public uint FailedParkingSpaceDemandIncrement = 10u; + public uint FailedParkingSpaceDemandIncrement = 5u; /// <summary> /// parking space demand increment when no parking spot could be found while trying to spawn a parked vehicle /// </summary> - public uint FailedSpawnParkingSpaceDemandIncrement = 20u; + public uint FailedSpawnParkingSpaceDemandIncrement = 10u; /// <summary> /// Maximum allowed reported speed difference among all lanes of one segment (in 10000ths) @@ -282,8 +287,12 @@ internal static void WriteConfig() { ModifiedTime = WriteConfig(Instance); } - private static GlobalConfig WriteDefaultConfig(out DateTime modifiedTime) { + private static GlobalConfig WriteDefaultConfig(GlobalConfig oldConfig, out DateTime modifiedTime) { GlobalConfig conf = new GlobalConfig(); + if (oldConfig != null) { + conf.MainMenuButtonX = oldConfig.MainMenuButtonX; + conf.MainMenuButtonY = oldConfig.MainMenuButtonY; + } modifiedTime = WriteConfig(conf); return conf; } @@ -320,7 +329,7 @@ public static GlobalConfig Load(out DateTime modifiedTime) { } } catch (Exception) { Log.Warning("Could not load global config. Generating default config."); - return WriteDefaultConfig(out modifiedTime); + return WriteDefaultConfig(null, out modifiedTime); } } @@ -340,17 +349,17 @@ public static void Reload(bool checkVersion=true) { } catch (Exception e) { Log.Warning($"Error occurred while saving backup config to '{filename}': {e.ToString()}"); } - Reset(); + Reset(conf); } else { Instance = conf; ModifiedTime = WriteConfig(Instance); } } - public static void Reset() { + public static void Reset(GlobalConfig oldConfig) { Log.Info($"Resetting global config."); DateTime modifiedTime; - Instance = WriteDefaultConfig(out modifiedTime); + Instance = WriteDefaultConfig(oldConfig, out modifiedTime); ModifiedTime = modifiedTime; } diff --git a/TLM/TLM/State/Options.cs b/TLM/TLM/State/Options.cs index caa76e88..e4ec7794 100644 --- a/TLM/TLM/State/Options.cs +++ b/TLM/TLM/State/Options.cs @@ -702,7 +702,7 @@ private static void onClickResetGlobalConf() { if (!checkGameLoaded()) return; - GlobalConfig.Reset(); + GlobalConfig.Reset(null); } public static void setSimAccuracy(int newAccuracy) { diff --git a/TLM/TLM/Traffic/ExtBuilding.cs b/TLM/TLM/Traffic/ExtBuilding.cs index c4521fd3..ded49061 100644 --- a/TLM/TLM/Traffic/ExtBuilding.cs +++ b/TLM/TLM/Traffic/ExtBuilding.cs @@ -37,10 +37,6 @@ internal void RemoveParkingSpaceDemand(uint delta) { RequestColorUpdate(); } - private void RequestColorUpdate() { - Singleton<BuildingManager>.instance.UpdateBuildingColors(BuildingId); - } - internal void ModifyParkingSpaceDemand(Vector3 parkPos, int minDelta=-10, int maxDelta=10) { Vector3 buildingPos = Singleton<BuildingManager>.instance.m_buildings.m_buffer[BuildingId].m_position; float distance = Mathf.Clamp((parkPos - buildingPos).magnitude, 0f, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius); @@ -71,5 +67,9 @@ internal void RemovePublicTransportDemand(uint delta, bool outgoing) { RequestColorUpdate(); } + + private void RequestColorUpdate() { + Singleton<BuildingManager>.instance.UpdateBuildingColors(BuildingId); + } } } diff --git a/TLM/TLM/TrafficManagerMod.cs b/TLM/TLM/TrafficManagerMod.cs index 94c15c7a..d9494023 100644 --- a/TLM/TLM/TrafficManagerMod.cs +++ b/TLM/TLM/TrafficManagerMod.cs @@ -5,7 +5,7 @@ namespace TrafficManager { public class TrafficManagerMod : IUserMod { - public static readonly string Version = "1.8.2"; + public static readonly string Version = "1.8.3"; public static readonly uint GameVersion = 159507472u; public static readonly uint GameVersionA = 1u;