public void CustomCalculateSegmentPositionPathFinder(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position position, uint laneId, byte offset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { var netManager = Singleton <NetManager> .instance; netManager.m_lanes.m_buffer[laneId].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir); var segmentInfo = netManager.m_segments.m_buffer[position.m_segment].Info; if (segmentInfo.m_lanes != null && segmentInfo.m_lanes.Length > position.m_lane) { // NON-STOCK CODE START float laneSpeedLimit = 1f; if (!Options.customSpeedLimitsEnabled) { laneSpeedLimit = segmentInfo.m_lanes[position.m_lane].m_speedLimit; } else { laneSpeedLimit = Constants.ManagerFactory.SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneId, segmentInfo.m_lanes[position.m_lane]); } // NON-STOCK CODE END maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[laneId].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } // NON-STOCK CODE START maxSpeed = VehicleBehaviorManager.Instance.CalcMaxSpeed(vehicleId, ref VehicleStateManager.Instance.VehicleStates[vehicleId], this.m_info, position, ref netManager.m_segments.m_buffer[position.m_segment], pos, maxSpeed); // NON-STOCK CODE END }
public new bool ChangeVehicleType(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position pathPos, uint laneID) { return(base.ChangeVehicleType(vehicleID, ref vehicleData, pathPos, laneID)); }
public new bool ParkVehicle(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position pathPos, uint nextPath, int nextPositionIndex, out byte segmentOffset) { return(base.ParkVehicle(vehicleID, ref vehicleData, pathPos, nextPath, nextPositionIndex, out segmentOffset)); }
public static bool FindPathPositionWithSpiralLoop(Vector3 position, Vector3?secondaryPosition, ItemClass.Service service, NetInfo.LaneType laneType, VehicleInfo.VehicleType vehicleType, VehicleInfo.VehicleType stopType, bool allowUnderground, bool requireConnect, float maxDistance, out PathUnit.Position pathPosA, out PathUnit.Position pathPosB, out float distanceSqrA, out float distanceSqrB) { int iMin = Mathf.Max((int)((position.z - (float)NetManager.NODEGRID_CELL_SIZE) / (float)NetManager.NODEGRID_CELL_SIZE + (float)NetManager.NODEGRID_RESOLUTION / 2f), 0); int iMax = Mathf.Min((int)((position.z + (float)NetManager.NODEGRID_CELL_SIZE) / (float)NetManager.NODEGRID_CELL_SIZE + (float)NetManager.NODEGRID_RESOLUTION / 2f), NetManager.NODEGRID_RESOLUTION - 1); int jMin = Mathf.Max((int)((position.x - (float)NetManager.NODEGRID_CELL_SIZE) / (float)NetManager.NODEGRID_CELL_SIZE + (float)NetManager.NODEGRID_RESOLUTION / 2f), 0); int jMax = Mathf.Min((int)((position.x + (float)NetManager.NODEGRID_CELL_SIZE) / (float)NetManager.NODEGRID_CELL_SIZE + (float)NetManager.NODEGRID_RESOLUTION / 2f), NetManager.NODEGRID_RESOLUTION - 1); int width = iMax - iMin + 1; int height = jMax - jMin + 1; int centerI = (int)(position.z / (float)NetManager.NODEGRID_CELL_SIZE + (float)NetManager.NODEGRID_RESOLUTION / 2f); int centerJ = (int)(position.x / (float)NetManager.NODEGRID_CELL_SIZE + (float)NetManager.NODEGRID_RESOLUTION / 2f); NetManager netManager = Singleton <NetManager> .instance; /*pathPosA.m_segment = 0; * pathPosA.m_lane = 0; * pathPosA.m_offset = 0;*/ distanceSqrA = 1E+10f; /*pathPosB.m_segment = 0; * pathPosB.m_lane = 0; * pathPosB.m_offset = 0;*/ distanceSqrB = 1E+10f; float minDist = float.MaxValue; PathUnit.Position myPathPosA = default(PathUnit.Position); float myDistanceSqrA = float.MaxValue; PathUnit.Position myPathPosB = default(PathUnit.Position); float myDistanceSqrB = float.MaxValue; int lastSpiralDist = 0; bool found = false; LoopUtil.SpiralLoop(centerI, centerJ, width, height, delegate(int i, int j) { if (i < 0 || i >= NetManager.NODEGRID_RESOLUTION || j < 0 || j >= NetManager.NODEGRID_RESOLUTION) { return(true); } int spiralDist = Math.Max(Math.Abs(i - centerI), Math.Abs(j - centerJ)); // maximum norm if (found && spiralDist > lastSpiralDist) { // last iteration return(false); } ushort segmentId = netManager.m_segmentGrid[i * NetManager.NODEGRID_RESOLUTION + j]; int iterations = 0; while (segmentId != 0) { NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info; if (segmentInfo != null && segmentInfo.m_class.m_service == service && (netManager.m_segments.m_buffer[segmentId].m_flags & (NetSegment.Flags.Collapsed | NetSegment.Flags.Flooded)) == NetSegment.Flags.None && (allowUnderground || !segmentInfo.m_netAI.IsUnderground()) ) { ushort startNodeId = netManager.m_segments.m_buffer[segmentId].m_startNode; ushort endNodeId = netManager.m_segments.m_buffer[segmentId].m_endNode; Vector3 startNodePos = netManager.m_nodes.m_buffer[startNodeId].m_position; Vector3 endNodePos = netManager.m_nodes.m_buffer[endNodeId].m_position; Vector3 posA; int laneIndexA; float laneOffsetA; Vector3 posB; int laneIndexB; float laneOffsetB; if (netManager.m_segments.m_buffer[segmentId].GetClosestLanePosition(position, laneType, vehicleType, stopType, requireConnect, out posA, out laneIndexA, out laneOffsetA, out posB, out laneIndexB, out laneOffsetB)) { float dist = Vector3.SqrMagnitude(position - posA); if (secondaryPosition != null) { dist += Vector3.SqrMagnitude((Vector3)secondaryPosition - posA); } if (dist < minDist) { found = true; minDist = dist; myPathPosA.m_segment = segmentId; myPathPosA.m_lane = (byte)laneIndexA; myPathPosA.m_offset = (byte)Mathf.Clamp(Mathf.RoundToInt(laneOffsetA * 255f), 0, 255); myDistanceSqrA = dist; dist = Vector3.SqrMagnitude(position - posB); if (secondaryPosition != null) { dist += Vector3.SqrMagnitude((Vector3)secondaryPosition - posB); } if (laneIndexB < 0) { myPathPosB.m_segment = 0; myPathPosB.m_lane = 0; myPathPosB.m_offset = 0; myDistanceSqrB = float.MaxValue; } else { myPathPosB.m_segment = segmentId; myPathPosB.m_lane = (byte)laneIndexB; myPathPosB.m_offset = (byte)Mathf.Clamp(Mathf.RoundToInt(laneOffsetB * 255f), 0, 255); myDistanceSqrB = dist; } } } } segmentId = netManager.m_segments.m_buffer[segmentId].m_nextGridSegment; if (++iterations >= NetManager.MAX_SEGMENT_COUNT) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } lastSpiralDist = spiralDist; return(true); }); pathPosA = myPathPosA; distanceSqrA = myDistanceSqrA; pathPosB = myPathPosB; distanceSqrB = myDistanceSqrB; return(pathPosA.m_segment != 0); }
internal bool ExtParkVehicle(ushort vehicleID, ref Vehicle vehicleData, uint driverCitizenId, ushort driverCitizenInstanceId, ref ExtCitizenInstance driverExtInstance, ushort targetBuildingId, PathUnit.Position pathPos, uint nextPath, int nextPositionIndex, out byte segmentOffset) { #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; #endif PathManager pathManager = Singleton <PathManager> .instance; CitizenManager citizenManager = Singleton <CitizenManager> .instance; NetManager netManager = Singleton <NetManager> .instance; VehicleManager vehicleManager = Singleton <VehicleManager> .instance; // NON-STOCK CODE START bool prohibitPocketCars = false; // NON-STOCK CODE END if (driverCitizenId != 0u) { if (Options.prohibitPocketCars && driverCitizenInstanceId != 0) { prohibitPocketCars = true; } uint laneID = PathManager.GetLaneID(pathPos); segmentOffset = (byte)Singleton <SimulationManager> .instance.m_randomizer.Int32(1, 254); Vector3 refPos; Vector3 vector; netManager.m_lanes.m_buffer[laneID].CalculatePositionAndDirection((float)segmentOffset * 0.003921569f, out refPos, out vector); NetInfo info = netManager.m_segments.m_buffer[(int)pathPos.m_segment].Info; bool isSegmentInverted = (netManager.m_segments.m_buffer[(int)pathPos.m_segment].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None; bool isPosNegative = info.m_lanes[(int)pathPos.m_lane].m_position < 0f; vector.Normalize(); Vector3 searchDir; if (isSegmentInverted != isPosNegative) { searchDir.x = -vector.z; searchDir.y = 0f; searchDir.z = vector.x; } else { searchDir.x = vector.z; searchDir.y = 0f; searchDir.z = -vector.x; } ushort homeID = 0; if (driverCitizenId != 0u) { homeID = Singleton <CitizenManager> .instance.m_citizens.m_buffer[driverCitizenId].m_homeBuilding; } Vector3 parkPos = default(Vector3); Quaternion parkRot = default(Quaternion); float parkOffset = -1f; // NON-STOCK CODE START bool foundParkingSpace = false; if (prohibitPocketCars) { #if DEBUG if (debug) { 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} driverCitizenId={driverCitizenId} driverCitizenInstanceId={driverCitizenInstanceId}"); } #endif if (driverExtInstance.pathMode == ExtCitizenInstance.ExtPathMode.DrivingToAltParkPos || driverExtInstance.pathMode == ExtCitizenInstance.ExtPathMode.DrivingToKnownParkPos) { // try to use previously found parking space #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleID} tries to park on an (alternative) parking position now! CurrentPathMode={driverExtInstance.pathMode} altParkingSpaceLocation={driverExtInstance.parkingSpaceLocation} altParkingSpaceLocationId={driverExtInstance.parkingSpaceLocationId}"); } #endif switch (driverExtInstance.parkingSpaceLocation) { case ExtCitizenInstance.ExtParkingSpaceLocation.RoadSide: uint parkLaneID; int parkLaneIndex; #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleID} wants to park road-side @ segment {driverExtInstance.parkingSpaceLocationId}"); } #endif foundParkingSpace = AdvancedParkingManager.Instance.FindParkingSpaceRoadSideForVehiclePos(this.m_info, 0, driverExtInstance.parkingSpaceLocationId, refPos, out parkPos, out parkRot, out parkOffset, out parkLaneID, out parkLaneIndex); break; case ExtCitizenInstance.ExtParkingSpaceLocation.Building: float maxDist = 9999f; #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleID} wants to park @ building {driverExtInstance.parkingSpaceLocationId}"); } #endif foundParkingSpace = AdvancedParkingManager.Instance.FindParkingSpacePropAtBuilding(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 Log.Error($"No alternative parking position stored for vehicle {vehicleID}! PathMode={driverExtInstance.pathMode}"); #endif foundParkingSpace = CustomFindParkingSpace(this.m_info, homeID, refPos, searchDir, pathPos.m_segment, out parkPos, out parkRot, out parkOffset); break; } } } if (!foundParkingSpace) { foundParkingSpace = /*prohibitPocketCars ?*/ CustomFindParkingSpace(this.m_info, homeID, refPos, searchDir, pathPos.m_segment, 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 ushort parkedVehicleId = 0; bool parkedCarCreated = foundParkingSpace && vehicleManager.CreateParkedVehicle(out parkedVehicleId, ref Singleton <SimulationManager> .instance.m_randomizer, this.m_info, parkPos, parkRot, driverCitizenId); if (foundParkingSpace && parkedCarCreated) { // we have reached a parking position #if DEBUG float sqrDist = (refPos - parkPos).sqrMagnitude; if (fineDebug) { Log._Debug($"Vehicle {vehicleID} succeeded in parking! CurrentPathMode={driverExtInstance.pathMode} sqrDist={sqrDist}"); } if (GlobalConfig.Instance.Debug.Switches[6] && sqrDist >= 16000) { Log._Debug($"CustomPassengerCarAI.CustomParkVehicle: FORCED PAUSE. Distance very large! Vehicle {vehicleID}. dist={sqrDist}"); Singleton <SimulationManager> .instance.SimulationPaused = true; } #endif citizenManager.m_citizens.m_buffer[driverCitizenId].SetParkedVehicle(driverCitizenId, parkedVehicleId); if (parkOffset >= 0f) { segmentOffset = (byte)(parkOffset * 255f); } // NON-STOCK CODE START if (prohibitPocketCars) { if ((driverExtInstance.pathMode == ExtCitizenInstance.ExtPathMode.DrivingToAltParkPos || driverExtInstance.pathMode == ExtCitizenInstance.ExtPathMode.DrivingToKnownParkPos) && targetBuildingId != 0) { // decrease parking space demand of target building ExtBuildingManager.Instance.ExtBuildings[targetBuildingId].ModifyParkingSpaceDemand(parkPos, GlobalConfig.Instance.ParkingAI.MinFoundParkPosParkingSpaceDemandDelta, GlobalConfig.Instance.ParkingAI.MaxFoundParkPosParkingSpaceDemandDelta); } //if (driverExtInstance.CurrentPathMode == ExtCitizenInstance.PathMode.DrivingToAltParkPos || driverExtInstance.CurrentPathMode == ExtCitizenInstance.PathMode.DrivingToKnownParkPos) { // we have reached an (alternative) parking position and succeeded in finding a parking space driverExtInstance.pathMode = ExtCitizenInstance.ExtPathMode.RequiresWalkingPathToTarget; driverExtInstance.failedParkingAttempts = 0; driverExtInstance.parkingSpaceLocation = ExtCitizenInstance.ExtParkingSpaceLocation.None; driverExtInstance.parkingSpaceLocationId = 0; #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleID} has reached an (alternative) parking position! CurrentPathMode={driverExtInstance.pathMode} position={parkPos}"); } #endif //} } } else if (prohibitPocketCars) { // could not find parking space. vehicle would despawn. if (targetBuildingId != 0 && (Singleton <BuildingManager> .instance.m_buildings.m_buffer[targetBuildingId].m_flags & Building.Flags.IncomingOutgoing) != Building.Flags.None) { // target is an outside connection return(true); } // 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 (!foundParkingSpace && (driverExtInstance.pathMode == ExtCitizenInstance.ExtPathMode.DrivingToAltParkPos || driverExtInstance.pathMode == ExtCitizenInstance.ExtPathMode.DrivingToKnownParkPos) && targetBuildingId != 0) { // increase parking space demand of target building if (driverExtInstance.failedParkingAttempts > 1) { ExtBuildingManager.Instance.ExtBuildings[targetBuildingId].AddParkingSpaceDemand(GlobalConfig.Instance.ParkingAI.FailedParkingSpaceDemandIncrement * (uint)(driverExtInstance.failedParkingAttempts - 1)); } } if (!foundParkingSpace) { ++driverExtInstance.failedParkingAttempts; } else { #if DEBUG if (debug) { Log._Debug($"Parking failed for vehicle {vehicleID}: Parked car could not be created. ABORT."); } #endif driverExtInstance.failedParkingAttempts = GlobalConfig.Instance.ParkingAI.MaxParkingAttempts + 1; } driverExtInstance.pathMode = ExtCitizenInstance.ExtPathMode.ParkingFailed; driverExtInstance.parkingPathStartPosition = pathPos; #if DEBUG if (debug) { 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 uint curUnitId = vehicleData.m_citizenUnits; int numIter = 0; while (curUnitId != 0u) { uint nextUnit = citizenManager.m_units.m_buffer[curUnitId].m_nextUnit; for (int i = 0; i < 5; i++) { uint curCitizenId = citizenManager.m_units.m_buffer[curUnitId].GetCitizen(i); if (curCitizenId != 0u) { ushort citizenInstanceId = citizenManager.m_citizens.m_buffer[curCitizenId].m_instance; if (citizenInstanceId != 0) { #if DEBUG if (debug) { 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) { #if DEBUG if (debug) { Log._Debug($"Resetting pathmode for passenger citizen instance {citizenInstanceId} sitting in vehicle {vehicleID} (was {ExtCitizenInstanceManager.Instance.ExtInstances[citizenInstanceId].pathMode})."); } #endif ExtCitizenInstanceManager.Instance.ExtInstances[citizenInstanceId].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; } } } } curUnitId = nextUnit; if (++numIter > CitizenManager.MAX_UNIT_COUNT) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } return(false); // NON-STOCK CODE END } } else { segmentOffset = pathPos.m_offset; } // parking has succeeded if (driverCitizenId != 0u) { uint curCitizenUnitId = vehicleData.m_citizenUnits; int numIter = 0; while (curCitizenUnitId != 0u) { uint nextUnit = citizenManager.m_units.m_buffer[curCitizenUnitId].m_nextUnit; for (int j = 0; j < 5; j++) { uint citId = citizenManager.m_units.m_buffer[curCitizenUnitId].GetCitizen(j); if (citId != 0u) { ushort citizenInstanceId = citizenManager.m_citizens.m_buffer[citId].m_instance; if (citizenInstanceId != 0) { // NON-STOCK CODE START if (prohibitPocketCars) { if (driverExtInstance.pathMode == ExtCitizenInstance.ExtPathMode.RequiresWalkingPathToTarget) { #if DEBUG if (debug) { Log._Debug($"Parking succeeded: Doing nothing for citizen instance {citizenInstanceId}! path: {citizenManager.m_instances.m_buffer[(int)citizenInstanceId].m_path}"); } #endif ExtCitizenInstanceManager.Instance.ExtInstances[citizenInstanceId].pathMode = ExtCitizenInstance.ExtPathMode.RequiresWalkingPathToTarget; continue; } } // NON-STOCK CODE END if (pathManager.AddPathReference(nextPath)) { if (citizenManager.m_instances.m_buffer[(int)citizenInstanceId].m_path != 0u) { pathManager.ReleasePath(citizenManager.m_instances.m_buffer[(int)citizenInstanceId].m_path); } citizenManager.m_instances.m_buffer[(int)citizenInstanceId].m_path = nextPath; citizenManager.m_instances.m_buffer[(int)citizenInstanceId].m_pathPositionIndex = (byte)nextPositionIndex; citizenManager.m_instances.m_buffer[(int)citizenInstanceId].m_lastPathOffset = segmentOffset; #if DEBUG if (debug) { Log._Debug($"Parking succeeded (default): Setting path of citizen instance {citizenInstanceId} to {nextPath}!"); } #endif } } } } curCitizenUnitId = nextUnit; if (++numIter > 524288) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } if (prohibitPocketCars) { if (driverExtInstance.pathMode == ExtCitizenInstance.ExtPathMode.RequiresWalkingPathToTarget) { #if DEBUG if (debug) { Log._Debug($"Parking succeeded (alternative parking spot): Citizen instance {driverExtInstance} has to walk for the remaining path!"); } #endif /*driverExtInstance.CurrentPathMode = ExtCitizenInstance.PathMode.CalculatingWalkingPathToTarget; * if (debug) * Log._Debug($"Setting CurrentPathMode of vehicle {vehicleID} to {driverExtInstance.CurrentPathMode}");*/ } } return(true); }
public bool ExtStartPathFind(ushort instanceID, ref CitizenInstance instanceData, ref ExtCitizenInstance extInstance, ref ExtCitizen extCitizen, Vector3 startPos, Vector3 endPos, VehicleInfo vehicleInfo, bool enableTransport, bool ignoreCost) { #if DEBUG bool citDebug = GlobalConfig.Instance.Debug.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}, enableTransport={enableTransport}, ignoreCost={ignoreCost}"); } #endif // NON-STOCK CODE START CitizenManager citizenManager = Singleton <CitizenManager> .instance; ushort parkedVehicleId = citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_parkedVehicle; ushort homeId = citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_homeBuilding; CarUsagePolicy carUsageMode = CarUsagePolicy.Allowed; #if BENCHMARK using (var bm = new Benchmark(null, "ParkingAI.Preparation")) { #endif if (Options.prohibitPocketCars) { switch (extInstance.pathMode) { case ExtPathMode.RequiresWalkingPathToParkedCar: case ExtPathMode.CalculatingWalkingPathToParkedCar: case ExtPathMode.WalkingToParkedCar: case ExtPathMode.ApproachingParkedCar: if (parkedVehicleId == 0) { /* * Parked vehicle not present but citizen wants to reach it * -> Reset path mode */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode} but no parked vehicle present. Change to 'None'."); } #endif extInstance.Reset(); } else { /* * Parked vehicle is present and citizen wants to reach it * -> Prohibit car usage */ #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToParkedCar'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToParkedCar; carUsageMode = CarUsagePolicy.Forbidden; } break; case ExtPathMode.RequiresWalkingPathToTarget: case ExtPathMode.CalculatingWalkingPathToTarget: case ExtPathMode.WalkingToTarget: /* * Citizen walks to target * -> Reset path mode */ #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToTarget'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; carUsageMode = CarUsagePolicy.Forbidden; break; case ExtPathMode.RequiresCarPath: case ExtPathMode.DrivingToTarget: case ExtPathMode.DrivingToKnownParkPos: case ExtPathMode.DrivingToAltParkPos: case ExtPathMode.CalculatingCarPathToAltParkPos: case ExtPathMode.CalculatingCarPathToKnownParkPos: case ExtPathMode.CalculatingCarPathToTarget: if (parkedVehicleId == 0) { /* * Citizen wants to drive to target but parked vehicle is not present * -> Reset path mode */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode} but no parked vehicle present. Change to 'None'."); } #endif extInstance.Reset(); } else { /* * Citizen wants to drive to target and parked vehicle is present * -> Force parked car usage */ #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'RequiresCarPath'."); } #endif extInstance.pathMode = ExtPathMode.RequiresCarPath; carUsageMode = CarUsagePolicy.ForcedParked; startPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; // force to start from the parked car } break; default: #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'None'."); } #endif extInstance.Reset(); break; } if (extInstance.pathMode == ExtPathMode.None) { if ((instanceData.m_flags & CitizenInstance.Flags.OnTour) != CitizenInstance.Flags.None || ignoreCost) { /* * Citizen is on a walking tour or is a mascot * -> Prohibit car usage */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen ignores cost ({ignoreCost}) or is on a walking tour ({(instanceData.m_flags & CitizenInstance.Flags.OnTour) != CitizenInstance.Flags.None}): Setting path mode to 'CalculatingWalkingPathToTarget'"); } #endif carUsageMode = CarUsagePolicy.Forbidden; extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; } else { /* * Citizen is not on a walking tour and is not a mascot * -> Check if citizen is located at an outside connection and make them obey Parking AI restrictions */ if (instanceData.m_sourceBuilding != 0) { ItemClass.Service sourceBuildingService = Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_sourceBuilding].Info.m_class.m_service; if (Constants.ManagerFactory.ExtCitizenInstanceManager.IsAtOutsideConnection(instanceID, ref instanceData, ref citizenManager.m_citizens.m_buffer[instanceData.m_citizen])) { if (sourceBuildingService == ItemClass.Service.Road) { if (vehicleInfo != null) { /* * Citizen is located at a road outside connection and can spawn a car * -> Force car usage */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is located at a road outside connection: Setting path mode to 'RequiresCarPath' and carUsageMode to 'ForcedPocket'"); } #endif extInstance.pathMode = ExtPathMode.RequiresCarPath; carUsageMode = CarUsagePolicy.ForcedPocket; } else { /* * Citizen is located at a non-road outside connection and cannot spawn a car * -> Path-finding fails */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is located at a road outside connection but does not have a car template: ABORTING PATH-FINDING"); } #endif return(false); } } else { /* * Citizen is located at a non-road outside connection * -> Prohibit car usage */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is located at a non-road outside connection: Setting path mode to 'CalculatingWalkingPathToTarget'"); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; carUsageMode = CarUsagePolicy.Forbidden; } } } } } if ((carUsageMode == CarUsagePolicy.Allowed || carUsageMode == CarUsagePolicy.ForcedParked) && parkedVehicleId != 0) { /* * Reuse parked vehicle info */ vehicleInfo = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].Info; /* * Check if the citizen should return their car back home */ if (extInstance.pathMode == ExtPathMode.None && // initiating a new path homeId != 0 && // home building present instanceData.m_targetBuilding == homeId // current target is home ) { /* * citizen travels back home * -> check if their car should be returned */ if ((extCitizen.lastTransportMode & ExtCitizen.ExtTransportMode.Car) != ExtCitizen.ExtTransportMode.None) { /* * citizen travelled by car * -> return car back home */ extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar; carUsageMode = CarUsagePolicy.Forbidden; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen used their car before and is not at home. Forcing to walk to parked car."); } #endif } else { /* * citizen travelled by other means of transport * -> check distance between home and parked car. if too far away: force to take the car back home */ float distHomeToParked = (Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position - Singleton <BuildingManager> .instance.m_buildings.m_buffer[homeId].m_position).magnitude; if (distHomeToParked > GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToHome) { /* * force to take car back home */ extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar; carUsageMode = CarUsagePolicy.Forbidden; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen wants to go home and parked car is too far away ({distHomeToParked}). Forcing walking to parked car."); } #endif } } } } /* * The following holds: * - pathMode is now either CalculatingWalkingPathToParkedCar, CalculatingWalkingPathToTarget, RequiresCarPath or None. * - if pathMode is CalculatingWalkingPathToParkedCar or RequiresCarPath: parked car is present and citizen is not on a walking tour * - carUsageMode is valid * - if pathMode is RequiresCarPath: carUsageMode is either ForcedParked or ForcedPocket */ /* * modify path-finding constraints (vehicleInfo, endPos) if citizen is forced to walk */ if (extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToParkedCar || extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToTarget) { /* * vehicle must not be used since we need a walking path to either * 1. a parked car or * 2. the target building */ if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar) { /* * walk to parked car * -> end position is parked car */ endPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen shall go to parked vehicle @ {endPos}"); } #endif } } } #if BENCHMARK } #endif #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is allowed to drive their car? {carUsageMode}"); } #endif // NON-STOCK CODE END /* * semi-stock code: determine path-finding parameters (laneTypes, vehicleTypes, extVehicleType, etc.) */ NetInfo.LaneType laneTypes = NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleTypes = VehicleInfo.VehicleType.None; bool randomParking = false; bool combustionEngine = false; ExtVehicleType extVehicleType = ExtVehicleType.None; if (vehicleInfo != null) { if (vehicleInfo.m_class.m_subService == ItemClass.SubService.PublicTransportTaxi) { if ((instanceData.m_flags & CitizenInstance.Flags.CannotUseTaxi) == CitizenInstance.Flags.None && Singleton <DistrictManager> .instance.m_districts.m_buffer[0].m_productionData.m_finalTaxiCapacity != 0u) { SimulationManager instance = Singleton <SimulationManager> .instance; if (instance.m_isNightTime || instance.m_randomizer.Int32(2u) == 0) { laneTypes |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); vehicleTypes |= vehicleInfo.m_vehicleType; extVehicleType = ExtVehicleType.Taxi; // NON-STOCK CODE // NON-STOCK CODE START if (Options.prohibitPocketCars) { extInstance.pathMode = ExtPathMode.TaxiToTarget; } // NON-STOCK CODE END } } } else // NON-STOCK CODE START if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Car) { if (carUsageMode != CarUsagePolicy.Forbidden) { extVehicleType = ExtVehicleType.PassengerCar; laneTypes |= NetInfo.LaneType.Vehicle; vehicleTypes |= vehicleInfo.m_vehicleType; combustionEngine = vehicleInfo.m_class.m_subService == ItemClass.SubService.ResidentialLow; } } else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { extVehicleType = ExtVehicleType.Bicycle; laneTypes |= NetInfo.LaneType.Vehicle; vehicleTypes |= vehicleInfo.m_vehicleType; } // NON-STOCK CODE END } // NON-STOCK CODE START ExtPathType extPathType = ExtPathType.None; PathUnit.Position endPosA = default(PathUnit.Position); bool calculateEndPos = true; bool allowRandomParking = true; #if BENCHMARK using (var bm = new Benchmark(null, "ParkingAI.Main")) { #endif if (Options.prohibitPocketCars) { // Parking AI if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.RequiresCarPath) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Setting startPos={startPos} for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode}"); } #endif if ( instanceData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None ) { /* * the citizen is starting their journey and the target is not an outside connection * -> find a suitable parking space near the target */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding parking space at target for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode} parkedVehicleId={parkedVehicleId}"); } #endif // find a parking space in the vicinity of the target bool calcEndPos; Vector3 parkPos; if ( AdvancedParkingManager.Instance.FindParkingSpaceForCitizen(endPos, vehicleInfo, ref extInstance, homeId, instanceData.m_targetBuilding == homeId, 0, false, out parkPos, ref endPosA, out calcEndPos) && extInstance.CalculateReturnPath(parkPos, endPos) ) { // success extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToKnownParkPos; calculateEndPos = calcEndPos; // if true, the end path position still needs to be calculated allowRandomParking = false; // find a direct path to the calculated parking position #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding known parking space for citizen instance {instanceID}, parked vehicle {parkedVehicleId} succeeded and return path {extInstance.returnPathId} ({extInstance.returnPathState}) is calculating. PathMode={extInstance.pathMode}"); } #endif /*if (! extInstance.CalculateReturnPath(parkPos, endPos)) { * // TODO retry? * if (debug) * Log._Debug($"CustomCitizenAI.CustomStartPathFind: [PFFAIL] Could not calculate return path for citizen instance {instanceID}, parked vehicle {parkedVehicleId}. Calling OnPathFindFailed."); * CustomHumanAI.OnPathFindFailure(extInstance); * return false; * }*/ } } if (extInstance.pathMode == ExtPathMode.RequiresCarPath) { /* * no known parking space found (pathMode has not been updated in the block above) * -> calculate direct path to target */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} is still at CurrentPathMode={extInstance.pathMode} (no parking space found?). Setting it to CalculatingCarPath. parkedVehicleId={parkedVehicleId}"); } #endif extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToTarget; } } /* * determine path type from path mode */ extPathType = extInstance.GetPathType(); /* * the following holds: * - pathMode is now either CalculatingWalkingPathToParkedCar, CalculatingWalkingPathToTarget, CalculatingCarPathToTarget, CalculatingCarPathToKnownParkPos or None. */ } #if BENCHMARK } #endif /* * enable random parking if exact parking space was not calculated yet */ if (extVehicleType == ExtVehicleType.PassengerCar || extVehicleType == ExtVehicleType.Bicycle) { if (allowRandomParking && instanceData.m_targetBuilding != 0 && ( Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office || (instanceData.m_flags & CitizenInstance.Flags.TargetIsNode) != 0 )) { randomParking = true; } } // NON-STOCK CODE END /* * determine the path position of the parked vehicle */ PathUnit.Position parkedVehiclePathPos = default(PathUnit.Position); if (parkedVehicleId != 0 && extVehicleType == ExtVehicleType.PassengerCar) { Vector3 position = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; CustomPathManager.FindPathPositionWithSpiralLoop(position, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out parkedVehiclePathPos); } bool allowUnderground = (instanceData.m_flags & (CitizenInstance.Flags.Underground | CitizenInstance.Flags.Transition)) != CitizenInstance.Flags.None; #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Requesting path-finding for citizen instance {instanceID}, citizen {instanceData.m_citizen}, extVehicleType={extVehicleType}, extPathType={extPathType}, startPos={startPos}, endPos={endPos}, sourceBuilding={instanceData.m_sourceBuilding}, targetBuilding={instanceData.m_targetBuilding} pathMode={extInstance.pathMode}"); } #endif /* * determine start & end path positions */ bool foundEndPos = !calculateEndPos || FindPathPosition(instanceID, ref instanceData, endPos, Options.prohibitPocketCars && (instanceData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) ? NetInfo.LaneType.Pedestrian : laneTypes, vehicleTypes, false, out endPosA); // NON-STOCK CODE: with Parking AI enabled, the end position must be a pedestrian position bool foundStartPos = false; PathUnit.Position startPosA; if (Options.prohibitPocketCars && (extInstance.pathMode == ExtPathMode.CalculatingCarPathToTarget || extInstance.pathMode == ExtPathMode.CalculatingCarPathToKnownParkPos)) { /* * citizen will enter their car now * -> find a road start position */ foundStartPos = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, laneTypes & ~NetInfo.LaneType.Pedestrian, vehicleTypes, allowUnderground, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out startPosA); } else { foundStartPos = FindPathPosition(instanceID, ref instanceData, startPos, laneTypes, vehicleTypes, allowUnderground, out startPosA); } /* * start path-finding */ if (foundStartPos && // TODO probably fails if vehicle is parked too far away from road foundEndPos // NON-STOCK CODE ) { if (enableTransport) { /* * public transport usage is allowed for this path */ if ((instanceData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None) { /* * citizen may use public transport */ laneTypes |= NetInfo.LaneType.PublicTransport; uint citizenId = instanceData.m_citizen; if (citizenId != 0u && (citizenManager.m_citizens.m_buffer[citizenId].m_flags & Citizen.Flags.Evacuating) != Citizen.Flags.None) { laneTypes |= NetInfo.LaneType.EvacuationTransport; } } else if (Options.prohibitPocketCars) // TODO check for incoming connection /* * citizen tried to use public transport but waiting time was too long * -> add public transport demand for source building */ { if (instanceData.m_sourceBuilding != 0) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} cannot uses public transport from building {instanceData.m_sourceBuilding} to {instanceData.m_targetBuilding}. Incrementing public transport demand."); } #endif ExtBuildingManager.Instance.ExtBuildings[instanceData.m_sourceBuilding].AddPublicTransportDemand((uint)GlobalConfig.Instance.ParkingAI.PublicTransportDemandWaitingIncrement, true); } } } PathUnit.Position dummyPathPos = default(PathUnit.Position); uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = extPathType; args.extVehicleType = extVehicleType; args.vehicleId = 0; args.spawned = (instanceData.m_flags & CitizenInstance.Flags.Character) != CitizenInstance.Flags.None; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = dummyPathPos; args.endPosA = endPosA; args.endPosB = dummyPathPos; args.vehiclePosition = parkedVehiclePathPos; args.laneTypes = laneTypes; args.vehicleTypes = vehicleTypes; args.maxLength = 20000f; args.isHeavyVehicle = false; args.hasCombustionEngine = combustionEngine; args.ignoreBlocked = false; args.ignoreFlooded = false; args.ignoreCosts = ignoreCost; args.randomParking = randomParking; args.stablePath = false; args.skipQueue = false; if ((instanceData.m_flags & CitizenInstance.Flags.OnTour) != 0) { args.stablePath = true; args.maxLength = 160000f; //args.laneTypes &= ~(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); } else { args.stablePath = false; args.maxLength = 20000f; } bool res = CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args); // NON-STOCK CODE END if (res) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Path-finding starts for citizen instance {instanceID}, path={path}, extVehicleType={extVehicleType}, extPathType={extPathType}, startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, laneType={laneTypes}, vehicleType={vehicleTypes}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, vehiclePos.m_segment={parkedVehiclePathPos.m_segment}, vehiclePos.m_lane={parkedVehiclePathPos.m_lane}, vehiclePos.m_offset={parkedVehiclePathPos.m_offset}"); } #endif if (instanceData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(instanceData.m_path); } instanceData.m_path = path; instanceData.m_flags |= CitizenInstance.Flags.WaitingPath; return(true); } } #if DEBUG if (Options.prohibitPocketCars) { if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): CustomCitizenAI.CustomStartPathFind: [PFFAIL] failed for citizen instance {instanceID} (CurrentPathMode={extInstance.pathMode}). startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, startPosA.offset={startPosA.m_offset}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, endPosA.offset={endPosA.m_offset}, foundStartPos={foundStartPos}, foundEndPos={foundEndPos}"); } } #endif return(false); }
public static bool FindPathPositionWithSpiralLoop(Vector3 position, Vector3?secondaryPosition, ItemClass.Service service, NetInfo.LaneType laneType, VehicleInfo.VehicleType vehicleType, bool allowUnderground, bool requireConnect, float maxDistance, out PathUnit.Position pathPos) { PathUnit.Position position2; float distanceSqrA; float distanceSqrB; return(FindPathPositionWithSpiralLoop(position, secondaryPosition, service, laneType, vehicleType, VehicleInfo.VehicleType.None, allowUnderground, requireConnect, maxDistance, out pathPos, out position2, out distanceSqrA, out distanceSqrB)); }
public void CustomCalculateSegmentPositionPathFinder(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position position, uint laneId, byte offset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { var netManager = Singleton <NetManager> .instance; netManager.m_lanes.m_buffer[laneId].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir); var segmentInfo = netManager.m_segments.m_buffer[position.m_segment].Info; if (segmentInfo.m_lanes != null && segmentInfo.m_lanes.Length > position.m_lane) { // NON-STOCK CODE START float laneSpeedLimit = 1f; #if BENCHMARK using (var bm = new Benchmark(null, "GetLockFreeGameSpeedLimit")) { #endif if (!Options.customSpeedLimitsEnabled) { laneSpeedLimit = segmentInfo.m_lanes[position.m_lane].m_speedLimit; } else { // === START INLINED VERSION OF SpeedLimitManager.GetLockFreeGameSpeedLimit === ushort?[] fastArray = Flags.laneSpeedLimitArray[position.m_segment]; if (fastArray != null && fastArray.Length > position.m_lane && fastArray[position.m_lane] != null) { // === START INLINED VERSION OF SpeedLimitManager.ToGameSpeedLimit === laneSpeedLimit = (float)fastArray[position.m_lane]; if (laneSpeedLimit == 0) { laneSpeedLimit = SpeedLimitManager.MAX_SPEED; } else { laneSpeedLimit = laneSpeedLimit / 50f; } // === END INLINED VERSION OF SpeedLimitManager.ToGameSpeedLimit === // laneSpeedLimit = ToGameSpeedLimit((ushort)fastArray[position.m_lane]); } else { laneSpeedLimit = segmentInfo.m_lanes[position.m_lane].m_speedLimit; } // === END INLINED VERSION OF SpeedLimitManager.GetLockFreeGameSpeedLimit === //laneSpeedLimit = SpeedLimitManager.Instance.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, segmentInfo.m_lanes[position.m_lane]); // info2.m_lanes[position.m_lane].m_speedLimit; // NON-STOCK CODE } //laneSpeedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneId, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; // NON-STOCK CODE #if BENCHMARK } #endif // NON-STOCK CODE END maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[laneId].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } // NON-STOCK CODE START (stock code replaced) bool isRecklessDriver = VehicleStateManager.Instance.VehicleStates[vehicleId].recklessDriver; #if BENCHMARK using (var bm = new Benchmark(null, "CalcMaxSpeed")) { #endif // === START INLINED VERSION OF VehicleBehaviorManager.CalcMaxSpeed === if (Singleton <NetManager> .instance.m_treatWetAsSnow) { DistrictManager districtManager = Singleton <DistrictManager> .instance; byte district = districtManager.GetDistrict(pos); DistrictPolicies.CityPlanning cityPlanningPolicies = districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPolicies; if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.StuddedTires) != DistrictPolicies.CityPlanning.None) { if (Options.strongerRoadConditionEffects) { if (maxSpeed > VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED) { maxSpeed = VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.0005882353f; // vanilla: -15% .. ±0% } districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPoliciesEffect |= DistrictPolicies.CityPlanning.StuddedTires; } else { if (Options.strongerRoadConditionEffects) { if (maxSpeed > VehicleBehaviorManager.ICY_ROADS_MIN_SPEED) { maxSpeed = VehicleBehaviorManager.ICY_ROADS_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - VehicleBehaviorManager.ICY_ROADS_MIN_SPEED); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.00117647066f; // vanilla: -30% .. ±0% } } } else { if (Options.strongerRoadConditionEffects) { float minSpeed = Math.Min(maxSpeed * VehicleBehaviorManager.WET_ROADS_FACTOR, VehicleBehaviorManager.WET_ROADS_MAX_SPEED); // custom: -25% .. 0 if (maxSpeed > minSpeed) { maxSpeed = minSpeed + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - minSpeed); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.0005882353f; // vanilla: -15% .. ±0% } } if (Options.strongerRoadConditionEffects) { float minSpeed = Math.Min(maxSpeed * VehicleBehaviorManager.BROKEN_ROADS_FACTOR, VehicleBehaviorManager.BROKEN_ROADS_MAX_SPEED); if (maxSpeed > minSpeed) { maxSpeed = minSpeed + (float)netManager.m_segments.m_buffer[position.m_segment].m_condition * 0.0039215686f * (maxSpeed - minSpeed); } } else { maxSpeed *= 1f + (float)netManager.m_segments.m_buffer[position.m_segment].m_condition * 0.0005882353f; // vanilla: ±0% .. +15 % } // === START INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds === if (Options.realisticSpeeds) { // === START INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds === float vehicleRand = 0.01f * (float)(vehicleId % 100); // float vehicleRand = 0.01f * (float)GetVehicleRand(vehicleId); // === END INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds === if (this.m_info.m_isLargeVehicle) { maxSpeed *= 0.9f + vehicleRand * 0.1f; // a little variance, 0.9 .. 1 } else if (isRecklessDriver) { maxSpeed *= 1.3f + vehicleRand * 1.7f; // woohooo, 1.3 .. 3 } else { maxSpeed *= 0.8f + vehicleRand * 0.5f; // a little variance, 0.8 .. 1.3 } } else if (isRecklessDriver) { maxSpeed *= 1.5f; } // === END INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds === //maxSpeed = ApplyRealisticSpeeds(maxSpeed, vehicleId, this.m_info, isRecklessDriver); maxSpeed = Math.Max(VehicleBehaviorManager.MIN_SPEED, maxSpeed); // at least 10 km/h // === END INLINED VERSION OF VehicleBehaviorManager.CalcMaxSpeed === //maxSpeed = VehicleBehaviorManager.Instance.CalcMaxSpeed(vehicleId, this.m_info, position, ref netManager.m_segments.m_buffer[position.m_segment], pos, maxSpeed, isRecklessDriver); #if BENCHMARK } #endif // NON-STOCK CODE END }
public bool CreatePath(out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPos, PathUnit.Position endPos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isServiceVehicle) { PathUnit.Position position = default(PathUnit.Position); return(this.CreatePath(out unit, ref randomizer, buildIndex, startPos, position, endPos, position, position, laneTypes, vehicleTypes, maxLength, false, false, false, false, isServiceVehicle)); }
public void CustomCalculateSegmentPositionPathFinder(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position position, uint laneId, byte offset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { var netManager = Singleton <NetManager> .instance; netManager.m_lanes.m_buffer[(int)((UIntPtr)laneId)].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir); var info = netManager.m_segments.m_buffer[position.m_segment].Info; if (info.m_lanes != null && info.m_lanes.Length > position.m_lane) { var laneSpeedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneId, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneId)].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } maxSpeed = CalcMaxSpeed(vehicleId, ref vehicleData, position, pos, maxSpeed, IsRecklessDriver(vehicleId, ref vehicleData)); }
public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { var netManager = Singleton <NetManager> .instance; ushort targetNodeId; ushort nextTargetNodeId; if (offset < position.m_offset) { targetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode; nextTargetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode; } else { targetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode; nextTargetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode; } var prevTargetNodeId = prevOffset == 0 ? netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode : netManager.m_segments.m_buffer[prevPos.m_segment].m_endNode; Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); Vector3 lastFrameVehiclePos = lastFrameData.m_position; float sqrVelocity = lastFrameData.m_velocity.sqrMagnitude; netManager.m_lanes.m_buffer[laneID].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir); float braking = this.m_info.m_braking; if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) != (Vehicle.Flags) 0) { braking *= 2f; } // car position on the Bezier curve of the lane var vehiclePosOnBezier = netManager.m_lanes.m_buffer[prevLaneID].CalculatePosition(prevOffset * 0.003921569f); //ushort currentSegmentId = netManager.m_lanes.m_buffer[prevLaneID].m_segment; // this seems to be like the required braking force in order to stop the vehicle within its half length. var crazyValue = 0.5f * sqrVelocity / braking + m_info.m_generatedInfo.m_size.z * 0.5f; bool withinBrakingDistance = Vector3.Distance(lastFrameVehiclePos, vehiclePosOnBezier) >= crazyValue - 1f; // NON-STOCK CODE START #if BENCHMARK using (var bm = new Benchmark(null, "UpdateVehiclePosition")) { #endif VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData, lastFrameData.m_velocity.magnitude); #if BENCHMARK } #endif // NON-STOCK CODE END bool isRecklessDriver = VehicleStateManager.Instance.VehicleStates[vehicleId].recklessDriver; if (targetNodeId == prevTargetNodeId && withinBrakingDistance) { // NON-STOCK CODE START (stock code replaced) #if BENCHMARK using (var bm = new Benchmark(null, "MayChangeSegment")) { #endif //bool isRecklessDriver = VehicleStateManager.Instance.IsRecklessDriver(vehicleId, ref vehicleData); // NON-STOCK CODE if (!VehicleBehaviorManager.Instance.MayChangeSegment(vehicleId, ref VehicleStateManager.Instance.VehicleStates[vehicleId], ref vehicleData, sqrVelocity, isRecklessDriver, ref prevPos, ref netManager.m_segments.m_buffer[prevPos.m_segment], prevTargetNodeId, prevLaneID, ref position, targetNodeId, ref netManager.m_nodes.m_buffer[targetNodeId], laneID, ref nextPosition, nextTargetNodeId, out maxSpeed)) // NON-STOCK CODE { return; } #if BENCHMARK } #endif // NON-STOCK CODE END } var segmentInfo = netManager.m_segments.m_buffer[position.m_segment].Info; if (segmentInfo.m_lanes != null && segmentInfo.m_lanes.Length > position.m_lane) { // NON-STOCK CODE START // NON-STOCK CODE START float laneSpeedLimit = 1f; #if BENCHMARK using (var bm = new Benchmark(null, "GetLockFreeGameSpeedLimit")) { #endif if (!Options.customSpeedLimitsEnabled) { laneSpeedLimit = segmentInfo.m_lanes[position.m_lane].m_speedLimit; } else { // === START INLINED VERSION OF SpeedLimitManager.GetLockFreeGameSpeedLimit === ushort?[] fastArray = Flags.laneSpeedLimitArray[position.m_segment]; if (fastArray != null && fastArray.Length > position.m_lane && fastArray[position.m_lane] != null) { // === START INLINED VERSION OF SpeedLimitManager.ToGameSpeedLimit === laneSpeedLimit = (float)fastArray[position.m_lane]; if (laneSpeedLimit == 0) { laneSpeedLimit = SpeedLimitManager.MAX_SPEED; } else { laneSpeedLimit = laneSpeedLimit / 50f; } // === END INLINED VERSION OF SpeedLimitManager.ToGameSpeedLimit === // laneSpeedLimit = ToGameSpeedLimit((ushort)fastArray[position.m_lane]); } else { laneSpeedLimit = segmentInfo.m_lanes[position.m_lane].m_speedLimit; } // === END INLINED VERSION OF SpeedLimitManager.GetLockFreeGameSpeedLimit === //laneSpeedLimit = SpeedLimitManager.Instance.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, segmentInfo.m_lanes[position.m_lane]); // info2.m_lanes[position.m_lane].m_speedLimit; // NON-STOCK CODE } #if BENCHMARK } #endif // NON-STOCK CODE END maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[laneID].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } // NON-STOCK CODE START (stock code replaced) #if BENCHMARK using (var bm = new Benchmark(null, "CalcMaxSpeed")) { #endif // === START INLINED VERSION OF VehicleBehaviorManager.CalcMaxSpeed === if (Singleton <NetManager> .instance.m_treatWetAsSnow) { DistrictManager districtManager = Singleton <DistrictManager> .instance; byte district = districtManager.GetDistrict(pos); DistrictPolicies.CityPlanning cityPlanningPolicies = districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPolicies; if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.StuddedTires) != DistrictPolicies.CityPlanning.None) { if (Options.strongerRoadConditionEffects) { if (maxSpeed > VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED) { maxSpeed = VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.0005882353f; // vanilla: -15% .. ±0% } districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPoliciesEffect |= DistrictPolicies.CityPlanning.StuddedTires; } else { if (Options.strongerRoadConditionEffects) { if (maxSpeed > VehicleBehaviorManager.ICY_ROADS_MIN_SPEED) { maxSpeed = VehicleBehaviorManager.ICY_ROADS_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - VehicleBehaviorManager.ICY_ROADS_MIN_SPEED); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.00117647066f; // vanilla: -30% .. ±0% } } } else { if (Options.strongerRoadConditionEffects) { float minSpeed = Math.Min(maxSpeed * VehicleBehaviorManager.WET_ROADS_FACTOR, VehicleBehaviorManager.WET_ROADS_MAX_SPEED); // custom: -25% .. 0 if (maxSpeed > minSpeed) { maxSpeed = minSpeed + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - minSpeed); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.0005882353f; // vanilla: -15% .. ±0% } } if (Options.strongerRoadConditionEffects) { float minSpeed = Math.Min(maxSpeed * VehicleBehaviorManager.BROKEN_ROADS_FACTOR, VehicleBehaviorManager.BROKEN_ROADS_MAX_SPEED); if (maxSpeed > minSpeed) { maxSpeed = minSpeed + (float)netManager.m_segments.m_buffer[position.m_segment].m_condition * 0.0039215686f * (maxSpeed - minSpeed); } } else { maxSpeed *= 1f + (float)netManager.m_segments.m_buffer[position.m_segment].m_condition * 0.0005882353f; // vanilla: ±0% .. +15 % } // === START INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds === if (Options.realisticSpeeds) { // === START INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds === float vehicleRand = 0.01f * (float)(vehicleId % 100); // float vehicleRand = 0.01f * (float)GetVehicleRand(vehicleId); // === END INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds === if (this.m_info.m_isLargeVehicle) { maxSpeed *= 0.9f + vehicleRand * 0.1f; // a little variance, 0.9 .. 1 } else if (isRecklessDriver) { maxSpeed *= 1.3f + vehicleRand * 1.7f; // woohooo, 1.3 .. 3 } else { maxSpeed *= 0.8f + vehicleRand * 0.5f; // a little variance, 0.8 .. 1.3 } } else if (isRecklessDriver) { maxSpeed *= 1.5f; } // === END INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds === //maxSpeed = ApplyRealisticSpeeds(maxSpeed, vehicleId, this.m_info, isRecklessDriver); maxSpeed = Math.Max(VehicleBehaviorManager.MIN_SPEED, maxSpeed); // at least 10 km/h // === END INLINED VERSION OF VehicleBehaviorManager.CalcMaxSpeed === //maxSpeed = VehicleBehaviorManager.Instance.CalcMaxSpeed(vehicleId, this.m_info, position, ref netManager.m_segments.m_buffer[position.m_segment], pos, maxSpeed, isRecklessDriver); #if BENCHMARK } #endif // NON-STOCK CODE END }
internal static float CalcMaxSpeed(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position position, Vector3 pos, float maxSpeed, bool isRecklessDriver) { var netManager = Singleton <NetManager> .instance; NetInfo segmentInfo = netManager.m_segments.m_buffer[(int)position.m_segment].Info; bool highwayRules = (segmentInfo.m_netAI is RoadBaseAI && ((RoadBaseAI)segmentInfo.m_netAI).m_highwayRules); if (!highwayRules) { if (netManager.m_treatWetAsSnow) { DistrictManager districtManager = Singleton <DistrictManager> .instance; byte district = districtManager.GetDistrict(pos); DistrictPolicies.CityPlanning cityPlanningPolicies = districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPolicies; if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.StuddedTires) != DistrictPolicies.CityPlanning.None) { if (Options.strongerRoadConditionEffects) { if (maxSpeed > ICY_ROADS_STUDDED_MIN_SPEED) { maxSpeed = ICY_ROADS_STUDDED_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - ICY_ROADS_STUDDED_MIN_SPEED); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.0005882353f; // vanilla: -15% .. � } districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPoliciesEffect |= DistrictPolicies.CityPlanning.StuddedTires; } else { if (Options.strongerRoadConditionEffects) { if (maxSpeed > ICY_ROADS_MIN_SPEED) { maxSpeed = ICY_ROADS_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - ICY_ROADS_MIN_SPEED); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.00117647066f; // vanilla: -30% .. � } } } else { if (Options.strongerRoadConditionEffects) { float minSpeed = Math.Min(maxSpeed * WET_ROADS_FACTOR, WET_ROADS_MAX_SPEED); if (maxSpeed > minSpeed) { maxSpeed = minSpeed + (float)(255 - netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - minSpeed); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.0005882353f; // vanilla: -15% .. � } } if (Options.strongerRoadConditionEffects) { float minSpeed = Math.Min(maxSpeed * BROKEN_ROADS_FACTOR, BROKEN_ROADS_MAX_SPEED); if (maxSpeed > minSpeed) { maxSpeed = minSpeed + (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_condition * 0.0039215686f * (maxSpeed - minSpeed); } } else { maxSpeed *= 1f + (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_condition * 0.0005882353f; // vanilla: � .. +15 % } } //ExtVehicleType? vehicleType = VehicleStateManager.GetVehicleState(vehicleId)?.VehicleType; float vehicleRand = Math.Min(1f, (float)(vehicleId % 101) * 0.01f); // we choose 101 because it's a prime number if (isRecklessDriver) { maxSpeed *= 1.5f + vehicleRand * 0.5f; // woohooo, 1.5 .. 2 } else { maxSpeed *= 0.7f + vehicleRand * 0.6f; // a little variance, 0.7 .. 1.3 } /*else if ((vehicleType & ExtVehicleType.PassengerCar) != ExtVehicleType.None) * maxSpeed *= 0.7f + vehicleRand * 0.4f; // a little variance, 0.7 .. 1.1 * else if ((vehicleType & ExtVehicleType.Taxi) != ExtVehicleType.None) * maxSpeed *= 0.9f + vehicleRand * 0.4f; // a little variance, 0.9 .. 1.3*/ maxSpeed = Math.Max(MIN_SPEED, maxSpeed); // at least 10 km/h return(maxSpeed); }
public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { if ((Options.prioritySignsEnabled || Options.timedLightsEnabled) && Options.simAccuracy <= 1) { try { VehicleStateManager.Instance().UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position); } catch (Exception e) { Log.Error("CarAI CustomCalculateSegmentPosition Error: " + e.ToString()); } } var netManager = Singleton <NetManager> .instance; //var vehicleManager = Singleton<VehicleManager>.instance; netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir); Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); Vector3 lastFrameVehiclePos = lastFrameData.m_position; var camPos = Camera.main.transform.position; #if DEBUG //bool isEmergency = VehicleStateManager._GetVehicleState(vehicleId).VehicleType == ExtVehicleType.Emergency; #endif // I think this is supposed to be the lane position? // [VN, 12/23/2015] It's the 3D car position on the Bezier curve of the lane. // This crazy 0.003921569f equals to 1f/255 and prevOffset is the byte value (0..255) of the car position. var vehiclePosOnBezier = netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].CalculatePosition(prevOffset * 0.003921569f); //ushort currentSegmentId = netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_segment; ushort targetNodeId; ushort nextTargetNodeId; if (offset < position.m_offset) { targetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode; nextTargetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode; } else { targetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode; nextTargetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode; } var prevTargetNodeId = prevOffset == 0 ? netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode : netManager.m_segments.m_buffer[prevPos.m_segment].m_endNode; // this seems to be like the required braking force in order to stop the vehicle within its half length. var crazyValue = 0.5f * lastFrameData.m_velocity.sqrMagnitude / m_info.m_braking + m_info.m_generatedInfo.m_size.z * 0.5f; /*try { * VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData); * } catch (Exception e) { * Log.Error("CarAI TmCalculateSegmentPosition Error: " + e.ToString()); * }*/ bool isRecklessDriver = IsRecklessDriver(vehicleId, ref vehicleData); if (targetNodeId == prevTargetNodeId) { if (Vector3.Distance(lastFrameVehiclePos, vehiclePosOnBezier) >= crazyValue - 1f) { if (!CustomVehicleAI.MayChangeSegment(vehicleId, ref vehicleData, ref lastFrameData, isRecklessDriver, ref prevPos, prevTargetNodeId, prevLaneID, ref position, targetNodeId, laneID, ref nextPosition, nextTargetNodeId, out maxSpeed)) { return; } } } var info2 = netManager.m_segments.m_buffer[position.m_segment].Info; if (info2.m_lanes != null && info2.m_lanes.Length > position.m_lane) { var laneSpeedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance().GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info2.m_lanes[position.m_lane]) : info2.m_lanes[position.m_lane].m_speedLimit; // info2.m_lanes[position.m_lane].m_speedLimit; #if DEBUG /*if (position.m_segment == 275) { * Log._Debug($"Applying lane speed limit of {laneSpeedLimit} to lane {laneID} @ seg. {position.m_segment}"); * }*/ #endif maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } maxSpeed = CalcMaxSpeed(vehicleId, ref vehicleData, position, pos, maxSpeed, isRecklessDriver); }
public static bool Prefix(TrolleybusAI __instance, ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { NetManager netManager = Singleton <NetManager> .instance; ushort prevSourceNodeId; ushort prevTargetNodeId; NetSegment[] segBuffer = netManager.m_segments.m_buffer; if (offset < position.m_offset) { prevSourceNodeId = segBuffer[position.m_segment].m_startNode; prevTargetNodeId = segBuffer[position.m_segment].m_endNode; } else { prevSourceNodeId = segBuffer[position.m_segment].m_endNode; prevTargetNodeId = segBuffer[position.m_segment].m_startNode; } ushort refTargetNodeId = prevOffset == 0 ? segBuffer[prevPos.m_segment].m_startNode : segBuffer[prevPos.m_segment].m_endNode; Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); float sqrVelocity = lastFrameData.m_velocity.sqrMagnitude; netManager.m_lanes.m_buffer[laneID].CalculatePositionAndDirection( Constants.ByteToFloat(offset), out pos, out dir); Vector3 b = netManager.m_lanes.m_buffer[prevLaneID].CalculatePosition( Constants.ByteToFloat(prevOffset)); Vector3 a = lastFrameData.m_position; Vector3 a2 = lastFrameData.m_position; Vector3 b2 = lastFrameData.m_rotation * new Vector3( 0f, 0f, __instance.m_info.m_generatedInfo.m_wheelBase * 0.5f); a += b2; a2 -= b2; float crazyValue = 0.5f * sqrVelocity / __instance.m_info.m_braking; float a3 = Vector3.Distance(a, b); float b3 = Vector3.Distance(a2, b); if (Mathf.Min(a3, b3) >= crazyValue - 1f) { if (prevSourceNodeId == refTargetNodeId) { if (!VehicleBehaviorManager.Instance.MayChangeSegment( vehicleID, ref vehicleData, sqrVelocity, ref prevPos, ref segBuffer[prevPos.m_segment], refTargetNodeId, prevLaneID, ref position, prevSourceNodeId, ref netManager.m_nodes.m_buffer[ prevSourceNodeId], laneID, ref nextPosition, prevTargetNodeId, out maxSpeed)) { maxSpeed = 0; return(false); } ExtVehicleManager.Instance.UpdateVehiclePosition( vehicleID, ref vehicleData); } } NetInfo info = segBuffer[position.m_segment].Info; VehicleAICommons.CustomCalculateTargetSpeed( __instance, vehicleID, ref vehicleData, position, laneID, info, out maxSpeed); // NON-STOCK CODE END return(false); }
protected override bool SpawnVehicle(ushort instanceID, ref CitizenInstance citizenData, PathUnit.Position pathPos) { VehicleManager instance = Singleton <VehicleManager> .instance; float num = 20f; int num2 = Mathf.Max((int)((citizenData.m_targetPos.x - num) / 32f + 270f), 0); int num3 = Mathf.Max((int)((citizenData.m_targetPos.z - num) / 32f + 270f), 0); int num4 = Mathf.Min((int)((citizenData.m_targetPos.x + num) / 32f + 270f), 539); int num5 = Mathf.Min((int)((citizenData.m_targetPos.z + num) / 32f + 270f), 539); for (int i = num3; i <= num5; i++) { for (int j = num2; j <= num4; j++) { ushort num6 = instance.m_vehicleGrid [i * 540 + j]; int num7 = 0; while (num6 != 0) { if (this.TryJoinVehicle(instanceID, ref citizenData, num6, ref instance.m_vehicles.m_buffer [(int)num6])) { citizenData.m_flags |= CitizenInstance.Flags.EnteringVehicle; citizenData.m_flags &= ~CitizenInstance.Flags.TryingSpawnVehicle; citizenData.m_flags &= ~CitizenInstance.Flags.BoredOfWaiting; citizenData.m_waitCounter = 0; return(true); } num6 = instance.m_vehicles.m_buffer [(int)num6].m_nextGridVehicle; if (++num7 > 65536) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } NetManager instance2 = Singleton <NetManager> .instance; CitizenManager instance3 = Singleton <CitizenManager> .instance; Vector3 vector = Vector3.zero; Quaternion rotation = Quaternion.identity; ushort num8 = instance3.m_citizens.m_buffer [(int)((UIntPtr)citizenData.m_citizen)].m_parkedVehicle; if (num8 != 0) { vector = instance.m_parkedVehicles.m_buffer [(int)num8].m_position; rotation = instance.m_parkedVehicles.m_buffer [(int)num8].m_rotation; } VehicleInfo vehicleInfo = this.GetVehicleInfo(instanceID, ref citizenData, false); if (vehicleInfo == null || vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { instance3.m_citizens.m_buffer [(int)((UIntPtr)citizenData.m_citizen)].SetParkedVehicle(citizenData.m_citizen, 0); if ((citizenData.m_flags & CitizenInstance.Flags.TryingSpawnVehicle) == CitizenInstance.Flags.None) { citizenData.m_flags |= CitizenInstance.Flags.TryingSpawnVehicle; citizenData.m_flags &= ~CitizenInstance.Flags.BoredOfWaiting; citizenData.m_waitCounter = 0; } return(true); } if (vehicleInfo.m_class.m_subService == ItemClass.SubService.PublicTransportTaxi) { instance3.m_citizens.m_buffer [(int)((UIntPtr)citizenData.m_citizen)].SetParkedVehicle(citizenData.m_citizen, 0); if ((citizenData.m_flags & CitizenInstance.Flags.WaitingTaxi) == CitizenInstance.Flags.None) { citizenData.m_flags |= CitizenInstance.Flags.WaitingTaxi; citizenData.m_flags &= ~CitizenInstance.Flags.BoredOfWaiting; citizenData.m_waitCounter = 0; } return(true); } uint laneID = PathManager.GetLaneID(pathPos); Vector3 vector2 = citizenData.m_targetPos; if (num8 != 0 && Vector3.SqrMagnitude(vector - vector2) < 1024f) { vector2 = vector; } else { num8 = 0; } Vector3 a; float num9; instance2.m_lanes.m_buffer [(int)((UIntPtr)laneID)].GetClosestPosition(vector2, out a, out num9); byte lastPathOffset = (byte)Mathf.Clamp(Mathf.RoundToInt(num9 * 255f), 0, 255); a = vector2 + Vector3.ClampMagnitude(a - vector2, 5f); ushort num10; if (instance.CreateVehicle(out num10, ref Singleton <SimulationManager> .instance.m_randomizer, vehicleInfo, vector2, TransferManager.TransferReason.None, false, false)) { Vehicle.Frame frame = instance.m_vehicles.m_buffer [(int)num10].m_frame0; if (num8 != 0) { frame.m_rotation = rotation; } else { Vector3 forward = a - citizenData.GetLastFrameData().m_position; if (forward.sqrMagnitude > 0.01f) { frame.m_rotation = Quaternion.LookRotation(forward); } } instance.m_vehicles.m_buffer [(int)num10].m_frame0 = frame; instance.m_vehicles.m_buffer [(int)num10].m_frame1 = frame; instance.m_vehicles.m_buffer [(int)num10].m_frame2 = frame; instance.m_vehicles.m_buffer [(int)num10].m_frame3 = frame; vehicleInfo.m_vehicleAI.FrameDataUpdated(num10, ref instance.m_vehicles.m_buffer [(int)num10], ref frame); instance.m_vehicles.m_buffer [(int)num10].m_targetPos0 = new Vector4(a.x, a.y, a.z, 2f); Vehicle[] expr_4E5_cp_0 = instance.m_vehicles.m_buffer; ushort expr_4E5_cp_1 = num10; expr_4E5_cp_0 [(int)expr_4E5_cp_1].m_flags = (expr_4E5_cp_0 [(int)expr_4E5_cp_1].m_flags | Vehicle.Flags.Stopped); instance.m_vehicles.m_buffer [(int)num10].m_path = citizenData.m_path; instance.m_vehicles.m_buffer [(int)num10].m_pathPositionIndex = citizenData.m_pathPositionIndex; instance.m_vehicles.m_buffer [(int)num10].m_lastPathOffset = lastPathOffset; instance.m_vehicles.m_buffer [(int)num10].m_transferSize = (ushort)(citizenData.m_citizen & 65535u); vehicleInfo.m_vehicleAI.TrySpawn(num10, ref instance.m_vehicles.m_buffer [(int)num10]); if (num8 != 0) { InstanceID empty = InstanceID.Empty; empty.ParkedVehicle = num8; InstanceID empty2 = InstanceID.Empty; empty2.Vehicle = num10; Singleton <InstanceManager> .instance.ChangeInstance(empty, empty2); } citizenData.m_path = 0u; instance3.m_citizens.m_buffer [(int)((UIntPtr)citizenData.m_citizen)].SetParkedVehicle(citizenData.m_citizen, 0); instance3.m_citizens.m_buffer [(int)((UIntPtr)citizenData.m_citizen)].SetVehicle(citizenData.m_citizen, num10, 0u); citizenData.m_flags |= CitizenInstance.Flags.EnteringVehicle; citizenData.m_flags &= ~CitizenInstance.Flags.TryingSpawnVehicle; citizenData.m_flags &= ~CitizenInstance.Flags.BoredOfWaiting; citizenData.m_waitCounter = 0; return(true); } instance3.m_citizens.m_buffer [(int)((UIntPtr)citizenData.m_citizen)].SetParkedVehicle(citizenData.m_citizen, 0); if ((citizenData.m_flags & CitizenInstance.Flags.TryingSpawnVehicle) == CitizenInstance.Flags.None) { citizenData.m_flags |= CitizenInstance.Flags.TryingSpawnVehicle; citizenData.m_flags &= ~CitizenInstance.Flags.BoredOfWaiting; citizenData.m_waitCounter = 0; } return(true); }
public bool CreatePath(out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue, bool isServiceVehicle) { return(this.CreatePath(out unit, ref randomizer, buildIndex, startPosA, startPosB, endPosA, endPosB, default(PathUnit.Position), laneTypes, vehicleTypes, maxLength, isHeavyVehicle, ignoreBlocked, stablePath, skipQueue, isServiceVehicle)); }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { #if DEBUG //Log._Debug($"CustomTaxiAI.CustomStartPathFind called for vehicle {vehicleID}"); #endif CitizenManager instance = Singleton <CitizenManager> .instance; ushort passengerInstanceId = CustomTaxiAI.GetPassengerInstance(vehicleID, ref vehicleData); if (passengerInstanceId == 0 || (instance.m_instances.m_buffer[(int)passengerInstanceId].m_flags & CitizenInstance.Flags.Character) != CitizenInstance.Flags.None) { return(base.StartPathFind(vehicleID, ref vehicleData, startPos, endPos, startBothWays, endBothWays, undergroundTarget)); } VehicleInfo info = this.m_info; CitizenInfo info2 = instance.m_instances.m_buffer[(int)passengerInstanceId].Info; NetInfo.LaneType laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.Pedestrian | NetInfo.LaneType.TransportVehicle; VehicleInfo.VehicleType vehicleTypes = this.m_info.m_vehicleType; bool allowUnderground = (vehicleData.m_flags & Vehicle.Flags.Underground) != 0; PathUnit.Position startPosA; PathUnit.Position startPosB; float startSqrDistA; float startSqrDistB; PathUnit.Position endPosA; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out startSqrDistA, out startSqrDistB) && info2.m_citizenAI.FindPathPosition(passengerInstanceId, ref instance.m_instances.m_buffer[(int)passengerInstanceId], endPos, laneTypes, vehicleTypes, undergroundTarget, out endPosA)) { if ((instance.m_instances.m_buffer[(int)passengerInstanceId].m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None) { laneTypes |= NetInfo.LaneType.PublicTransport; uint citizenId = instance.m_instances.m_buffer[passengerInstanceId].m_citizen; if (citizenId != 0u && (instance.m_citizens.m_buffer[citizenId].m_flags & Citizen.Flags.Evacuating) != Citizen.Flags.None) { laneTypes |= NetInfo.LaneType.EvacuationTransport; } } if (!startBothWays || startSqrDistA < 10f) { startPosB = default(PathUnit.Position); } PathUnit.Position endPosB = default(PathUnit.Position); SimulationManager simMan = Singleton <SimulationManager> .instance; uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtCitizenInstance.ExtPathType.None; args.extVehicleType = ExtVehicleType.Taxi; args.vehicleId = vehicleID; args.buildIndex = simMan.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default(PathUnit.Position); args.laneTypes = laneTypes; args.vehicleTypes = vehicleTypes; args.maxLength = 20000f; args.isHeavyVehicle = this.IsHeavyVehicle(); args.hasCombustionEngine = this.CombustionEngine(); args.ignoreBlocked = this.IgnoreBlocked(vehicleID, ref vehicleData); args.ignoreFlooded = false; args.ignoreCosts = false; args.randomParking = false; args.stablePath = false; args.skipQueue = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; if (CustomPathManager._instance.CreatePath(out path, ref simMan.m_randomizer, args)) { // NON-STOCK CODE END if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
public bool CreatePath(out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, PathUnit.Position vehiclePosition, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue, bool isServiceVehicle) { while (!Monitor.TryEnter(this.m_bufferLock, SimulationManager.SYNCHRONIZE_TIMEOUT)) { } uint num; try { if (!this.m_pathUnits.CreateItem(out num, ref randomizer)) { unit = 0u; bool result = false; return(result); } this.m_pathUnitCount = (int)(this.m_pathUnits.ItemCount() - 1u); } finally { Monitor.Exit(this.m_bufferLock); } unit = num; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags = 1; if (isServiceVehicle) { PathUnit[] pathUnits = this.m_pathUnits.m_buffer; UIntPtr unitIndex = (UIntPtr)unit; pathUnits[(int)unitIndex].m_simulationFlags = (byte)(pathUnits[(int)unitIndex].m_simulationFlags | 8); } if (isHeavyVehicle) { PathUnit[] expr_92_cp_0 = this.m_pathUnits.m_buffer; UIntPtr expr_92_cp_1 = (UIntPtr)unit; expr_92_cp_0[(int)expr_92_cp_1].m_simulationFlags = (byte)(expr_92_cp_0[(int)expr_92_cp_1].m_simulationFlags | 16); } if (ignoreBlocked) { PathUnit[] expr_BB_cp_0 = this.m_pathUnits.m_buffer; UIntPtr expr_BB_cp_1 = (UIntPtr)unit; expr_BB_cp_0[(int)expr_BB_cp_1].m_simulationFlags = (byte)(expr_BB_cp_0[(int)expr_BB_cp_1].m_simulationFlags | 32); } if (stablePath) { PathUnit[] expr_E4_cp_0 = this.m_pathUnits.m_buffer; UIntPtr expr_E4_cp_1 = (UIntPtr)unit; expr_E4_cp_0[(int)expr_E4_cp_1].m_simulationFlags = (byte)(expr_E4_cp_0[(int)expr_E4_cp_1].m_simulationFlags | 64); } this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_pathFindFlags = 0; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_buildIndex = buildIndex; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_position00 = startPosA; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_position01 = endPosA; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_position02 = startPosB; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_position03 = endPosB; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_position11 = vehiclePosition; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_nextPathUnit = 0u; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_laneTypes = (byte)laneTypes; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_vehicleTypes = (byte)vehicleTypes; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_length = maxLength; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount = 20; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_referenceCount = 1; int num2 = 10000000; CustomPathFind pathFind = null; for (int i = 0; i < this.m_pathFinds.Length; i++) { CustomPathFind pathFind2 = this.m_pathFinds[i]; if (pathFind2.IsAvailable && pathFind2.m_queuedPathFindCount < num2) { num2 = pathFind2.m_queuedPathFindCount; pathFind = pathFind2; } } if (pathFind != null && pathFind.CalculatePath(unit, skipQueue)) { return(true); } this.ReleasePath(unit); return(false); }
public bool CustomFindPathPosition(ushort instanceID, ref CitizenInstance citizenData, Vector3 pos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, bool allowUnderground, out PathUnit.Position position) { position = default(PathUnit.Position); float minDist = 1E+10f; PathUnit.Position posA; PathUnit.Position posB; float distA; float distB; if (PathManager.FindPathPosition(pos, ItemClass.Service.Road, laneTypes, vehicleTypes, allowUnderground, false, Options.prohibitPocketCars ? GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, out posA, out posB, out distA, out distB) && distA < minDist) { minDist = distA; position = posA; } if (PathManager.FindPathPosition(pos, ItemClass.Service.Beautification, laneTypes, vehicleTypes, allowUnderground, false, Options.prohibitPocketCars ? GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, out posA, out posB, out distA, out distB) && distA < minDist) { minDist = distA; position = posA; } if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None && PathManager.FindPathPosition(pos, ItemClass.Service.PublicTransport, laneTypes, vehicleTypes, allowUnderground, false, Options.prohibitPocketCars ? GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, out posA, out posB, out distA, out distB) && distA < minDist) { minDist = distA; position = posA; } return(position.m_segment != 0); }
public static void CargoTruckAI_PreChangeVehicleType(out CargoParcel __state, /*ushort vehicleID,*/ ref Vehicle vehicleData, PathUnit.Position pathPos, uint laneID) { Vector3 vector = NetManager.instance.m_lanes.m_buffer[laneID].CalculatePosition(0.5f); NetInfo info = NetManager.instance.m_segments.m_buffer[pathPos.m_segment].Info; ushort buildingID = BuildingManager.instance.FindBuilding(vector, 100f, info.m_class.m_service, ItemClass.SubService.None, Building.Flags.None, Building.Flags.None); __state = new CargoParcel(buildingID, true, vehicleData.m_transferType, vehicleData.m_transferSize, vehicleData.m_flags); }
public static bool FindPathPositionWithSpiralLoop(Vector3 position, ItemClass.Service service, NetInfo.LaneType laneType, VehicleInfo.VehicleType vehicleType, VehicleInfo.VehicleType stopType, bool allowUnderground, bool requireConnect, float maxDistance, out PathUnit.Position pathPosA, out PathUnit.Position pathPosB, out float distanceSqrA, out float distanceSqrB) { return(FindPathPositionWithSpiralLoop(position, null, service, laneType, vehicleType, stopType, allowUnderground, requireConnect, maxDistance, out pathPosA, out pathPosB, out distanceSqrA, out distanceSqrB)); }
/// <summary> /// Starts path-finding of the walking path from parking position <paramref name="parkPos"/> to target position <paramref name="targetPos"/>. /// </summary> /// <param name="parkPos">Parking position</param> /// <param name="targetPos">Target position</param> /// <returns></returns> internal bool CalculateReturnPath(Vector3 parkPos, Vector3 targetPos) { #if DEBUG bool citDebug = GlobalConfig.Instance.Debug.CitizenId == 0 || GlobalConfig.Instance.Debug.CitizenId == GetCitizenId(); bool debug = GlobalConfig.Instance.Debug.Switches[2] && citDebug; bool fineDebug = GlobalConfig.Instance.Debug.Switches[4] && citDebug; #endif ReleaseReturnPath(); PathUnit.Position parkPathPos; PathUnit.Position targetPathPos; if (CustomPathManager.FindPathPositionWithSpiralLoop(parkPos, ItemClass.Service.Road, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, NetInfo.LaneType.None, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out parkPathPos) && CustomPathManager.FindPathPositionWithSpiralLoop(targetPos, ItemClass.Service.Road, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, NetInfo.LaneType.None, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out targetPathPos)) { PathUnit.Position dummyPathPos = default(PathUnit.Position); uint pathId; PathCreationArgs args; args.extPathType = ExtCitizenInstance.ExtPathType.WalkingOnly; args.extVehicleType = ExtVehicleType.None; args.vehicleId = 0; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = parkPathPos; args.startPosB = dummyPathPos; args.endPosA = targetPathPos; args.endPosB = dummyPathPos; args.vehiclePosition = dummyPathPos; args.laneTypes = NetInfo.LaneType.Pedestrian; args.vehicleTypes = VehicleInfo.VehicleType.None; args.maxLength = 20000f; args.isHeavyVehicle = false; args.hasCombustionEngine = false; args.ignoreBlocked = false; args.ignoreFlooded = false; args.ignoreCosts = false; args.randomParking = false; args.stablePath = false; args.skipQueue = false; if (CustomPathManager._instance.CreatePath(out pathId, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { #if DEBUG if (debug) { Log._Debug($"ExtCitizenInstance.CalculateReturnPath: Path-finding starts for return path of citizen instance {instanceId}, path={pathId}, parkPathPos.segment={parkPathPos.m_segment}, parkPathPos.lane={parkPathPos.m_lane}, targetPathPos.segment={targetPathPos.m_segment}, targetPathPos.lane={targetPathPos.m_lane}"); } #endif returnPathId = pathId; returnPathState = ExtPathState.Calculating; return(true); } } #if DEBUG if (debug) { Log._Debug($"ExtCitizenInstance.CalculateReturnPath: Could not find path position(s) for either the parking position or target position of citizen instance {instanceId}."); } #endif return(false); }
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; bool searchAtCurrentPos = false; if (driverExtInstance.pathMode == ExtPathMode.ParkingFailed) { // previous parking attempt failed driverExtInstance.pathMode = ExtPathMode.CalculatingCarPathToAltParkPos; allowTourists = true; searchAtCurrentPos = 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(searchAtCurrentPos ? vehicleData.GetLastFramePosition() : 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.spawned = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; 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); }
private SearchDirection GetImmediateSearchDirection(ushort hearseID) { Vehicle hearse = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[hearseID]; PathManager pm = Singleton <PathManager> .instance; PathUnit pu = pm.m_pathUnits.m_buffer[hearse.m_path]; byte pi = hearse.m_pathPositionIndex; if (pi == 255) { pi = 0; } PathUnit.Position position = pu.GetPosition(pi >> 1); NetManager nm = Singleton <NetManager> .instance; NetSegment segment = nm.m_segments.m_buffer[position.m_segment]; int laneCount = 0; int leftLane = -1; float leftPosition = float.PositiveInfinity; int rightLane = -1; float rightPosition = float.NegativeInfinity; for (int i = 0; i < segment.Info.m_lanes.Length; i++) { NetInfo.Lane l = segment.Info.m_lanes[i]; if (l.m_laneType != NetInfo.LaneType.Vehicle || l.m_vehicleType != VehicleInfo.VehicleType.Car) { continue; } laneCount++; if (l.m_position < leftPosition) { leftLane = i; leftPosition = l.m_position; } if (l.m_position > rightPosition) { rightLane = i; rightPosition = l.m_position; } } SearchDirection dir = SearchDirection.None; if (laneCount == 0) { } else if (position.m_lane != leftLane && position.m_lane != rightLane) { dir = SearchDirection.Ahead; } else if (leftLane == rightLane) { dir = SearchDirection.Left | SearchDirection.Right | SearchDirection.Ahead; } else if (laneCount == 2 && segment.Info.m_lanes[leftLane].m_direction != segment.Info.m_lanes[rightLane].m_direction) { dir = SearchDirection.Left | SearchDirection.Right | SearchDirection.Ahead; } else { if (position.m_lane == leftLane) { dir = SearchDirection.Left | SearchDirection.Ahead; } else { dir = SearchDirection.Right | SearchDirection.Ahead; } } return(dir); }
// from CitizenAI public static bool FindPathPosition(ushort instanceID, ref CitizenInstance citizenData, Vector3 pos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, out PathUnit.Position position) { position = default(PathUnit.Position); float num = 1E+10f; PathUnit.Position position2; PathUnit.Position position3; float num2; float num3; if (CustomPathManager.FindPathPosition(pos, ItemClass.Service.Road, laneTypes, vehicleTypes, 32f, out position2, out position3, out num2, out num3, RoadManager.VehicleType.PassengerCar) && num2 < num) { num = num2; position = position2; } PathUnit.Position position4; PathUnit.Position position5; float num4; float num5; if (CustomPathManager.FindPathPosition(pos, ItemClass.Service.Beautification, laneTypes, vehicleTypes, 32f, out position4, out position5, out num4, out num5, RoadManager.VehicleType.PassengerCar) && num4 < num) { num = num4; position = position4; } PathUnit.Position position6; PathUnit.Position position7; float num6; float num7; if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None && CustomPathManager.FindPathPosition(pos, ItemClass.Service.PublicTransport, laneTypes, vehicleTypes, 32f, out position6, out position7, out num6, out num7, RoadManager.VehicleType.PassengerCar) && num6 < num) { position = position6; } return(position.m_segment != 0); }
public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); float sqrVelocity = lastFrameData.m_velocity.sqrMagnitude; // NON-STOCK CODE START #if BENCHMARK using (var bm = new Benchmark(null, "UpdateVehiclePosition")) { #endif VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData, lastFrameData.m_velocity.magnitude); #if BENCHMARK } #endif // NON-STOCK CODE END NetManager netManager = Singleton <NetManager> .instance; netManager.m_lanes.m_buffer[laneID].CalculatePositionAndDirection((float)offset * 0.003921569f, out pos, out dir); Vector3 b = netManager.m_lanes.m_buffer[prevLaneID].CalculatePosition((float)prevOffset * 0.003921569f); Vector3 a = lastFrameData.m_position; Vector3 a2 = lastFrameData.m_position; Vector3 b2 = lastFrameData.m_rotation * new Vector3(0f, 0f, this.m_info.m_generatedInfo.m_wheelBase * 0.5f); a += b2; a2 -= b2; float crazyValue = 0.5f * sqrVelocity / this.m_info.m_braking; float a3 = Vector3.Distance(a, b); float b3 = Vector3.Distance(a2, b); if (Mathf.Min(a3, b3) >= crazyValue - 1f) { Segment3 segment; segment.a = pos; ushort targetNodeId; ushort nextTargetNodeId; if (offset < position.m_offset) { segment.b = pos + dir.normalized * this.m_info.m_generatedInfo.m_size.z; targetNodeId = netManager.m_segments.m_buffer[(int)position.m_segment].m_startNode; nextTargetNodeId = netManager.m_segments.m_buffer[(int)position.m_segment].m_endNode; } else { segment.b = pos - dir.normalized * this.m_info.m_generatedInfo.m_size.z; targetNodeId = netManager.m_segments.m_buffer[(int)position.m_segment].m_endNode; nextTargetNodeId = netManager.m_segments.m_buffer[(int)position.m_segment].m_startNode; } ushort prevTargetNodeId; if (prevOffset == 0) { prevTargetNodeId = netManager.m_segments.m_buffer[(int)prevPos.m_segment].m_startNode; } else { prevTargetNodeId = netManager.m_segments.m_buffer[(int)prevPos.m_segment].m_endNode; } if (targetNodeId == prevTargetNodeId) { #if BENCHMARK using (var bm = new Benchmark(null, "MayChangeSegment")) { #endif if (!VehicleBehaviorManager.Instance.MayChangeSegment(vehicleId, ref VehicleStateManager.Instance.VehicleStates[vehicleId], ref vehicleData, sqrVelocity, false, ref prevPos, ref netManager.m_segments.m_buffer[prevPos.m_segment], prevTargetNodeId, prevLaneID, ref position, targetNodeId, ref netManager.m_nodes.m_buffer[targetNodeId], laneID, ref nextPosition, nextTargetNodeId, out maxSpeed)) { return; } #if BENCHMARK } #endif } } NetInfo info = netManager.m_segments.m_buffer[(int)position.m_segment].Info; if (info.m_lanes != null && info.m_lanes.Length > (int)position.m_lane) { float speedLimit = 1; #if BENCHMARK using (var bm = new Benchmark(null, "GetLockFreeGameSpeedLimit")) { #endif speedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; #if BENCHMARK } #endif maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, speedLimit, netManager.m_lanes.m_buffer[laneID].m_curve); } else { maxSpeed = this.CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } }
public new void CalculateSegmentPosition(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { base.CalculateSegmentPosition(vehicleID, ref vehicleData, nextPosition, position, laneID, offset, prevPos, prevLaneID, prevOffset, out pos, out dir, out maxSpeed); }
public void CustomCalculateSegmentPositionPathFinder(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position position, uint laneID, byte offset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { NetManager instance = Singleton <NetManager> .instance; instance.m_lanes.m_buffer[laneID].CalculatePositionAndDirection((float)offset * 0.003921569f, out pos, out dir); NetInfo info = instance.m_segments.m_buffer[(int)position.m_segment].Info; if (info.m_lanes != null && info.m_lanes.Length > (int)position.m_lane) { float speedLimit = 1; #if BENCHMARK using (var bm = new Benchmark(null, "GetLockFreeGameSpeedLimit")) { #endif speedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit; #if BENCHMARK } #endif maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, speedLimit, instance.m_lanes.m_buffer[laneID].m_curve); } else { maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1f, 0f); } }
public new bool NeedChangeVehicleType(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position pathPos, uint laneID, VehicleInfo.VehicleType laneVehicleType, ref Vector4 target) { return(base.NeedChangeVehicleType(vehicleID, ref vehicleData, pathPos, laneID, laneVehicleType, ref target)); }
public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position prevPosition, uint prevLaneId, byte prevOffset, PathUnit.Position refPosition, uint refLaneId, byte refOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { var netManager = Singleton <NetManager> .instance; ushort prevSourceNodeId; ushort prevTargetNodeId; if (prevOffset < prevPosition.m_offset) { prevSourceNodeId = netManager.m_segments.m_buffer[prevPosition.m_segment].m_startNode; prevTargetNodeId = netManager.m_segments.m_buffer[prevPosition.m_segment].m_endNode; } else { prevSourceNodeId = netManager.m_segments.m_buffer[prevPosition.m_segment].m_endNode; prevTargetNodeId = netManager.m_segments.m_buffer[prevPosition.m_segment].m_startNode; } ushort refTargetNodeId; if (refOffset == 0) { refTargetNodeId = netManager.m_segments.m_buffer[(int)refPosition.m_segment].m_startNode; } else { refTargetNodeId = netManager.m_segments.m_buffer[(int)refPosition.m_segment].m_endNode; } #if DEBUG bool debug = GlobalConfig.Instance.Debug.Switches[21] && (GlobalConfig.Instance.Debug.NodeId <= 0 || refTargetNodeId == GlobalConfig.Instance.Debug.NodeId) && (GlobalConfig.Instance.Debug.ExtVehicleType == ExtVehicleType.None || GlobalConfig.Instance.Debug.ExtVehicleType == ExtVehicleType.RoadVehicle) && (GlobalConfig.Instance.Debug.VehicleId == 0 || GlobalConfig.Instance.Debug.VehicleId == vehicleId); if (debug) { Log._Debug($"CustomCarAI.CustomCalculateSegmentPosition({vehicleId}) called.\n" + $"\trefPosition.m_segment={refPosition.m_segment}, refPosition.m_offset={refPosition.m_offset}\n" + $"\tprevPosition.m_segment={prevPosition.m_segment}, prevPosition.m_offset={prevPosition.m_offset}\n" + $"\tnextPosition.m_segment={nextPosition.m_segment}, nextPosition.m_offset={nextPosition.m_offset}\n" + $"\trefLaneId={refLaneId}, refOffset={refOffset}\n" + $"\tprevLaneId={prevLaneId}, prevOffset={prevOffset}\n" + $"\tprevSourceNodeId={prevSourceNodeId}, prevTargetNodeId={prevTargetNodeId}\n" + $"\trefTargetNodeId={refTargetNodeId}, refTargetNodeId={refTargetNodeId}\n" + $"\tindex={index}"); } #endif Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); Vector3 lastFrameVehiclePos = lastFrameData.m_position; float sqrVelocity = lastFrameData.m_velocity.sqrMagnitude; netManager.m_lanes.m_buffer[prevLaneId].CalculatePositionAndDirection(prevOffset * 0.003921569f, out pos, out dir); float braking = this.m_info.m_braking; if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) != (Vehicle.Flags) 0) { braking *= 2f; } // car position on the Bezier curve of the lane var refVehiclePosOnBezier = netManager.m_lanes.m_buffer[refLaneId].CalculatePosition(refOffset * 0.003921569f); //ushort currentSegmentId = netManager.m_lanes.m_buffer[prevLaneID].m_segment; // this seems to be like the required braking force in order to stop the vehicle within its half length. var crazyValue = 0.5f * sqrVelocity / braking + m_info.m_generatedInfo.m_size.z * 0.5f; bool withinBrakingDistance = Vector3.Distance(lastFrameVehiclePos, refVehiclePosOnBezier) >= crazyValue - 1f; if (prevSourceNodeId == refTargetNodeId && withinBrakingDistance) { // NON-STOCK CODE START (stock code replaced) #if BENCHMARK using (var bm = new Benchmark(null, "MayChangeSegment")) { #endif //bool isRecklessDriver = VehicleStateManager.Instance.IsRecklessDriver(vehicleId, ref vehicleData); // NON-STOCK CODE if (!VehicleBehaviorManager.Instance.MayChangeSegment(vehicleId, ref vehicleData, sqrVelocity, ref refPosition, ref netManager.m_segments.m_buffer[refPosition.m_segment], refTargetNodeId, refLaneId, ref prevPosition, prevSourceNodeId, ref netManager.m_nodes.m_buffer[prevSourceNodeId], prevLaneId, ref nextPosition, prevTargetNodeId, out maxSpeed)) // NON-STOCK CODE { return; } else { #if BENCHMARK using (var bm = new Benchmark(null, "UpdateVehiclePosition")) { #endif VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData /*, lastFrameData.m_velocity.magnitude*/); #if BENCHMARK } #endif } #if BENCHMARK } #endif // NON-STOCK CODE END } var segmentInfo = netManager.m_segments.m_buffer[prevPosition.m_segment].Info; if (segmentInfo.m_lanes != null && segmentInfo.m_lanes.Length > prevPosition.m_lane) { // NON-STOCK CODE START float laneSpeedLimit = 1f; if (!Options.customSpeedLimitsEnabled) { laneSpeedLimit = segmentInfo.m_lanes[prevPosition.m_lane].m_speedLimit; } else { laneSpeedLimit = Constants.ManagerFactory.SpeedLimitManager.GetLockFreeGameSpeedLimit(prevPosition.m_segment, prevPosition.m_lane, prevLaneId, segmentInfo.m_lanes[prevPosition.m_lane]); } // NON-STOCK CODE END maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[prevLaneId].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } // NON-STOCK CODE START (stock code replaced) maxSpeed = Constants.ManagerFactory.VehicleBehaviorManager.CalcMaxSpeed(vehicleId, ref VehicleStateManager.Instance.VehicleStates[vehicleId], this.m_info, prevPosition, ref netManager.m_segments.m_buffer[prevPosition.m_segment], pos, maxSpeed); // NON-STOCK CODE END }