/* * Private unmodified methods */ private void TryCollectGarbage(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData) { Vector3 position = frameData.m_position; float num = position.x - 32f; float num2 = position.z - 32f; float num3 = position.x + 32f; float num4 = position.z + 32f; int num5 = Mathf.Max((int)((num - 72f) / 64f + 135f), 0); int num6 = Mathf.Max((int)((num2 - 72f) / 64f + 135f), 0); int num7 = Mathf.Min((int)((num3 + 72f) / 64f + 135f), 269); int num8 = Mathf.Min((int)((num4 + 72f) / 64f + 135f), 269); BuildingManager instance = Singleton <BuildingManager> .instance; for (int i = num6; i <= num8; i++) { for (int j = num5; j <= num7; j++) { ushort num9 = instance.m_buildingGrid[i * 270 + j]; int num10 = 0; while (num9 != 0) { this.TryCollectGarbage(vehicleID, ref vehicleData, ref frameData, num9, ref instance.m_buildings.m_buffer[(int)num9]); num9 = instance.m_buildings.m_buffer[(int)num9].m_nextGridBuilding; if (++num10 >= 32768) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } }
private void CalculatePositionAndRotation(ushort vehicleID, ref Vehicle vehicleData, out Vector3 position, out Vector3 swayPosition, out Quaternion rotation) { uint targetFrame = vehicleData.GetTargetFrame(m_info, vehicleID); Vehicle.Frame frameData = vehicleData.GetFrameData(targetFrame - 32); Vehicle.Frame frameData2 = vehicleData.GetFrameData(targetFrame - 16); float t = ((float)(targetFrame & 0xF) + Singleton <SimulationManager> .instance.m_referenceTimer) * 0.0625f; Bezier3 bezier = default(Bezier3); bezier.a = frameData.m_position; bezier.b = frameData.m_position + frameData.m_velocity * 0.333f; bezier.c = frameData2.m_position - frameData2.m_velocity * 0.333f; bezier.d = frameData2.m_position; position = bezier.Position(t); Bezier3 bezier2 = default(Bezier3); bezier2.a = frameData.m_swayPosition; bezier2.b = frameData.m_swayPosition + frameData.m_swayVelocity * 0.333f; bezier2.c = frameData2.m_swayPosition - frameData2.m_swayVelocity * 0.333f; bezier2.d = frameData2.m_swayPosition; swayPosition = bezier2.Position(t); swayPosition.x *= m_info.m_leanMultiplier / Mathf.Max(1f, m_info.m_generatedInfo.m_wheelGauge); swayPosition.z *= m_info.m_nodMultiplier / Mathf.Max(1f, m_info.m_generatedInfo.m_wheelBase); rotation = Quaternion.Lerp(frameData.m_rotation, frameData2.m_rotation, t); }
private void CheckOtherVehicles(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ref float maxSpeed, ref bool blocked, float maxDistance, float maxBraking, int lodPhysics) { VehicleManager instance = Singleton <VehicleManager> .instance; Vector3 vector = ((Vector3)vehicleData.m_targetPos3) - frameData.m_position; Vector3 rhs = frameData.m_position + Vector3.ClampMagnitude(vector, maxDistance); Vector3 min = Vector3.Min(vehicleData.m_segment.Min(), rhs); Vector3 max = Vector3.Max(vehicleData.m_segment.Max(), rhs); int num = Mathf.Max((int)((min.x - 100f) / 320f + 27f), 0); int num2 = Mathf.Max((int)((min.z - 100f) / 320f + 27f), 0); int num3 = Mathf.Min((int)((max.x + 100f) / 320f + 27f), 53); int num4 = Mathf.Min((int)((max.z + 100f) / 320f + 27f), 53); for (int i = num2; i <= num4; i++) { for (int j = num; j <= num3; j++) { ushort num5 = instance.m_vehicleGrid2 [i * 54 + j]; int num6 = 0; while (num5 != 0) { num5 = this.CheckOtherVehicle(vehicleID, ref vehicleData, ref frameData, ref maxSpeed, ref blocked, maxBraking, num5, ref instance.m_vehicles.m_buffer [(int)num5], min, max, lodPhysics); if (++num6 > 65536) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } }
public bool CustomCreateVehicle(out ushort vehicleId, ref Randomizer r, VehicleInfo info, Vector3 position, TransferManager.TransferReason type, bool transferToSource, bool transferToTarget) { ushort vehId; if (this.m_vehicles.CreateItem(out vehId, ref r)) { vehicleId = vehId; Vehicle.Frame frame = new Vehicle.Frame(position, Quaternion.identity); this.m_vehicles.m_buffer[(int)vehicleId].m_flags = Vehicle.Flags.Created; if (transferToSource) { this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToSource); } if (transferToTarget) { this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToTarget); } this.m_vehicles.m_buffer[(int)vehicleId].Info = info; this.m_vehicles.m_buffer[(int)vehicleId].m_frame0 = frame; this.m_vehicles.m_buffer[(int)vehicleId].m_frame1 = frame; this.m_vehicles.m_buffer[(int)vehicleId].m_frame2 = frame; this.m_vehicles.m_buffer[(int)vehicleId].m_frame3 = frame; this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos0 = Vector4.zero; this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos1 = Vector4.zero; this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos2 = Vector4.zero; this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos3 = Vector4.zero; this.m_vehicles.m_buffer[(int)vehicleId].m_sourceBuilding = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_targetBuilding = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_transferType = (byte)type; this.m_vehicles.m_buffer[(int)vehicleId].m_transferSize = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_waitCounter = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_blockCounter = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextGridVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextOwnVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextGuestVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextLineVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_transportLine = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_leadingVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_trailingVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_cargoParent = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_firstCargo = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextCargo = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_citizenUnits = 0u; this.m_vehicles.m_buffer[(int)vehicleId].m_path = 0u; this.m_vehicles.m_buffer[(int)vehicleId].m_lastFrame = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_pathPositionIndex = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_lastPathOffset = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_gateIndex = 0; info.m_vehicleAI.CreateVehicle(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]); info.m_vehicleAI.FrameDataUpdated(vehicleId, ref this.m_vehicles.m_buffer[vehicleId], ref this.m_vehicles.m_buffer[vehicleId].m_frame0); this.m_vehicleCount = (int)(this.m_vehicles.ItemCount() - 1u); VehicleStateManager.Instance().DetermineVehicleType(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]); // NON-STOCK CODE return(true); } vehicleId = 0; return(false); }
internal static void Postfix(ref Vehicle vehicleData, ref Vehicle.Frame frameData) { if (!RotationUpdated) { return; } RotationUpdated = false; SuperElevationCommons.Postfix(ref vehicleData, ref frameData); }
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { if (CustomCarAI.sm_speedData[vehicleID].speedMultiplier == 0 || CustomCarAI.sm_speedData[vehicleID].currentPath != vehicleData.m_path) { CustomCarAI.sm_speedData[vehicleID].currentPath = vehicleData.m_path; CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(0.7f, 1.1f); } CustomCarAI.sm_speedData[vehicleID].ApplySpeedMultiplier(this.m_info); } if ((vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None) { Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); if (this.m_info.m_isLargeVehicle) { int num = Mathf.Clamp((int)(lastFrameData.m_position.x / 320f + 27f), 0, 53); int num2 = Mathf.Clamp((int)(lastFrameData.m_position.z / 320f + 27f), 0, 53); CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref lastFrameData, leaderID, ref leaderData, lodPhysics); int num3 = Mathf.Clamp((int)(lastFrameData.m_position.x / 320f + 27f), 0, 53); int num4 = Mathf.Clamp((int)(lastFrameData.m_position.z / 320f + 27f), 0, 53); if ((num3 != num || num4 != num2) && (vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None) { Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref vehicleData, true, num, num2); Singleton <VehicleManager> .instance.AddToGrid(vehicleID, ref vehicleData, true, num3, num4); } } else { int num5 = Mathf.Clamp((int)(lastFrameData.m_position.x / 32f + 270f), 0, 539); int num6 = Mathf.Clamp((int)(lastFrameData.m_position.z / 32f + 270f), 0, 539); CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref lastFrameData, leaderID, ref leaderData, lodPhysics); int num7 = Mathf.Clamp((int)(lastFrameData.m_position.x / 32f + 270f), 0, 539); int num8 = Mathf.Clamp((int)(lastFrameData.m_position.z / 32f + 270f), 0, 539); if ((num7 != num5 || num8 != num6) && (vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None) { Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref vehicleData, false, num5, num6); Singleton <VehicleManager> .instance.AddToGrid(vehicleID, ref vehicleData, false, num7, num8); } } if ((vehicleData.m_flags & (Vehicle.Flags.Created | Vehicle.Flags.Deleted)) == Vehicle.Flags.Created) { this.FrameDataUpdated(vehicleID, ref vehicleData, ref lastFrameData); vehicleData.SetFrameData(Singleton <SimulationManager> .instance.m_currentFrameIndex, lastFrameData); } } if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { CustomCarAI.sm_speedData[vehicleID].RestoreVehicleSpeed(this.m_info); } }
private bool CustomArriveAtTarget(ushort vehicleID, ref Vehicle data) { // NON-STOCK CODE START //RealCity Mod related if (Loader.isRealCityRunning) { GetVehicleRunningTimingForRealCity(vehicleID, ref data); } //RealGasStation Mod related if (data.m_transferType == 112) { PassengerCarAIArriveAtTargetForRealGasStationPre(vehicleID, ref data); return(true); } // NON-STOCK CODE END if ((data.m_flags & Vehicle.Flags.Parking) != (Vehicle.Flags) 0) { VehicleManager instance = Singleton <VehicleManager> .instance; CitizenManager instance2 = Singleton <CitizenManager> .instance; ushort driverInstance = this.GetDriverInstance(vehicleID, ref data); if (driverInstance != 0) { uint citizen = instance2.m_instances.m_buffer[(int)driverInstance].m_citizen; if (citizen != 0u) { ushort parkedVehicle = instance2.m_citizens.m_buffer[(int)((UIntPtr)citizen)].m_parkedVehicle; if (parkedVehicle != 0) { Vehicle.Frame lastFrameData = data.GetLastFrameData(); instance.m_parkedVehicles.m_buffer[(int)parkedVehicle].m_travelDistance = lastFrameData.m_travelDistance; VehicleParked[] expr_A1_cp_0 = instance.m_parkedVehicles.m_buffer; ushort expr_A1_cp_1 = parkedVehicle; expr_A1_cp_0[(int)expr_A1_cp_1].m_flags = (ushort)(expr_A1_cp_0[(int)expr_A1_cp_1].m_flags & 65527); InstanceID empty = InstanceID.Empty; empty.Vehicle = vehicleID; InstanceID empty2 = InstanceID.Empty; empty2.ParkedVehicle = parkedVehicle; Singleton <InstanceManager> .instance.ChangeInstance(empty, empty2); } } } } this.UnloadPassengers(vehicleID, ref data); if (data.m_targetBuilding == 0) { return(true); } data.m_targetPos0 = Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)data.m_targetBuilding].CalculateSidewalkPosition(); data.m_targetPos0.w = 2f; data.m_targetPos1 = data.m_targetPos0; data.m_targetPos2 = data.m_targetPos0; data.m_targetPos3 = data.m_targetPos0; this.RemoveTarget(vehicleID, ref data); return(true); }
private void TryCollectCrime(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort buildingID, ref Building building) { Vector3 a = building.CalculateSidewalkPosition(); if (Vector3.SqrMagnitude(a - frameData.m_position) < 1024f) { int num = -this.m_crimeCapacity; BuildingInfo info = building.Info; info.m_buildingAI.ModifyMaterialBuffer(buildingID, ref building, TransferManager.TransferReason.Crime, ref num); } }
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None && this.CanLeave(vehicleID, ref vehicleData)) { vehicleData.m_flags &= ~Vehicle.Flags.Stopped; vehicleData.m_flags |= Vehicle.Flags.Leaving; } if ((vehicleData.m_flags & (Vehicle.Flags.TransferToSource | Vehicle.Flags.GoingBack)) == Vehicle.Flags.TransferToSource && this.ShouldReturnToSource(vehicleID, ref vehicleData)) { this.SetTarget(vehicleID, ref vehicleData, 0); } }
public static void Postfix(ref Vehicle vehicleData, ref Vehicle.Frame frameData) { if (!vehicleData.GetCurrentPathPos(out var pathPos)) { return; } float se = GetCurrentSE(pathPos, vehicleData.m_lastPathOffset * (1f / 255f), ref vehicleData); var rot = Quaternion.Euler(0, 0f, se); frameData.m_rotation *= rot; }
internal static void Postfix(ref Vehicle vehicleData, ref Vehicle.Frame frameData) { if (vehicleData.Info.m_leanMultiplier < 0) { return; // motor cycle. } if (!RotationUpdated) { //Log.Debug("CarTrailerAI_SimulationStepPatch rotation was not updated! leadID=" + vehicleData.m_leadingVehicle); return; } RotationUpdated = false; ref Vehicle leadingVehicle = ref VehicleBuffer[vehicleData.m_leadingVehicle];
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { if (m_speedData.currentPath != vehicleData.m_path) { m_speedData.currentPath = vehicleData.m_path; if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2) m_speedData.SetRandomSpeedMultiplier(1f, 1.75f); else m_speedData.SetRandomSpeedMultiplier(0.7f, 1.1f); } m_speedData.ApplySpeedMultiplier(this.m_info); } frameData.m_blinkState = (((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None) ? 0f : 10f); this.TryCollectCrime(vehicleID, ref vehicleData, ref frameData); CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None) { if (this.CanLeave(vehicleID, ref vehicleData)) { vehicleData.m_flags &= ~Vehicle.Flags.Stopped; vehicleData.m_flags |= Vehicle.Flags.Leaving; } } else { if ((vehicleData.m_flags & Vehicle.Flags.Arriving) != Vehicle.Flags.None && vehicleData.m_targetBuilding != 0 && (vehicleData.m_flags & (Vehicle.Flags.Emergency2 | Vehicle.Flags.WaitingPath | Vehicle.Flags.GoingBack | Vehicle.Flags.WaitingTarget)) == Vehicle.Flags.None) { this.ArriveAtTarget(vehicleID, ref vehicleData); } } if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == Vehicle.Flags.None && this.ShouldReturnToSource(vehicleID, ref vehicleData)) { this.SetTarget(vehicleID, ref vehicleData, 0); } if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { m_speedData.RestoreVehicleSpeed(this.m_info); } }
private void TryCollectGarbage(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort buildingID, ref Building building) { Vector3 a = building.CalculateSidewalkPosition(); if (Vector3.SqrMagnitude(a - frameData.m_position) < 1024f) { int num = Mathf.Min(0, (int)vehicleData.m_transferSize - this.m_cargoCapacity); if (num == 0) { return; } BuildingInfo info = building.Info; info.m_buildingAI.ModifyMaterialBuffer(buildingID, ref building, (TransferManager.TransferReason)vehicleData.m_transferType, ref num); if (num != 0) { vehicleData.m_transferSize += (ushort)Mathf.Max(0, -num); } } }
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { if ((vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None) { Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); if (this.m_info.m_isLargeVehicle) { int num = Mathf.Clamp((int)(lastFrameData.m_position.x / 320f + 27f), 0, 53); int num2 = Mathf.Clamp((int)(lastFrameData.m_position.z / 320f + 27f), 0, 53); CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref lastFrameData, leaderID, ref leaderData, lodPhysics); int num3 = Mathf.Clamp((int)(lastFrameData.m_position.x / 320f + 27f), 0, 53); int num4 = Mathf.Clamp((int)(lastFrameData.m_position.z / 320f + 27f), 0, 53); if ((num3 != num || num4 != num2) && (vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None) { Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref vehicleData, true, num, num2); Singleton <VehicleManager> .instance.AddToGrid(vehicleID, ref vehicleData, true, num3, num4); } } else { int num5 = Mathf.Clamp((int)(lastFrameData.m_position.x / 32f + 270f), 0, 539); int num6 = Mathf.Clamp((int)(lastFrameData.m_position.z / 32f + 270f), 0, 539); CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref lastFrameData, leaderID, ref leaderData, lodPhysics); int num7 = Mathf.Clamp((int)(lastFrameData.m_position.x / 32f + 270f), 0, 539); int num8 = Mathf.Clamp((int)(lastFrameData.m_position.z / 32f + 270f), 0, 539); if ((num7 != num5 || num8 != num6) && (vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None) { Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref vehicleData, false, num5, num6); Singleton <VehicleManager> .instance.AddToGrid(vehicleID, ref vehicleData, false, num7, num8); } } if ((vehicleData.m_flags & (Vehicle.Flags.Created | Vehicle.Flags.Deleted)) == Vehicle.Flags.Created) { this.FrameDataUpdated(vehicleID, ref vehicleData, ref lastFrameData); vehicleData.SetFrameData(Singleton <SimulationManager> .instance.m_currentFrameIndex, lastFrameData); } } }
public bool CustomCreateVehicle(out ushort vehicleId, ref Randomizer r, VehicleInfo info, Vector3 position, TransferManager.TransferReason type, bool transferToSource, bool transferToTarget) { // NON-STOCK CODE START if (this.m_vehicleCount > VehicleManager.MAX_VEHICLE_COUNT - 5) { // prioritize service vehicles and public transport when hitting the vehicle limit ItemClass.Service service = info.GetService(); if (service == ItemClass.Service.Residential || service == ItemClass.Service.Industrial || service == ItemClass.Service.Commercial || service == ItemClass.Service.Office) { vehicleId = 0; return(false); } } // NON-STOCK CODE END ushort vehId; if (this.m_vehicles.CreateItem(out vehId, ref r)) { vehicleId = vehId; Vehicle.Frame frame = new Vehicle.Frame(position, Quaternion.identity); this.m_vehicles.m_buffer[(int)vehicleId].m_flags = Vehicle.Flags.Created; this.m_vehicles.m_buffer[(int)vehicleId].m_flags2 = (Vehicle.Flags2) 0; if (transferToSource) { this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToSource); } if (transferToTarget) { this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToTarget); } this.m_vehicles.m_buffer[(int)vehicleId].Info = info; this.m_vehicles.m_buffer[(int)vehicleId].m_frame0 = frame; this.m_vehicles.m_buffer[(int)vehicleId].m_frame1 = frame; this.m_vehicles.m_buffer[(int)vehicleId].m_frame2 = frame; this.m_vehicles.m_buffer[(int)vehicleId].m_frame3 = frame; this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos0 = Vector4.zero; this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos1 = Vector4.zero; this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos2 = Vector4.zero; this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos3 = Vector4.zero; this.m_vehicles.m_buffer[(int)vehicleId].m_sourceBuilding = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_targetBuilding = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_transferType = (byte)type; this.m_vehicles.m_buffer[(int)vehicleId].m_transferSize = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_waitCounter = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_blockCounter = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextGridVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextOwnVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextGuestVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextLineVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_transportLine = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_leadingVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_trailingVehicle = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_cargoParent = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_firstCargo = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_nextCargo = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_citizenUnits = 0u; this.m_vehicles.m_buffer[(int)vehicleId].m_path = 0u; this.m_vehicles.m_buffer[(int)vehicleId].m_lastFrame = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_pathPositionIndex = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_lastPathOffset = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_gateIndex = 0; this.m_vehicles.m_buffer[(int)vehicleId].m_waterSource = 0; info.m_vehicleAI.CreateVehicle(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]); info.m_vehicleAI.FrameDataUpdated(vehicleId, ref this.m_vehicles.m_buffer[vehicleId], ref this.m_vehicles.m_buffer[vehicleId].m_frame0); this.m_vehicleCount = (int)(this.m_vehicles.ItemCount() - 1u); VehicleStateManager.Instance.OnCreateVehicle(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]); // NON-STOCK CODE return(true); } vehicleId = 0; return(false); }
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 VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData, lastFrameData.m_velocity.magnitude); // 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 (!VehicleBehaviorManager.Instance.MayChangeSegment(vehicleId, ref VehicleStateManager.Instance.VehicleStates[vehicleId], ref vehicleData, ref lastFrameData, 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; } } } 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 = 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, speedLimit, netManager.m_lanes.m_buffer[laneID].m_curve); } else { maxSpeed = this.CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } }
/// <summary> /// Checks for traffic lights and priority signs when changing segments (for road & rail vehicles). /// Sets the maximum allowed speed <paramref name="maxSpeed"/> if segment change is not allowed (otherwise <paramref name="maxSpeed"/> has to be set by the calling method). /// </summary> /// <param name="vehicleId">vehicle id</param> /// <param name="vehicleData">vehicle data</param> /// <param name="lastFrameData">last frame data of vehicle</param> /// <param name="isRecklessDriver">if true, this vehicle ignores red traffic lights and priority signs</param> /// <param name="prevPos">previous path position</param> /// <param name="prevTargetNodeId">previous target node</param> /// <param name="prevLaneID">previous lane</param> /// <param name="position">current path position</param> /// <param name="targetNodeId">transit node</param> /// <param name="laneID">current lane</param> /// <param name="nextPosition">next path position</param> /// <param name="nextTargetNodeId">next target node</param> /// <param name="maxSpeed">maximum allowed speed (only valid if method returns false)</param> /// <returns>true, if the vehicle may change segments, false otherwise.</returns> internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData, ref Vehicle.Frame lastFrameData, bool isRecklessDriver, ref PathUnit.Position prevPos, ushort prevTargetNodeId, uint prevLaneID, ref PathUnit.Position position, ushort targetNodeId, uint laneID, ref PathUnit.Position nextPosition, ushort nextTargetNodeId, out float maxSpeed, bool debug = false) { debug = false; if (prevTargetNodeId != targetNodeId) { // method should only be called if targetNodeId == prevTargetNode maxSpeed = 0f; return(true); } bool forceUpdatePos = false; VehicleState vehicleState = null; try { vehicleState = VehicleStateManager.GetVehicleState(vehicleId); if (vehicleState == null) { VehicleStateManager.OnPathFindReady(vehicleId, ref vehicleData); vehicleState = VehicleStateManager.GetVehicleState(vehicleId); if (vehicleState == null) { #if DEBUG Log._Debug($"Could not get vehicle state of {vehicleId}!"); #endif } else { forceUpdatePos = true; } } } catch (Exception e) { Log.Error("VehicleAI MayChangeSegment vehicle state error: " + e.ToString()); } if (forceUpdatePos || Options.simAccuracy >= 2) { try { VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position); } catch (Exception e) { Log.Error("VehicleAI MayChangeSegment Error: " + e.ToString()); } } var netManager = Singleton <NetManager> .instance; uint currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex; uint prevTargetNodeLower8Bits = (uint)((prevTargetNodeId << 8) / 32768); uint random = currentFrameIndex - prevTargetNodeLower8Bits & 255u; bool isRailVehicle = (vehicleData.Info.m_vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro)) != VehicleInfo.VehicleType.None; NetNode.Flags targetNodeFlags = netManager.m_nodes.m_buffer[targetNodeId].m_flags; bool hasTrafficLight = (targetNodeFlags & NetNode.Flags.TrafficLights) != NetNode.Flags.None; bool checkTrafficLights = false; if (!isRailVehicle) { // check if to check space #if DEBUG if (debug) { Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} is not a train."); } #endif var prevLaneFlags = (NetLane.Flags)netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_flags; var hasCrossing = (targetNodeFlags & NetNode.Flags.LevelCrossing) != NetNode.Flags.None; var isJoinedJunction = (prevLaneFlags & NetLane.Flags.JoinedJunction) != NetLane.Flags.None; bool checkSpace = !Flags.getEnterWhenBlockedAllowed(prevPos.m_segment, netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode == targetNodeId) && !isRecklessDriver; //TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(destinationNodeId); //if (timedNode != null && timedNode.vehiclesMayEnterBlockedJunctions) { // checkSpace = false; //} if (checkSpace) { // check if there is enough space if ((targetNodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) == NetNode.Flags.Junction && netManager.m_nodes.m_buffer[targetNodeId].CountSegments() != 2) { var len = vehicleData.CalculateTotalLength(vehicleId) + 2f; if (!netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(len)) { var sufficientSpace = false; if (nextPosition.m_segment != 0 && netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_length < 30f) { NetNode.Flags nextTargetNodeFlags = netManager.m_nodes.m_buffer[nextTargetNodeId].m_flags; if ((nextTargetNodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) != NetNode.Flags.Junction || netManager.m_nodes.m_buffer[nextTargetNodeId].CountSegments() == 2) { uint nextLaneId = PathManager.GetLaneID(nextPosition); if (nextLaneId != 0u) { sufficientSpace = netManager.m_lanes.m_buffer[(int)((UIntPtr)nextLaneId)].CheckSpace(len); } } } if (!sufficientSpace) { maxSpeed = 0f; try { if (vehicleState != null) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to BLOCKED"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Blocked; } } catch (Exception e) { Log.Error("VehicleAI MayChangeSegment error while setting junction state to BLOCKED: " + e.ToString()); } return(false); } } } } checkTrafficLights = (!isJoinedJunction || hasCrossing); } else { #if DEBUG if (debug) { Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} is a train."); } #endif checkTrafficLights = true; } try { if (vehicleState != null && vehicleState.JunctionTransitState == VehicleJunctionTransitState.Blocked) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState from BLOCKED to ENTER"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter; } if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == 0) { if (hasTrafficLight && checkTrafficLights) { #if DEBUG if (debug) { Log._Debug($"CustomVehicleAI.MayChangeSegment: Node {targetNodeId} has a traffic light."); } #endif var destinationInfo = netManager.m_nodes.m_buffer[targetNodeId].Info; if (vehicleState != null && vehicleState.JunctionTransitState == VehicleJunctionTransitState.None) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to ENTER (1)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter; } RoadBaseAI.TrafficLightState vehicleLightState; RoadBaseAI.TrafficLightState pedestrianLightState; bool vehicles; bool pedestrians; CustomRoadAI.GetTrafficLightState(vehicleId, ref vehicleData, targetNodeId, prevPos.m_segment, prevPos.m_lane, position.m_segment, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - prevTargetNodeLower8Bits, out vehicleLightState, out pedestrianLightState, out vehicles, out pedestrians); if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car && isRecklessDriver) // no reckless driving at railroad crossings { vehicleLightState = RoadBaseAI.TrafficLightState.Green; } #if DEBUG if (debug) { Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} has {vehicleLightState} at node {targetNodeId}"); } #endif if (!vehicles && random >= 196u) { vehicles = true; RoadBaseAI.SetTrafficLightState(targetNodeId, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - prevTargetNodeLower8Bits, vehicleLightState, pedestrianLightState, vehicles, pedestrians); } var stopCar = false; switch (vehicleLightState) { case RoadBaseAI.TrafficLightState.RedToGreen: if (random < 60u) { stopCar = true; } else { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (RedToGreen)"); } #endif if (vehicleState != null) { vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } } break; case RoadBaseAI.TrafficLightState.Red: stopCar = true; break; case RoadBaseAI.TrafficLightState.GreenToRed: if (random >= 30u) { stopCar = true; } else if (vehicleState != null) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (GreenToRed)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } break; } /*if ((vehicleLightState == RoadBaseAI.TrafficLightState.Green || vehicleLightState == RoadBaseAI.TrafficLightState.RedToGreen) && !Flags.getEnterWhenBlockedAllowed(prevPos.m_segment, netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode == targetNodeId)) { * var hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, targetNodeId); * * if (hasIncomingCars) { * // green light but other cars are incoming and they have priority: stop * stopCar = true; * } * }*/ if (stopCar) { if (vehicleState != null) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop; } maxSpeed = 0f; return(false); } } else if (vehicleState != null) { #if DEBUG //bool debug = destinationNodeId == 10864; //bool debug = destinationNodeId == 13531; //bool debug = false;// targetNodeId == 5027; #endif //bool debug = false; #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId} is arriving @ seg. {prevPos.m_segment} ({position.m_segment}, {nextPosition.m_segment}), node {targetNodeId} which is not a traffic light."); } #endif var prioritySegment = TrafficPriority.GetPrioritySegment(targetNodeId, prevPos.m_segment); if (prioritySegment != null) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId} is arriving @ seg. {prevPos.m_segment} ({position.m_segment}, {nextPosition.m_segment}), node {targetNodeId} which is not a traffic light and is a priority segment."); } #endif //if (prioritySegment.HasVehicle(vehicleId)) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: segment target position found"); } #endif #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: global target position found. carState = {vehicleState.JunctionTransitState.ToString()}"); } #endif var currentFrameIndex2 = Singleton <SimulationManager> .instance.m_currentFrameIndex; var frame = currentFrameIndex2 >> 4; float speed = lastFrameData.m_velocity.magnitude; if (vehicleState.JunctionTransitState == VehicleJunctionTransitState.None) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to ENTER (prio)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter; } if (vehicleState.JunctionTransitState != VehicleJunctionTransitState.Leave) { bool hasIncomingCars; switch (prioritySegment.Type) { case SegmentEnd.PriorityType.Stop: #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: STOP sign. waittime={vehicleState.WaitTime}, vel={speed}"); } #endif if (Options.simAccuracy <= 2 || (Options.simAccuracy >= 3 && vehicleState.WaitTime < MaxPriorityWaitTime)) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop; if (speed <= TrafficPriority.maxStopVelocity) { vehicleState.WaitTime++; float minStopWaitTime = UnityEngine.Random.Range(0f, 3f); if (vehicleState.WaitTime >= minStopWaitTime) { if (Options.simAccuracy >= 4) { vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } else { hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position); #if DEBUG if (debug) { Log._Debug($"hasIncomingCars: {hasIncomingCars}"); } #endif if (hasIncomingCars) { maxSpeed = 0f; return(false); } #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (min wait timeout)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } } else { maxSpeed = 0; return(false); } } else { vehicleState.WaitTime = 0; maxSpeed = 0f; return(false); } } else { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (max wait timeout)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } break; case SegmentEnd.PriorityType.Yield: #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: YIELD sign. waittime={vehicleState.WaitTime}"); } #endif if (Options.simAccuracy <= 2 || (Options.simAccuracy >= 3 && vehicleState.WaitTime < MaxPriorityWaitTime)) { vehicleState.WaitTime++; #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop; if (speed <= TrafficPriority.maxYieldVelocity || Options.simAccuracy <= 2) { if (Options.simAccuracy >= 4) { vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } else { hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position); #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: hasIncomingCars: {hasIncomingCars}"); } #endif if (hasIncomingCars) { maxSpeed = 0f; return(false); } else { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (no incoming cars)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } } } else { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Vehicle has not yet reached yield speed (reduce {speed} by {vehicleState.ReduceSpeedByValueToYield})"); } #endif // vehicle has not yet reached yield speed maxSpeed = TrafficPriority.maxYieldVelocity; return(false); } } else { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (max wait timeout)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } break; case SegmentEnd.PriorityType.Main: case SegmentEnd.PriorityType.None: #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: MAIN sign. waittime={vehicleState.WaitTime}"); } #endif maxSpeed = 0f; if (Options.simAccuracy == 4) { return(true); } if (Options.simAccuracy <= 2 || (Options.simAccuracy == 3 && vehicleState.WaitTime < MaxPriorityWaitTime)) { vehicleState.WaitTime++; #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop; hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position); #if DEBUG if (debug) { Log._Debug($"hasIncomingCars: {hasIncomingCars}"); } #endif if (hasIncomingCars) { return(false); } #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (no conflicting car)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave; } return(true); } } else if (speed <= TrafficPriority.maxStopVelocity) { // vehicle is not moving. reset allowance to leave junction #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState from LEAVE to BLOCKED (speed to low)"); } #endif vehicleState.JunctionTransitState = VehicleJunctionTransitState.Blocked; maxSpeed = 0f; return(false); } } } } } catch (Exception e) { Log.Error($"Error occured in MayChangeSegment: {e.ToString()}"); } maxSpeed = 0f; // maxSpeed should be set by caller return(true); }
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { if (m_speedData.currentPath != vehicleData.m_path) { m_speedData.currentPath = vehicleData.m_path; m_speedData.SetRandomSpeedMultiplier(0.65f, 1.05f); } m_speedData.ApplySpeedMultiplier(this.m_info); } if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None) { vehicleData.m_waitCounter += 1; if (this.CanLeave(vehicleID, ref vehicleData)) { vehicleData.m_flags &= ~Vehicle.Flags.Stopped; vehicleData.m_flags |= Vehicle.Flags.Leaving; vehicleData.m_waitCounter = 0; } } CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == Vehicle.Flags.None && this.ShouldReturnToSource(vehicleID, ref vehicleData)) { this.SetTransportLine(vehicleID, ref vehicleData, 0); } if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { m_speedData.RestoreVehicleSpeed(this.m_info); } }
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { if (CustomCarAI.sm_speedData[vehicleID].speedMultiplier == 0 || CustomCarAI.sm_speedData[vehicleID].currentPath != vehicleData.m_path) { CustomCarAI.sm_speedData[vehicleID].currentPath = vehicleData.m_path; if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2) { CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(1f, 1.5f); } else { CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(0.7f, 1.05f); } } CustomCarAI.sm_speedData[vehicleID].ApplySpeedMultiplier(this.m_info); } frameData.m_blinkState = (((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None) ? 0f : 10f); CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None && this.CanLeave(vehicleID, ref vehicleData)) { vehicleData.m_flags &= ~Vehicle.Flags.Stopped; vehicleData.m_flags |= Vehicle.Flags.Leaving; } if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == Vehicle.Flags.None && this.ShouldReturnToSource(vehicleID, ref vehicleData)) { this.SetTarget(vehicleID, ref vehicleData, 0); } if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { CustomCarAI.sm_speedData[vehicleID].RestoreVehicleSpeed(this.m_info); } }
/// <summary> /// Checks for traffic lights and priority signs when changing segments (for rail vehicles). /// Sets the maximum allowed speed <paramref name="maxSpeed"/> if segment change is not allowed (otherwise <paramref name="maxSpeed"/> has to be set by the calling method). /// </summary> /// <param name="vehicleId">vehicle id</param> /// <param name="vehicleData">vehicle data</param> /// <param name="lastFrameData">last frame data of vehicle</param> /// <param name="isRecklessDriver">if true, this vehicle ignores red traffic lights and priority signs</param> /// <param name="prevPos">previous path position</param> /// <param name="prevTargetNodeId">previous target node</param> /// <param name="prevLaneID">previous lane</param> /// <param name="position">current path position</param> /// <param name="targetNodeId">transit node</param> /// <param name="laneID">current lane</param> /// <param name="maxSpeed">maximum allowed speed (only valid if method returns false)</param> /// <returns>true, if the vehicle may change segments, false otherwise.</returns> internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData, ref Vehicle.Frame lastFrameData, bool isRecklessDriver, ref PathUnit.Position prevPos, ushort prevTargetNodeId, uint prevLaneID, ref PathUnit.Position position, ushort targetNodeId, uint laneID, out float maxSpeed, bool debug = false) { return(MayChangeSegment(vehicleId, ref vehicleData, ref lastFrameData, isRecklessDriver, ref prevPos, prevTargetNodeId, prevLaneID, ref position, targetNodeId, laneID, ref DUMMY_POS, 0, out maxSpeed, debug)); }
private static bool CreateVehicle(VehicleManager vMgr, out ushort vehicle, ref Randomizer r, VehicleInfo info, Vector3 position, TransferManager.TransferReason type, bool transferToSource, bool transferToTarget) { bool AttemptFlag = false; uint ReserveMax = (vMgr.m_vehicles.m_size - 1) - Mod.RESERVEAMOUNT; //we subtract 1 cause game doesn't use entry 0 for a real vehicle. int CurrentVehicleNum = vMgr.m_vehicleCount; //vMgr.m_vehicles.ItemCount(); //found they were never different ~+\- a nanosecond. int m_VecCount = vMgr.m_vehicleCount; //unly Mod.timesCV_CalledTotal++; //stat tracking. if (CurrentVehicleNum >= ReserveMax && type != TransferManager.TransferReason.Fire && type != TransferManager.TransferReason.Sick && type != TransferManager.TransferReason.Garbage && type != TransferManager.TransferReason.Dead && type != TransferManager.TransferReason.Crime && type != TransferManager.TransferReason.Bus && type != TransferManager.TransferReason.MetroTrain && type != TransferManager.TransferReason.PassengerTrain && type != TransferManager.TransferReason.DeadMove && type != TransferManager.TransferReason.CriminalMove && type != TransferManager.TransferReason.Taxi && type != TransferManager.TransferReason.GarbageMove && type != TransferManager.TransferReason.Tram && type != TransferManager.TransferReason.RoadMaintenance && type != TransferManager.TransferReason.Snow && type != TransferManager.TransferReason.SnowMove && type != TransferManager.TransferReason.Fire2 && type != TransferManager.TransferReason.ForestFire && type != TransferManager.TransferReason.FloodWater && type !=TransferManager.TransferReason.SickMove && type != TransferManager.TransferReason.Sick2 && type !=TransferManager.TransferReason.EvacuateVipA && type != TransferManager.TransferReason.EvacuateVipB && type != TransferManager.TransferReason.EvacuateVipC && type != TransferManager.TransferReason.EvacuateVipD) { Mod.timesFailedByReserve++; //stat tracking Mod.timesFailedToCreate++; //stat tracking vehicle = 0; return false; } if (CurrentVehicleNum >= ReserveMax) { AttemptFlag = true; Mod.timesReservedAttempted++; //stat tracking. if (CurrentVehicleNum == (vMgr.m_vehicles.m_size -1)) { Mod.timesLimitReached++; } //stattracking if (Mod.DEBUG_LOG_ON && Mod.DEBUG_LOG_LEVEL >= 3) { Helper.dbgLog(" Vehicles[" + CurrentVehicleNum.ToString() + "] max reached, attempting to use reserve for a " + type.ToString() + " - " + System.DateTime.Now.ToString() + " : " + DateTime.Now.Millisecond.ToString() + " counter=" + Mod.timesReservedAttempted.ToString() + " reservemax=" + ReserveMax.ToString()); } } //Original Untouched Below except for attemptflag and Mod.timeFailedToCreate Counters and debug logging. ushort num; if (!vMgr.m_vehicles.CreateItem(out num, ref r)) { vehicle = 0; if (AttemptFlag) { Mod.timesReserveAttemptFailed++ ; //stat tracking. if (Mod.DEBUG_LOG_ON && Mod.DEBUG_LOG_LEVEL >= 2) { Helper.dbgLog(" Vehicles[" + CurrentVehicleNum.ToString() + "] max reached, attempted to use reserve for a " + type.ToString() + " but Failed! " + System.DateTime.Now.ToString() + " : " + DateTime.Now.Millisecond.ToString() + " counter=" + Mod.timesReservedAttempted.ToString()); } } Mod.timesFailedToCreate++; //stat tracking return false; } vehicle = num; Vehicle.Frame frame = new Vehicle.Frame(position, Quaternion.identity); vMgr.m_vehicles.m_buffer[vehicle].m_flags = Vehicle.Flags.Created; if (transferToSource) { vMgr.m_vehicles.m_buffer[vehicle].m_flags = vMgr.m_vehicles.m_buffer[vehicle].m_flags | Vehicle.Flags.TransferToSource; } if (transferToTarget) { vMgr.m_vehicles.m_buffer[vehicle].m_flags = vMgr.m_vehicles.m_buffer[vehicle].m_flags | Vehicle.Flags.TransferToTarget; } vMgr.m_vehicles.m_buffer[vehicle].Info = info; vMgr.m_vehicles.m_buffer[vehicle].m_frame0 = frame; vMgr.m_vehicles.m_buffer[vehicle].m_frame1 = frame; vMgr.m_vehicles.m_buffer[vehicle].m_frame2 = frame; vMgr.m_vehicles.m_buffer[vehicle].m_frame3 = frame; vMgr.m_vehicles.m_buffer[vehicle].m_targetPos0 = Vector4.zero; vMgr.m_vehicles.m_buffer[vehicle].m_targetPos1 = Vector4.zero; vMgr.m_vehicles.m_buffer[vehicle].m_targetPos2 = Vector4.zero; vMgr.m_vehicles.m_buffer[vehicle].m_targetPos3 = Vector4.zero; vMgr.m_vehicles.m_buffer[vehicle].m_sourceBuilding = 0; vMgr.m_vehicles.m_buffer[vehicle].m_targetBuilding = 0; vMgr.m_vehicles.m_buffer[vehicle].m_transferType = (byte)type; vMgr.m_vehicles.m_buffer[vehicle].m_transferSize = 0; vMgr.m_vehicles.m_buffer[vehicle].m_waitCounter = 0; vMgr.m_vehicles.m_buffer[vehicle].m_blockCounter = 0; vMgr.m_vehicles.m_buffer[vehicle].m_nextGridVehicle = 0; vMgr.m_vehicles.m_buffer[vehicle].m_nextOwnVehicle = 0; vMgr.m_vehicles.m_buffer[vehicle].m_nextGuestVehicle = 0; vMgr.m_vehicles.m_buffer[vehicle].m_nextLineVehicle = 0; vMgr.m_vehicles.m_buffer[vehicle].m_transportLine = 0; vMgr.m_vehicles.m_buffer[vehicle].m_leadingVehicle = 0; vMgr.m_vehicles.m_buffer[vehicle].m_trailingVehicle = 0; vMgr.m_vehicles.m_buffer[vehicle].m_cargoParent = 0; vMgr.m_vehicles.m_buffer[vehicle].m_firstCargo = 0; vMgr.m_vehicles.m_buffer[vehicle].m_nextCargo = 0; vMgr.m_vehicles.m_buffer[vehicle].m_citizenUnits = 0; vMgr.m_vehicles.m_buffer[vehicle].m_path = 0; vMgr.m_vehicles.m_buffer[vehicle].m_lastFrame = 0; vMgr.m_vehicles.m_buffer[vehicle].m_pathPositionIndex = 0; vMgr.m_vehicles.m_buffer[vehicle].m_lastPathOffset = 0; vMgr.m_vehicles.m_buffer[vehicle].m_gateIndex = 0; vMgr.m_vehicles.m_buffer[vehicle].m_waterSource = 0; info.m_vehicleAI.CreateVehicle(vehicle, ref vMgr.m_vehicles.m_buffer[vehicle]); info.m_vehicleAI.FrameDataUpdated(vehicle, ref vMgr.m_vehicles.m_buffer[vehicle], ref vMgr.m_vehicles.m_buffer[vehicle].m_frame0); vMgr.m_vehicleCount = (int)(vMgr.m_vehicles.ItemCount() - 1); return true; }
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { if ((TrafficMod.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { var speedData = CarSpeedData.Of(vehicleID); if (speedData.SpeedMultiplier == 0 || speedData.CurrentPath != vehicleData.m_path) { speedData.CurrentPath = vehicleData.m_path; if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2) { speedData.SetRandomSpeedMultiplier(1f, 1.75f); } else { speedData.SetRandomSpeedMultiplier(0.7f, 1.1f); } } m_info.ApplySpeedMultiplier(CarSpeedData.Of(vehicleID)); } if (this.m_info.m_class.m_level >= ItemClass.Level.Level4) { base.SimulationStep(vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != 0 && this.CanLeave(vehicleID, ref vehicleData)) { vehicleData.m_flags &= ~Vehicle.Flags.Stopped; vehicleData.m_flags |= Vehicle.Flags.Leaving; } if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == 0 && this.ShouldReturnToSource(vehicleID, ref vehicleData)) { this.SetTarget(vehicleID, ref vehicleData, 0); } } else { frameData.m_blinkState = (((vehicleData.m_flags & Vehicle.Flags.Emergency2) == 0) ? 0f : 10f); this.TryCollectCrime(vehicleID, ref vehicleData, ref frameData); base.SimulationStep(vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != 0) { if (this.CanLeave(vehicleID, ref vehicleData)) { vehicleData.m_flags &= ~Vehicle.Flags.Stopped; vehicleData.m_flags |= Vehicle.Flags.Leaving; } } else if ((vehicleData.m_flags & Vehicle.Flags.Arriving) != 0 && vehicleData.m_targetBuilding != 0 && (vehicleData.m_flags & (Vehicle.Flags.Emergency2 | Vehicle.Flags.WaitingPath | Vehicle.Flags.GoingBack | Vehicle.Flags.WaitingTarget)) == 0) { this.ArriveAtTarget(vehicleID, ref vehicleData); } if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == 0 && this.ShouldReturnToSource(vehicleID, ref vehicleData)) { this.SetTarget(vehicleID, ref vehicleData, 0); } } if ((TrafficMod.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { m_info.RestoreVehicleSpeed(CarSpeedData.Of(vehicleID)); } }
// HACK public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { var baseAcceleration = m_info.m_acceleration; if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2) { m_info.m_acceleration *= 3; } base.SimulationStep(vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); m_info.m_acceleration = baseAcceleration; }
public void CustomSimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { #if DEBUG bool debug = GlobalConfig.Instance.Debug.Switches[16] && GlobalConfig.Instance.Debug.NodeId == vehicleID; #endif ushort leadingVehicle = vehicleData.m_leadingVehicle; uint currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex; VehicleInfo leaderInfo; if (leaderID != vehicleID) { leaderInfo = leaderData.Info; } else { leaderInfo = this.m_info; } TramBaseAI tramBaseAI = leaderInfo.m_vehicleAI as TramBaseAI; if (leadingVehicle != 0) { frameData.m_position += frameData.m_velocity * 0.4f; } else { frameData.m_position += frameData.m_velocity * 0.5f; } frameData.m_swayPosition += frameData.m_swayVelocity * 0.5f; Vector3 wheelBaseRot = frameData.m_rotation * new Vector3(0f, 0f, this.m_info.m_generatedInfo.m_wheelBase * 0.5f); Vector3 posAfterWheelRot = frameData.m_position + wheelBaseRot; Vector3 posBeforeWheelRot = frameData.m_position - wheelBaseRot; float acceleration = this.m_info.m_acceleration; float braking = this.m_info.m_braking; float curSpeed = frameData.m_velocity.magnitude; Vector3 afterRotToTargetPos1Diff = (Vector3)vehicleData.m_targetPos1 - posAfterWheelRot; float afterRotToTargetPos1DiffSqrMag = afterRotToTargetPos1Diff.sqrMagnitude; Quaternion curInvRot = Quaternion.Inverse(frameData.m_rotation); Vector3 curveTangent = curInvRot * frameData.m_velocity; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): ================================================"); Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): leadingVehicle={leadingVehicle} frameData.m_position={frameData.m_position} frameData.m_swayPosition={frameData.m_swayPosition} wheelBaseRot={wheelBaseRot} posAfterWheelRot={posAfterWheelRot} posBeforeWheelRot={posBeforeWheelRot} acceleration={acceleration} braking={braking} curSpeed={curSpeed} afterRotToTargetPos1Diff={afterRotToTargetPos1Diff} afterRotToTargetPos1DiffSqrMag={afterRotToTargetPos1DiffSqrMag} curInvRot={curInvRot} curveTangent={curveTangent} this.m_info.m_generatedInfo.m_wheelBase={this.m_info.m_generatedInfo.m_wheelBase}"); } #endif Vector3 forward = Vector3.forward; Vector3 targetMotion = Vector3.zero; float targetSpeed = 0f; float motionFactor = 0.5f; float turnAngle = 0f; if (leadingVehicle != 0) { VehicleManager vehMan = Singleton <VehicleManager> .instance; Vehicle.Frame leadingVehLastFrameData = vehMan.m_vehicles.m_buffer[(int)leadingVehicle].GetLastFrameData(); VehicleInfo leadingVehInfo = vehMan.m_vehicles.m_buffer[(int)leadingVehicle].Info; float attachOffset; if ((vehicleData.m_flags & Vehicle.Flags.Inverted) != (Vehicle.Flags) 0) { attachOffset = this.m_info.m_attachOffsetBack - this.m_info.m_generatedInfo.m_size.z * 0.5f; } else { attachOffset = this.m_info.m_attachOffsetFront - this.m_info.m_generatedInfo.m_size.z * 0.5f; } float leadingAttachOffset; if ((vehMan.m_vehicles.m_buffer[(int)leadingVehicle].m_flags & Vehicle.Flags.Inverted) != (Vehicle.Flags) 0) { leadingAttachOffset = leadingVehInfo.m_attachOffsetFront - leadingVehInfo.m_generatedInfo.m_size.z * 0.5f; } else { leadingAttachOffset = leadingVehInfo.m_attachOffsetBack - leadingVehInfo.m_generatedInfo.m_size.z * 0.5f; } Vector3 curPosMinusRotAttachOffset = frameData.m_position - frameData.m_rotation * new Vector3(0f, 0f, attachOffset); Vector3 leadingPosPlusRotAttachOffset = leadingVehLastFrameData.m_position + leadingVehLastFrameData.m_rotation * new Vector3(0f, 0f, leadingAttachOffset); wheelBaseRot = leadingVehLastFrameData.m_rotation * new Vector3(0f, 0f, leadingVehInfo.m_generatedInfo.m_wheelBase * 0.5f); Vector3 leadingPosBeforeWheelRot = leadingVehLastFrameData.m_position - wheelBaseRot; if (Vector3.Dot(vehicleData.m_targetPos1 - vehicleData.m_targetPos0, (Vector3)vehicleData.m_targetPos0 - posBeforeWheelRot) < 0f && vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0) { int someIndex = -1; InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, vehicleData.m_targetPos0, posBeforeWheelRot, 0, ref leaderData, ref someIndex, 0, 0, Vector3.SqrMagnitude(posBeforeWheelRot - (Vector3)vehicleData.m_targetPos0) + 1f, 1f); afterRotToTargetPos1DiffSqrMag = 0f; } float attachRotDist = Mathf.Max(Vector3.Distance(curPosMinusRotAttachOffset, leadingPosPlusRotAttachOffset), 2f); float one = 1f; float attachRotSqrDist = attachRotDist * attachRotDist; float oneSqr = one * one; int i = 0; if (afterRotToTargetPos1DiffSqrMag < attachRotSqrDist) { if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0) { InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, posBeforeWheelRot, posAfterWheelRot, 0, ref leaderData, ref i, 1, 2, attachRotSqrDist, oneSqr); } while (i < 4) { vehicleData.SetTargetPos(i, vehicleData.GetTargetPos(i - 1)); i++; } afterRotToTargetPos1Diff = (Vector3)vehicleData.m_targetPos1 - posAfterWheelRot; afterRotToTargetPos1DiffSqrMag = afterRotToTargetPos1Diff.sqrMagnitude; } afterRotToTargetPos1Diff = curInvRot * afterRotToTargetPos1Diff; float negTotalAttachLen = -((this.m_info.m_generatedInfo.m_wheelBase + leadingVehInfo.m_generatedInfo.m_wheelBase) * 0.5f + attachOffset + leadingAttachOffset); bool hasPath = false; if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0) { float u1; float u2; if (Line3.Intersect(posAfterWheelRot, vehicleData.m_targetPos1, leadingPosBeforeWheelRot, negTotalAttachLen, out u1, out u2)) { targetMotion = afterRotToTargetPos1Diff * Mathf.Clamp(Mathf.Min(u1, u2) / 0.6f, 0f, 2f); } else { Line3.DistanceSqr(posAfterWheelRot, vehicleData.m_targetPos1, leadingPosBeforeWheelRot, out u1); targetMotion = afterRotToTargetPos1Diff * Mathf.Clamp(u1 / 0.6f, 0f, 2f); } hasPath = true; } if (hasPath) { if (Vector3.Dot(leadingPosBeforeWheelRot - posAfterWheelRot, posAfterWheelRot - posBeforeWheelRot) < 0f) { motionFactor = 0f; } } else { float leadingPosBeforeToAfterWheelRotDist = Vector3.Distance(leadingPosBeforeWheelRot, posAfterWheelRot); motionFactor = 0f; targetMotion = curInvRot * ((leadingPosBeforeWheelRot - posAfterWheelRot) * (Mathf.Max(0f, leadingPosBeforeToAfterWheelRotDist - negTotalAttachLen) / Mathf.Max(1f, leadingPosBeforeToAfterWheelRotDist * 0.6f))); } } else { float estimatedFrameDist = (curSpeed + acceleration) * (0.5f + 0.5f * (curSpeed + acceleration) / braking) + (this.m_info.m_generatedInfo.m_size.z - this.m_info.m_generatedInfo.m_wheelBase) * 0.5f; float maxSpeedAdd = Mathf.Max(curSpeed + acceleration, 2f); float meanSpeedAdd = Mathf.Max((estimatedFrameDist - maxSpeedAdd) / 2f, 2f); float maxSpeedAddSqr = maxSpeedAdd * maxSpeedAdd; float meanSpeedAddSqr = meanSpeedAdd * meanSpeedAdd; if (Vector3.Dot(vehicleData.m_targetPos1 - vehicleData.m_targetPos0, (Vector3)vehicleData.m_targetPos0 - posBeforeWheelRot) < 0f && vehicleData.m_path != 0u && (leaderData.m_flags & (Vehicle.Flags.WaitingPath | Vehicle.Flags.Stopped)) == (Vehicle.Flags) 0) { int someIndex = -1; InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, vehicleData.m_targetPos0, posBeforeWheelRot, leaderID, ref leaderData, ref someIndex, 0, 0, Vector3.SqrMagnitude(posBeforeWheelRot - (Vector3)vehicleData.m_targetPos0) + 1f, 1f); afterRotToTargetPos1DiffSqrMag = 0f; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): dot < 0"); } #endif } #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Leading vehicle is 0. vehicleData.m_targetPos0={vehicleData.m_targetPos0} vehicleData.m_targetPos1={vehicleData.m_targetPos1} posBeforeWheelRot={posBeforeWheelRot} posBeforeWheelRot={posAfterWheelRot} estimatedFrameDist={estimatedFrameDist} maxSpeedAdd={maxSpeedAdd} meanSpeedAdd={meanSpeedAdd} maxSpeedAddSqr={maxSpeedAddSqr} meanSpeedAddSqr={meanSpeedAddSqr} afterRotToTargetPos1DiffSqrMag={afterRotToTargetPos1DiffSqrMag}"); } #endif int posIndex = 0; bool hasValidPathTargetPos = false; if ((afterRotToTargetPos1DiffSqrMag < maxSpeedAddSqr || vehicleData.m_targetPos3.w < 0.01f) && (leaderData.m_flags & (Vehicle.Flags.WaitingPath | Vehicle.Flags.Stopped)) == (Vehicle.Flags) 0) { if (vehicleData.m_path != 0u) { InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, posBeforeWheelRot, posAfterWheelRot, leaderID, ref leaderData, ref posIndex, 1, 4, maxSpeedAddSqr, meanSpeedAddSqr); } if (posIndex < 4) { hasValidPathTargetPos = true; while (posIndex < 4) { vehicleData.SetTargetPos(posIndex, vehicleData.GetTargetPos(posIndex - 1)); posIndex++; } } afterRotToTargetPos1Diff = (Vector3)vehicleData.m_targetPos1 - posAfterWheelRot; afterRotToTargetPos1DiffSqrMag = afterRotToTargetPos1Diff.sqrMagnitude; } #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): posIndex={posIndex} hasValidPathTargetPos={hasValidPathTargetPos}"); } #endif if (leaderData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0) { NetManager netMan = Singleton <NetManager> .instance; byte leaderPathPosIndex = leaderData.m_pathPositionIndex; byte leaderLastPathOffset = leaderData.m_lastPathOffset; if (leaderPathPosIndex == 255) { leaderPathPosIndex = 0; } float leaderLen = 1f + leaderData.CalculateTotalLength(leaderID); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): leaderPathPosIndex={leaderPathPosIndex} leaderLastPathOffset={leaderLastPathOffset} leaderPathPosIndex={leaderPathPosIndex} leaderLen={leaderLen}"); } #endif // reserve space / add traffic PathManager pathMan = Singleton <PathManager> .instance; PathUnit.Position pathPos; if (pathMan.m_pathUnits.m_buffer[leaderData.m_path].GetPosition(leaderPathPosIndex >> 1, out pathPos)) { netMan.m_segments.m_buffer[(int)pathPos.m_segment].AddTraffic(Mathf.RoundToInt(leaderLen * 2.5f)); bool reservedSpaceOnCurrentLane = false; if ((leaderPathPosIndex & 1) == 0 || leaderLastPathOffset == 0) { uint laneId = PathManager.GetLaneID(pathPos); if (laneId != 0u) { Vector3 curPathOffsetPos = netMan.m_lanes.m_buffer[laneId].CalculatePosition((float)pathPos.m_offset * 0.003921569f); float speedAdd = 0.5f * curSpeed * curSpeed / this.m_info.m_braking; float afterWheelRotCurPathOffsetDist = Vector3.Distance(posAfterWheelRot, curPathOffsetPos); float beforeWheelRotCurPathOffsetDist = Vector3.Distance(posBeforeWheelRot, curPathOffsetPos); if (Mathf.Min(afterWheelRotCurPathOffsetDist, beforeWheelRotCurPathOffsetDist) >= speedAdd - 1f) { netMan.m_lanes.m_buffer[laneId].ReserveSpace(leaderLen); reservedSpaceOnCurrentLane = true; } } } if (!reservedSpaceOnCurrentLane && pathMan.m_pathUnits.m_buffer[leaderData.m_path].GetNextPosition(leaderPathPosIndex >> 1, out pathPos)) { uint nextLaneId = PathManager.GetLaneID(pathPos); if (nextLaneId != 0u) { netMan.m_lanes.m_buffer[nextLaneId].ReserveSpace(leaderLen); } } } if ((ulong)(currentFrameIndex >> 4 & 15u) == (ulong)((long)(leaderID & 15))) { // check if vehicle can proceed to next path position bool canProceeed = false; uint curLeaderPathId = leaderData.m_path; int curLeaderPathPosIndex = leaderPathPosIndex >> 1; int k = 0; while (k < 5) { bool invalidPos; if (PathUnit.GetNextPosition(ref curLeaderPathId, ref curLeaderPathPosIndex, out pathPos, out invalidPos)) { uint laneId = PathManager.GetLaneID(pathPos); if (laneId != 0u && !netMan.m_lanes.m_buffer[laneId].CheckSpace(leaderLen)) { k++; continue; } } if (invalidPos) { this.InvalidPath(vehicleID, ref vehicleData, leaderID, ref leaderData); } canProceeed = true; break; } if (!canProceeed) { leaderData.m_flags |= Vehicle.Flags.Congestion; } } } float maxSpeed; if ((leaderData.m_flags & Vehicle.Flags.Stopped) != (Vehicle.Flags) 0) { maxSpeed = 0f; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Vehicle is stopped. maxSpeed={maxSpeed}"); } #endif } else { maxSpeed = Mathf.Min(vehicleData.m_targetPos1.w, GetMaxSpeed(leaderID, ref leaderData)); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Vehicle is not stopped. maxSpeed={maxSpeed}"); } #endif } #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Start of second part. curSpeed={curSpeed} curInvRot={curInvRot}"); } #endif afterRotToTargetPos1Diff = curInvRot * afterRotToTargetPos1Diff; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1Diff={afterRotToTargetPos1Diff} (old afterRotToTargetPos1DiffSqrMag={afterRotToTargetPos1DiffSqrMag})"); } #endif Vector3 zero = Vector3.zero; bool blocked = false; float forwardLen = 0f; if (afterRotToTargetPos1DiffSqrMag > 1f) // TODO why is this not recalculated? { forward = VectorUtils.NormalizeXZ(afterRotToTargetPos1Diff, out forwardLen); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1DiffSqrMag > 1f. forward={forward} forwardLen={forwardLen}"); } #endif if (forwardLen > 1f) { Vector3 fwd = afterRotToTargetPos1Diff; maxSpeedAdd = Mathf.Max(curSpeed, 2f); maxSpeedAddSqr = maxSpeedAdd * maxSpeedAdd; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): forwardLen > 1f. fwd={fwd} maxSpeedAdd={maxSpeedAdd} maxSpeedAddSqr={maxSpeedAddSqr}"); } #endif if (afterRotToTargetPos1DiffSqrMag > maxSpeedAddSqr) { float fwdLimiter = maxSpeedAdd / Mathf.Sqrt(afterRotToTargetPos1DiffSqrMag); fwd.x *= fwdLimiter; fwd.y *= fwdLimiter; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1DiffSqrMag > maxSpeedAddSqr. afterRotToTargetPos1DiffSqrMag={afterRotToTargetPos1DiffSqrMag} maxSpeedAddSqr={maxSpeedAddSqr} fwdLimiter={fwdLimiter} fwd={fwd}"); } #endif } if (fwd.z < -1f) // !!! { #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): fwd.z < -1f. fwd={fwd}"); } #endif if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0) { Vector3 targetPos0TargetPos1Diff = vehicleData.m_targetPos1 - vehicleData.m_targetPos0; if ((curInvRot * targetPos0TargetPos1Diff).z < -0.01f) // !!! { #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): (curInvRot * targetPos0TargetPos1Diff).z < -0.01f. curInvRot={curInvRot} targetPos0TargetPos1Diff={targetPos0TargetPos1Diff}"); } #endif if (afterRotToTargetPos1Diff.z < Mathf.Abs(afterRotToTargetPos1Diff.x) * -10f) // !!! { #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1Diff.z < Mathf.Abs(afterRotToTargetPos1Diff.x) * -10f. fwd={fwd} targetPos0TargetPos1Diff={targetPos0TargetPos1Diff} afterRotToTargetPos1Diff={afterRotToTargetPos1Diff}"); } #endif /*fwd.z = 0f; * afterRotToTargetPos1Diff = Vector3.zero;*/ maxSpeed = 0.5f; // NON-STOCK CODE #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): (1) set maxSpeed={maxSpeed}"); } #endif } else { posAfterWheelRot = posBeforeWheelRot + Vector3.Normalize(vehicleData.m_targetPos1 - vehicleData.m_targetPos0) * this.m_info.m_generatedInfo.m_wheelBase; posIndex = -1; InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, vehicleData.m_targetPos0, vehicleData.m_targetPos1, leaderID, ref leaderData, ref posIndex, 0, 0, Vector3.SqrMagnitude(vehicleData.m_targetPos1 - vehicleData.m_targetPos0) + 1f, 1f); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1Diff.z >= Mathf.Abs(afterRotToTargetPos1Diff.x) * -10f. Invoked UpdatePathTargetPositions. posAfterWheelRot={posAfterWheelRot} posBeforeWheelRot={posBeforeWheelRot} this.m_info.m_generatedInfo.m_wheelBase={this.m_info.m_generatedInfo.m_wheelBase}"); } #endif } } else { posIndex = -1; InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, vehicleData.m_targetPos0, posBeforeWheelRot, leaderID, ref leaderData, ref posIndex, 0, 0, Vector3.SqrMagnitude(posBeforeWheelRot - (Vector3)vehicleData.m_targetPos0) + 1f, 1f); vehicleData.m_targetPos1 = posAfterWheelRot; fwd.z = 0f; afterRotToTargetPos1Diff = Vector3.zero; maxSpeed = 0f; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Vehicle is waiting for a path. posIndex={posIndex} vehicleData.m_targetPos1={vehicleData.m_targetPos1} fwd={fwd} afterRotToTargetPos1Diff={afterRotToTargetPos1Diff} maxSpeed={maxSpeed}"); } #endif } } motionFactor = 0f; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Reset motion factor. motionFactor={motionFactor}"); } #endif } forward = VectorUtils.NormalizeXZ(fwd, out forwardLen); float curve = Mathf.PI / 2f /* 1.57079637f*/ * (1f - forward.z); // <- constant: a bit inaccurate PI/2 if (forwardLen > 1f) { curve /= forwardLen; } float targetDist = forwardLen; #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): targetDist={targetDist} fwd={fwd} curve={curve} maxSpeed={maxSpeed}"); } #endif if (vehicleData.m_targetPos1.w < 0.1f) { maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1000f, curve); maxSpeed = Mathf.Min(maxSpeed, CalculateMaxSpeed(targetDist, vehicleData.m_targetPos1.w, braking * 0.9f)); } else { maxSpeed = Mathf.Min(maxSpeed, this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1000f, curve)); } #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): [1] maxSpeed={maxSpeed}"); } #endif maxSpeed = Mathf.Min(maxSpeed, CalculateMaxSpeed(targetDist, vehicleData.m_targetPos2.w, braking * 0.9f)); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): [2] maxSpeed={maxSpeed}"); } #endif targetDist += VectorUtils.LengthXZ(vehicleData.m_targetPos2 - vehicleData.m_targetPos1); maxSpeed = Mathf.Min(maxSpeed, CalculateMaxSpeed(targetDist, vehicleData.m_targetPos3.w, braking * 0.9f)); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): [3] maxSpeed={maxSpeed}"); } #endif targetDist += VectorUtils.LengthXZ(vehicleData.m_targetPos3 - vehicleData.m_targetPos2); if (vehicleData.m_targetPos3.w < 0.01f) { targetDist = Mathf.Max(0f, targetDist + (this.m_info.m_generatedInfo.m_wheelBase - this.m_info.m_generatedInfo.m_size.z) * 0.5f); } maxSpeed = Mathf.Min(maxSpeed, CalculateMaxSpeed(targetDist, 0f, braking * 0.9f)); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): [4] maxSpeed={maxSpeed}"); } #endif CarAI.CheckOtherVehicles(vehicleID, ref vehicleData, ref frameData, ref maxSpeed, ref blocked, ref zero, estimatedFrameDist, braking * 0.9f, lodPhysics); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): CheckOtherVehicles finished. blocked={blocked}"); } #endif if (maxSpeed < curSpeed) { float brake = Mathf.Max(acceleration, Mathf.Min(braking, curSpeed)); targetSpeed = Mathf.Max(maxSpeed, curSpeed - brake); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): maxSpeed < curSpeed. maxSpeed={maxSpeed} curSpeed={curSpeed} brake={brake} targetSpeed={targetSpeed}"); } #endif } else { float accel = Mathf.Max(acceleration, Mathf.Min(braking, -curSpeed)); targetSpeed = Mathf.Min(maxSpeed, curSpeed + accel); #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): maxSpeed >= curSpeed. maxSpeed={maxSpeed} curSpeed={curSpeed} accel={accel} targetSpeed={targetSpeed}"); } #endif } } } else if (curSpeed < 0.1f && hasValidPathTargetPos && leaderInfo.m_vehicleAI.ArriveAtDestination(leaderID, ref leaderData)) { leaderData.Unspawn(leaderID); return; } if ((leaderData.m_flags & Vehicle.Flags.Stopped) == (Vehicle.Flags) 0 && maxSpeed < 0.1f) { #if DEBUG if (debug) { Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Vehicle is not stopped but maxSpeed < 0.1. maxSpeed={maxSpeed}"); } #endif blocked = true; } if (blocked) { leaderData.m_blockCounter = (byte)Mathf.Min((int)(leaderData.m_blockCounter + 1), 255); } else { leaderData.m_blockCounter = 0; } if (forwardLen > 1f) { turnAngle = Mathf.Asin(forward.x) * Mathf.Sign(targetSpeed); targetMotion = forward * targetSpeed; } else { Vector3 vel = Vector3.ClampMagnitude(afterRotToTargetPos1Diff * 0.5f - curveTangent, braking); targetMotion = curveTangent + vel; } } bool mayBlink = (currentFrameIndex + (uint)leaderID & 16u) != 0u; Vector3 springs = targetMotion - curveTangent; Vector3 targetAfterWheelRotMotion = frameData.m_rotation * targetMotion; Vector3 targetBeforeWheelRotMotion = Vector3.Normalize((Vector3)vehicleData.m_targetPos0 - posBeforeWheelRot) * (targetMotion.magnitude * motionFactor); targetBeforeWheelRotMotion -= targetAfterWheelRotMotion * (Vector3.Dot(targetAfterWheelRotMotion, targetBeforeWheelRotMotion) / Mathf.Max(1f, targetAfterWheelRotMotion.sqrMagnitude)); posAfterWheelRot += targetAfterWheelRotMotion; posBeforeWheelRot += targetBeforeWheelRotMotion; frameData.m_rotation = Quaternion.LookRotation(posAfterWheelRot - posBeforeWheelRot); Vector3 targetPos = posAfterWheelRot - frameData.m_rotation * new Vector3(0f, 0f, this.m_info.m_generatedInfo.m_wheelBase * 0.5f); frameData.m_velocity = targetPos - frameData.m_position; if (leadingVehicle != 0) { frameData.m_position += frameData.m_velocity * 0.6f; } else { frameData.m_position += frameData.m_velocity * 0.5f; } frameData.m_swayVelocity = frameData.m_swayVelocity * (1f - this.m_info.m_dampers) - springs * (1f - this.m_info.m_springs) - frameData.m_swayPosition * this.m_info.m_springs; frameData.m_swayPosition += frameData.m_swayVelocity * 0.5f; frameData.m_steerAngle = 0f; frameData.m_travelDistance += targetMotion.z; if (leadingVehicle != 0) { frameData.m_lightIntensity = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[(int)leaderID].GetLastFrameData().m_lightIntensity; } else { frameData.m_lightIntensity.x = 5f; frameData.m_lightIntensity.y = ((springs.z >= -0.1f) ? 0.5f : 5f); frameData.m_lightIntensity.z = ((turnAngle >= -0.1f || !mayBlink) ? 0f : 5f); frameData.m_lightIntensity.w = ((turnAngle <= 0.1f || !mayBlink) ? 0f : 5f); } frameData.m_underground = ((vehicleData.m_flags & Vehicle.Flags.Underground) != (Vehicle.Flags) 0); frameData.m_transition = ((vehicleData.m_flags & Vehicle.Flags.Transition) != (Vehicle.Flags) 0); //base.SimulationStep(vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); }
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 vehicleData, this.m_info, prevPosition, ref netManager.m_segments.m_buffer[prevPosition.m_segment], pos, maxSpeed); // NON-STOCK CODE END }
public static bool Prefix(TrainAI __instance, VehicleInfo ___m_info, ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { bool reversed = (leaderData.m_flags & Vehicle.Flags.Reversed) != 0; ushort frontVehicleId = (!reversed) ? vehicleData.m_leadingVehicle : vehicleData.m_trailingVehicle; VehicleInfo vehicleInfo = leaderID != vehicleID ? leaderData.Info : ___m_info; TrainAI trainAi = vehicleInfo.m_vehicleAI as TrainAI; if (frontVehicleId != 0) { frameData.m_position += frameData.m_velocity * 0.4f; } else { frameData.m_position += frameData.m_velocity * 0.5f; } frameData.m_swayPosition += frameData.m_swayVelocity * 0.5f; Vector3 posBeforeWheelRot = frameData.m_position; Vector3 posAfterWheelRot = frameData.m_position; Vector3 wheelBaseRot = frameData.m_rotation * new Vector3(0f, 0f, ___m_info.m_generatedInfo.m_wheelBase * 0.5f); if (reversed) { posBeforeWheelRot -= wheelBaseRot; posAfterWheelRot += wheelBaseRot; } else { posBeforeWheelRot += wheelBaseRot; posAfterWheelRot -= wheelBaseRot; } float acceleration = ___m_info.m_acceleration; float braking = ___m_info.m_braking; float curSpeed = frameData.m_velocity.magnitude; Vector3 beforeRotToTargetPos1Diff = (Vector3)vehicleData.m_targetPos1 - posBeforeWheelRot; float beforeRotToTargetPos1DiffSqrMag = beforeRotToTargetPos1Diff.sqrMagnitude; Quaternion curInvRot = Quaternion.Inverse(frameData.m_rotation); Vector3 curveTangent = curInvRot * frameData.m_velocity; Vector3 forward = Vector3.forward; Vector3 targetMotion = Vector3.zero; float targetSpeed = 0f; float motionFactor = 0.5f; if (frontVehicleId != 0) { VehicleManager vehMan = VehicleManager.instance; Vehicle.Frame frontVehLastFrameData = vehMan.m_vehicles.m_buffer[frontVehicleId].GetLastFrameData(); VehicleInfo frontVehInfo = vehMan.m_vehicles.m_buffer[frontVehicleId].Info; float attachOffset; if ((vehicleData.m_flags & Vehicle.Flags.Inverted) != 0 != reversed) { attachOffset = ___m_info.m_attachOffsetBack - (___m_info.m_generatedInfo.m_size.z * 0.5f); } else { attachOffset = ___m_info.m_attachOffsetFront - (___m_info.m_generatedInfo.m_size.z * 0.5f); } float frontAttachOffset; if ((vehMan.m_vehicles.m_buffer[frontVehicleId].m_flags & Vehicle.Flags.Inverted) != 0 != reversed) { frontAttachOffset = frontVehInfo.m_attachOffsetFront - (frontVehInfo.m_generatedInfo.m_size.z * 0.5f); } else { frontAttachOffset = (frontVehInfo.m_attachOffsetBack - (frontVehInfo.m_generatedInfo.m_size.z * 0.5f)); } Vector3 posMinusAttachOffset = frameData.m_position; if (reversed) { posMinusAttachOffset += frameData.m_rotation * new Vector3(0f, 0f, attachOffset); } else { posMinusAttachOffset -= frameData.m_rotation * new Vector3(0f, 0f, attachOffset); } Vector3 frontPosPlusAttachOffset = frontVehLastFrameData.m_position; if (reversed) { frontPosPlusAttachOffset -= frontVehLastFrameData.m_rotation * new Vector3(0f, 0f, frontAttachOffset); } else { frontPosPlusAttachOffset += frontVehLastFrameData.m_rotation * new Vector3(0f, 0f, frontAttachOffset); } Vector3 frontPosMinusWheelBaseRot = frontVehLastFrameData.m_position; wheelBaseRot = frontVehLastFrameData.m_rotation * new Vector3( 0f, 0f, frontVehInfo.m_generatedInfo.m_wheelBase * 0.5f); if (reversed) { frontPosMinusWheelBaseRot += wheelBaseRot; } else { frontPosMinusWheelBaseRot -= wheelBaseRot; } if (Vector3.Dot( vehicleData.m_targetPos1 - vehicleData.m_targetPos0, (Vector3)vehicleData.m_targetPos0 - posAfterWheelRot) < 0f && vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == 0) { int someIndex = -1; UpdatePathTargetPositions( trainAi, vehicleID, ref vehicleData, vehicleData.m_targetPos0, posAfterWheelRot, 0, ref leaderData, ref someIndex, 0, 0, Vector3.SqrMagnitude(posAfterWheelRot - (Vector3)vehicleData.m_targetPos0) + 1f, 1f); beforeRotToTargetPos1DiffSqrMag = 0f; } float maxAttachDist = Mathf.Max(Vector3.Distance(posMinusAttachOffset, frontPosPlusAttachOffset), 2f); const float ONE = 1f; float maxAttachSqrDist = maxAttachDist * maxAttachDist; const float ONE_SQR = ONE * ONE; int i = 0; if (beforeRotToTargetPos1DiffSqrMag < maxAttachSqrDist) { if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == 0) { UpdatePathTargetPositions( trainAi, vehicleID, ref vehicleData, posAfterWheelRot, posBeforeWheelRot, 0, ref leaderData, ref i, 1, 2, maxAttachSqrDist, ONE_SQR); } while (i < 4) { vehicleData.SetTargetPos(i, vehicleData.GetTargetPos(i - 1)); i++; } beforeRotToTargetPos1Diff = (Vector3)vehicleData.m_targetPos1 - posBeforeWheelRot; beforeRotToTargetPos1DiffSqrMag = beforeRotToTargetPos1Diff.sqrMagnitude; } if (vehicleData.m_path != 0u) { NetManager netMan = NetManager.instance; byte pathPosIndex = vehicleData.m_pathPositionIndex; byte lastPathOffset = vehicleData.m_lastPathOffset; if (pathPosIndex == 255) { pathPosIndex = 0; } PathManager pathMan = PathManager.instance; if (pathMan.m_pathUnits.m_buffer[vehicleData.m_path] .GetPosition(pathPosIndex >> 1, out PathUnit.Position curPathPos)) { netMan.m_segments.m_buffer[curPathPos.m_segment].AddTraffic( Mathf.RoundToInt(___m_info.m_generatedInfo.m_size.z * 3f), GetNoiseLevel(trainAi)); if ((pathPosIndex & 1) == 0 || lastPathOffset == 0 || (leaderData.m_flags & Vehicle.Flags.WaitingPath) != 0) { uint laneId = PathManager.GetLaneID(curPathPos); if (laneId != 0u) { netMan.m_lanes.m_buffer[laneId].ReserveSpace(___m_info.m_generatedInfo.m_size.z); } } else if (pathMan.m_pathUnits.m_buffer[vehicleData.m_path] .GetNextPosition(pathPosIndex >> 1, out PathUnit.Position nextPathPos)) { // NON-STOCK CODE START ushort transitNodeId; if (curPathPos.m_offset < 128) { transitNodeId = netMan.m_segments.m_buffer[curPathPos.m_segment].m_startNode; } else { transitNodeId = netMan.m_segments.m_buffer[curPathPos.m_segment].m_endNode; } if (VehicleBehaviorManager.Instance.IsSpaceReservationAllowed( transitNodeId, curPathPos, nextPathPos)) { // NON-STOCK CODE END uint nextLaneId = PathManager.GetLaneID(nextPathPos); if (nextLaneId != 0u) { netMan.m_lanes.m_buffer[nextLaneId].ReserveSpace(___m_info.m_generatedInfo.m_size.z); } } // NON-STOCK CODE } } } beforeRotToTargetPos1Diff = curInvRot * beforeRotToTargetPos1Diff; float negTotalAttachLen = -(((___m_info.m_generatedInfo.m_wheelBase + frontVehInfo.m_generatedInfo.m_wheelBase) * 0.5f) + attachOffset + frontAttachOffset); bool hasPath = false; if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == 0) { if (Line3.Intersect( posBeforeWheelRot, vehicleData.m_targetPos1, frontPosMinusWheelBaseRot, negTotalAttachLen, out float u1, out float u2)) { targetMotion = beforeRotToTargetPos1Diff * Mathf.Clamp(Mathf.Min(u1, u2) / 0.6f, 0f, 2f); } else { Line3.DistanceSqr( posBeforeWheelRot, vehicleData.m_targetPos1, frontPosMinusWheelBaseRot, out u1); targetMotion = beforeRotToTargetPos1Diff * Mathf.Clamp(u1 / 0.6f, 0f, 2f); } hasPath = true; } if (hasPath) { if (Vector3.Dot( frontPosMinusWheelBaseRot - posBeforeWheelRot, posBeforeWheelRot - posAfterWheelRot) < 0f) { motionFactor = 0f; } } else { float frontPosBeforeToAfterWheelRotDist = Vector3.Distance( frontPosMinusWheelBaseRot, posBeforeWheelRot); motionFactor = 0f; targetMotion = curInvRot * ((frontPosMinusWheelBaseRot - posBeforeWheelRot) * (Mathf.Max(0f, frontPosBeforeToAfterWheelRotDist - negTotalAttachLen) / Mathf.Max(1f, frontPosBeforeToAfterWheelRotDist * 0.6f))); } }
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { if (CustomCarAI.sm_speedData[vehicleID].speedMultiplier == 0 || CustomCarAI.sm_speedData[vehicleID].currentPath != vehicleData.m_path) { CustomCarAI.sm_speedData[vehicleID].currentPath = vehicleData.m_path; if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2) { CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(1f, 1.75f); } else { CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(0.65f, 1f); } } CustomCarAI.sm_speedData[vehicleID].ApplySpeedMultiplier(this.m_info); } frameData.m_blinkState = (((vehicleData.m_flags & (Vehicle.Flags.Emergency1 | Vehicle.Flags.Emergency2)) == Vehicle.Flags.None) ? 0f : 10f); CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); bool flag = false; if (vehicleData.m_targetBuilding != 0) { BuildingManager instance = Singleton <BuildingManager> .instance; Vector3 a = instance.m_buildings.m_buffer[(int)vehicleData.m_targetBuilding].CalculateSidewalkPosition(); flag = ((a - frameData.m_position).sqrMagnitude < 4096f); bool flag2 = (vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None || frameData.m_velocity.sqrMagnitude < 0.0100000007f; if (flag && (vehicleData.m_flags & Vehicle.Flags.Emergency2) != Vehicle.Flags.None) { vehicleData.m_flags = ((vehicleData.m_flags & ~Vehicle.Flags.Emergency2) | Vehicle.Flags.Emergency1); } if (flag && flag2) { if (vehicleData.m_blockCounter > 8) { vehicleData.m_blockCounter = 8; } if (vehicleData.m_blockCounter == 8 && (vehicleData.m_flags & Vehicle.Flags.Stopped) == Vehicle.Flags.None) { this.ArriveAtTarget(leaderID, ref leaderData); } if (this.ExtinguishFire(vehicleID, ref vehicleData, vehicleData.m_targetBuilding, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)vehicleData.m_targetBuilding])) { this.SetTarget(vehicleID, ref vehicleData, 0); } } else { if (instance.m_buildings.m_buffer[(int)vehicleData.m_targetBuilding].m_fireIntensity == 0) { this.SetTarget(vehicleID, ref vehicleData, 0); } } } if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None && !flag && this.CanLeave(vehicleID, ref vehicleData)) { vehicleData.m_flags &= ~Vehicle.Flags.Stopped; vehicleData.m_flags |= Vehicle.Flags.Leaving; } if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == Vehicle.Flags.None) { if (this.ShouldReturnToSource(vehicleID, ref vehicleData)) { this.SetTarget(vehicleID, ref vehicleData, 0); } } else { if ((ulong)(Singleton <SimulationManager> .instance.m_currentFrameIndex >> 4 & 15u) == (ulong)((long)(vehicleID & 15)) && !this.ShouldReturnToSource(vehicleID, ref vehicleData)) { TransferManager.TransferOffer offer = default(TransferManager.TransferOffer); offer.Priority = 3; offer.Vehicle = vehicleID; offer.Position = frameData.m_position; offer.Amount = 1; offer.Active = true; Singleton <TransferManager> .instance.AddIncomingOffer((TransferManager.TransferReason) vehicleData.m_transferType, offer); } } if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { CustomCarAI.sm_speedData[vehicleID].RestoreVehicleSpeed(this.m_info); } }
private void TryCollectCrime(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData) { throw new NotImplementedException("TryCollectCrime is target of redirection and is not implemented."); }
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 }
private static ushort CheckOtherVehicle(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ref float maxSpeed, ref bool blocked, ref Vector3 collisionPush, float maxBraking, ushort otherID, ref Vehicle otherData, Vector3 min, Vector3 max, int lodPhysics) { Log.Error("CustomCarAI.CheckOtherVehicle called"); return(0); }
public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { if (CustomCarAI.sm_speedData[vehicleID].speedMultiplier == 0 || CustomCarAI.sm_speedData[vehicleID].currentPath != vehicleData.m_path) { CustomCarAI.sm_speedData[vehicleID].currentPath = vehicleData.m_path; CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(0.6f, 1.4f); } CustomCarAI.sm_speedData[vehicleID].ApplySpeedMultiplier(this.m_info); } if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None) { vehicleData.m_waitCounter += 1; if (this.CanLeave(vehicleID, ref vehicleData)) { vehicleData.m_flags &= ~Vehicle.Flags.Stopped; vehicleData.m_waitCounter = 0; } } CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics); if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds) { CustomCarAI.sm_speedData[vehicleID].RestoreVehicleSpeed(this.m_info); } }