@inventure71/paddockjs 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/INSTALL_AND_UPDATE.md +31 -5
- package/README.md +34 -3
- package/docs/advanced_ai_pace.md +131 -0
- package/docs/advanced_physics_rebuild.md +166 -0
- package/docs/architecture.md +111 -30
- package/docs/cleanup_coverage.md +284 -0
- package/docs/component_inventory.md +32 -16
- package/docs/composable-layouts.md +2 -0
- package/docs/concepts.md +12 -1
- package/docs/custom_model_controller.md +1 -1
- package/docs/data_contract.md +33 -10
- package/docs/data_model.md +4 -2
- package/docs/efficiency_cleanup_2026-10-13.md +80 -0
- package/docs/getting-started.md +3 -0
- package/docs/grid_walk.md +80 -0
- package/docs/index.md +5 -2
- package/docs/keyboard_driving_fix.md +118 -0
- package/docs/limit_driving_2026-10-14.md +88 -0
- package/docs/loading.md +141 -0
- package/docs/maintainability_audit_2026-09-08.md +146 -0
- package/docs/racing_ai_improvements.md +145 -0
- package/docs/rules.md +43 -13
- package/docs/sense_contract.md +4 -1
- package/docs/system_specs.md +40 -12
- package/docs/testing-reliability-guide.md +67 -0
- package/docs/v11_improvements.md +108 -0
- package/package.json +23 -15
- package/src/api/MountedSimulatorComponents.js +101 -0
- package/src/api/PaddockSimulatorController.js +56 -81
- package/src/app/BrowserExpertAdapter.js +0 -6
- package/src/app/BrowserExpertExternalRenderer.js +72 -50
- package/src/app/ExternalTrackSnapshot.js +50 -0
- package/src/app/F1SimulatorApp.js +242 -297
- package/src/app/HostLifecycleEmitter.js +93 -0
- package/src/app/banners/raceDataBannerController.js +9 -4
- package/src/app/camera/cameraConstants.js +1 -1
- package/src/app/camera/cameraController.js +10 -13
- package/src/app/camera/cameraGeometry.js +1 -1
- package/src/app/controls/SimulatorViewControls.js +45 -0
- package/src/app/controls/workbenchBindings.js +64 -0
- package/src/app/controls/workbenchDisclosure.js +41 -0
- package/src/app/domBindings.js +21 -13
- package/src/app/gridWalk/GridWalkController.js +180 -0
- package/src/app/gridWalk/gridWalkCamera.js +88 -0
- package/src/app/gridWalk/gridWalkControls.js +24 -0
- package/src/app/gridWalk/gridWalkCrew.js +246 -0
- package/src/app/gridWalk/gridWalkLabels.js +104 -0
- package/src/app/gridWalk/gridWalkLayout.js +46 -0
- package/src/app/gridWalk/gridWalkNavigation.js +99 -0
- package/src/app/gridWalk/gridWalkProjectBanner.js +43 -0
- package/src/app/gridWalk/gridWalkSession.js +50 -0
- package/src/app/layoutSupport.js +2 -0
- package/src/app/raceOverlayClearanceSupport.js +21 -7
- package/src/app/readouts/carOverviewRenderer.js +9 -4
- package/src/app/readouts/readoutFormatters.js +1 -8
- package/src/app/readouts/telemetryRenderer.js +1 -3
- package/src/app/readouts/timingTowerRenderer.js +48 -50
- package/src/app/rendering/appAssets.js +8 -10
- package/src/app/rendering/carRenderer.js +27 -79
- package/src/app/rendering/displayUtils.js +0 -6
- package/src/app/rendering/expertSensorRenderer.js +1 -1
- package/src/app/rendering/replayGhostRenderer.js +4 -1
- package/src/app/rendering/trackRenderer.js +2 -2
- package/src/app/runtime/frameLoop.js +18 -17
- package/src/app/runtime/pixiStartupLifecycle.js +94 -0
- package/src/app/runtime/runtimeTiming.js +4 -1
- package/src/app/runtime/runtimeVisibility.js +7 -2
- package/src/config/cssValues.js +1 -1
- package/src/config/defaultOptions.js +12 -173
- package/src/config/restartOptions.js +1 -0
- package/src/config/runtimeSeed.js +10 -0
- package/src/config/simulatorDefaults.js +106 -0
- package/src/config/telemetryModules.js +20 -0
- package/src/config/theme/cssTokens.js +85 -0
- package/src/config/theme/themeCss.js +72 -0
- package/src/config/theme/themeInputs.js +155 -0
- package/src/config/theme/themeResolver.js +172 -0
- package/src/config/theme/themeSelectors.js +69 -0
- package/src/config/theme/themeTokens.js +257 -0
- package/src/config/theme/themeUtils.js +15 -0
- package/src/config/themeOptions.js +14 -830
- package/src/config/timingGapMode.js +0 -2
- package/src/config/uiOptions.js +53 -0
- package/src/data/championship.js +16 -158
- package/src/data/championshipDefaults.js +87 -0
- package/src/data/driverData.js +10 -20
- package/src/data/entryIdentity.js +67 -0
- package/src/data/entryPresentation.js +23 -0
- package/src/data/entryTypes.d.ts +160 -0
- package/src/data/index.d.ts +12 -195
- package/src/data/ratingScale.js +14 -0
- package/src/data/teamTypes.d.ts +23 -0
- package/src/data/trackTypes.d.ts +101 -0
- package/src/data/vehicleData.js +12 -23
- package/src/environment/actions.js +3 -2
- package/src/environment/controllerLoop.js +57 -44
- package/src/environment/controllerScheduler.js +30 -0
- package/src/environment/driverObservations.js +260 -0
- package/src/environment/driverReset.js +51 -0
- package/src/environment/episode.js +0 -1
- package/src/environment/evaluation.js +6 -90
- package/src/environment/evaluationTracker.js +100 -0
- package/src/environment/events.js +23 -0
- package/src/environment/index.d.ts +35 -91
- package/src/environment/metrics.js +3 -17
- package/src/environment/observationSchema.js +104 -0
- package/src/environment/observationVector.js +16 -115
- package/src/environment/observations.js +16 -316
- package/src/environment/options.js +5 -24
- package/src/environment/renderFrames.js +21 -0
- package/src/environment/resetOptions.js +41 -0
- package/src/environment/results.js +125 -0
- package/src/environment/rewards.js +10 -16
- package/src/environment/runtime.js +17 -300
- package/src/environment/scenarioOptions.js +90 -0
- package/src/environment/scenarioPlacements.js +70 -0
- package/src/environment/scenarioPresets.js +78 -0
- package/src/environment/scenarios.js +5 -236
- package/src/environment/scratch.js +18 -0
- package/src/environment/sensorOptions.js +20 -0
- package/src/environment/sensors/index.js +2 -556
- package/src/environment/sensors/indexedRayBands.js +0 -18
- package/src/environment/sensors/nearbyCars.js +18 -15
- package/src/environment/sensors/opponentRadar.js +3 -2
- package/src/environment/sensors/pitConnectorProximity.js +20 -0
- package/src/environment/sensors/rayBandTrace.js +1 -37
- package/src/environment/sensors/rayBatch.js +81 -0
- package/src/environment/sensors/rayConfig.js +26 -0
- package/src/environment/sensors/rayGeometry.js +0 -8
- package/src/environment/sensors/rayGuards.js +0 -6
- package/src/environment/sensors/rayOutputs.js +75 -0
- package/src/environment/sensors/rayQuery.js +110 -0
- package/src/environment/sensors/rayScratch.js +146 -0
- package/src/environment/sensors/sensorTargets.js +12 -4
- package/src/environment/sensors/surfaceRays.js +6 -61
- package/src/environment/sensors/trackRays.js +7 -80
- package/src/environment/simulationSetup.js +30 -0
- package/src/environment/specs.js +15 -109
- package/src/index.d.ts +43 -202
- package/src/index.js +28 -6
- package/src/placeholder/index.js +1 -8
- package/src/rendering/displayLifecycle.js +6 -0
- package/src/rendering/proceduralTrackAsset.js +1 -1
- package/src/rendering/renderSnapshot.js +3 -0
- package/src/rendering/track/finishLineRenderer.js +1 -1
- package/src/rendering/track/gridRenderer.js +1 -1
- package/src/rendering/track/offsetStrokeSafety.js +2 -2
- package/src/rendering/track/pitLaneRenderer.js +1 -1
- package/src/rendering/track/trackMaterialRenderer.js +4 -4
- package/src/rendering/track/trackRenderConstants.js +0 -1
- package/src/rendering/track/trackRenderGeometry.js +1 -7
- package/src/simulation/collisionGeometry.js +12 -20
- package/src/simulation/driver/advancedPathControls.js +53 -0
- package/src/simulation/driver/advancedRacePace.js +112 -0
- package/src/simulation/driver/advancedRacingControls.js +61 -0
- package/src/simulation/driver/advancedRacingEnvelope.js +255 -0
- package/src/simulation/driver/advancedRacingSteering.js +76 -0
- package/src/simulation/driver/advancedRacingTiming.js +16 -0
- package/src/simulation/driver/arcadeRacePace.js +83 -0
- package/src/simulation/driver/arcadeRacingControls.js +111 -0
- package/src/simulation/driver/arcadeRacingEnvelope.js +63 -0
- package/src/simulation/driver/driverControlConstants.js +0 -2
- package/src/simulation/driver/driverController.js +16 -5
- package/src/simulation/driver/edgeRecovery.js +2 -3
- package/src/simulation/driver/racingControls.js +10 -396
- package/src/simulation/driver/racingDriverProfile.js +48 -0
- package/src/simulation/driver/racingLinePlan.js +54 -20
- package/src/simulation/driver/rejoinControls.js +59 -112
- package/src/simulation/driver/safetyCarControls.js +12 -0
- package/src/simulation/driver/trafficScan.js +136 -27
- package/src/simulation/participants/participantInteractions.js +24 -15
- package/src/simulation/pit/pitCarPlacement.js +29 -0
- package/src/simulation/pit/pitFlow.js +8 -30
- package/src/simulation/pit/pitIntent.js +4 -3
- package/src/simulation/pit/pitOccupancy.js +2 -2
- package/src/simulation/pit/pitQueue.js +2 -18
- package/src/simulation/pit/pitRouteMovement.js +1 -36
- package/src/simulation/pit/pitRouting.js +5 -81
- package/src/simulation/pit/pitService.js +3 -32
- package/src/simulation/pit/pitServiceConstants.js +1 -0
- package/src/simulation/pit/pitServiceProgress.js +34 -0
- package/src/simulation/pit/pitSnapshots.js +8 -4
- package/src/simulation/pit/pitState.js +1 -5
- package/src/simulation/race/classification.js +1 -8
- package/src/simulation/race/raceFinish.js +3 -8
- package/src/simulation/race/raceOrder.js +2 -13
- package/src/simulation/race/raceProgress.js +6 -20
- package/src/simulation/race/raceSetup.js +1 -1
- package/src/simulation/race/raceStep.js +20 -11
- package/src/simulation/race/redFlag.js +2 -4
- package/src/simulation/race/safetyCar.js +5 -9
- package/src/simulation/race/stalledDnf.js +2 -4
- package/src/simulation/raceSimulation.js +6 -38
- package/src/simulation/replay/replayGhosts.js +44 -32
- package/src/simulation/rules/collisionSteward.js +0 -14
- package/src/simulation/rules/penaltyActions.js +37 -0
- package/src/simulation/rules/penaltyLedger.js +8 -1
- package/src/simulation/rules/pitLaneSpeedingSteward.js +1 -1
- package/src/simulation/rules/rulesReview.js +20 -16
- package/src/simulation/rules/trackLimitsSteward.js +2 -2
- package/src/simulation/simMath.js +4 -0
- package/src/simulation/snapshots/raceSnapshots.js +30 -11
- package/src/simulation/timing/drsState.js +8 -0
- package/src/simulation/timing/drsTiming.js +2 -4
- package/src/simulation/timing/lapTelemetry.js +7 -4
- package/src/simulation/timing/sectorPerformance.js +14 -6
- package/src/simulation/timing/timingLines.js +12 -6
- package/src/simulation/track/pitLaneAccess.js +2 -2
- package/src/simulation/track/pitLaneLayout.js +4 -135
- package/src/simulation/track/pitLaneModel.js +70 -0
- package/src/simulation/track/pitLaneState.js +0 -1
- package/src/simulation/track/pitServiceLayout.js +121 -0
- package/src/simulation/track/proceduralTrack.js +77 -0
- package/src/simulation/track/spatialQueries.js +76 -31
- package/src/simulation/track/trackBuilder.js +54 -0
- package/src/simulation/track/trackConstants.js +0 -22
- package/src/simulation/track/trackMath.js +4 -29
- package/src/simulation/track/trackModel.js +12 -240
- package/src/simulation/track/trackModelCache.js +105 -0
- package/src/simulation/track/trackNearestQueries.js +1218 -0
- package/src/simulation/track/trackQueryConstants.js +3 -0
- package/src/simulation/track/trackQueryConstruction.js +368 -0
- package/src/simulation/track/trackQueryIndex.js +12 -1933
- package/src/simulation/track/trackQuerySegments.js +174 -0
- package/src/simulation/track/trackQueryStats.js +12 -0
- package/src/simulation/track/trackRayQueries.js +165 -0
- package/src/simulation/vehicle/advancedContactResponse.js +89 -0
- package/src/simulation/vehicle/advancedTireForces.js +92 -0
- package/src/simulation/vehicle/advancedVehicleModel.js +65 -0
- package/src/simulation/vehicle/advancedVehiclePhysics.js +127 -0
- package/src/simulation/vehicle/contactResolution.js +23 -9
- package/src/simulation/vehicle/mainTrackWheelSurface.js +2 -13
- package/src/simulation/vehicle/pitWheelSurface.js +0 -12
- package/src/simulation/vehicle/runoffResponse.js +2 -4
- package/src/simulation/vehicle/sampledWheelSurface.js +266 -0
- package/src/simulation/vehicle/vehicleGeometry.js +85 -103
- package/src/simulation/vehicle/vehicleKinematics.js +10 -0
- package/src/simulation/vehicle/vehiclePhysics.js +42 -196
- package/src/simulation/vehicle/vehicleSnapshots.js +18 -6
- package/src/simulation/vehicle/vehicleState.js +5 -3
- package/src/simulation/vehicle/wheelSurface.js +13 -432
- package/src/simulation/vehicle/wheelSurfaceCache.js +55 -0
- package/src/simulation/vehicle/wheelSurfaceSummary.js +101 -0
- package/src/styles.css +173 -19
- package/src/ui/bannerTemplates.js +4 -2
- package/src/ui/cameraControlsTemplate.js +4 -2
- package/src/ui/gridWalkTemplate.js +29 -0
- package/src/ui/htmlEscaping.js +8 -0
- package/src/ui/raceCanvasTemplate.js +3 -2
- package/src/ui/shellTemplate.js +3 -0
- package/src/ui/telemetryDrawerTemplate.js +4 -2
- package/src/ui/telemetryTemplates.js +3 -22
- package/src/ui/templateUtils.js +2 -8
- package/src/ui/viewControlsTemplate.js +21 -0
- package/examples/train-basic-policy.mjs +0 -276
- package/examples/trainingData.mjs +0 -133
|
@@ -41,14 +41,6 @@ export const PARTICIPANT_INTERACTION_PROFILES = Object.freeze({
|
|
|
41
41
|
}),
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
const INTERACTION_FLAGS = Object.freeze([
|
|
45
|
-
'collidable',
|
|
46
|
-
'detectableByRays',
|
|
47
|
-
'detectableAsNearby',
|
|
48
|
-
'blocksPitLane',
|
|
49
|
-
'affectsRaceOrder',
|
|
50
|
-
]);
|
|
51
|
-
|
|
52
44
|
export function normalizeParticipantInteractions(options = {}) {
|
|
53
45
|
const defaultProfile = resolveProfileName(options.defaultProfile);
|
|
54
46
|
const defaultInteraction = { ...PARTICIPANT_INTERACTION_PROFILES[defaultProfile] };
|
|
@@ -73,11 +65,15 @@ export function attachParticipantInteractions(cars = [], options = {}) {
|
|
|
73
65
|
|
|
74
66
|
export function resolveInteraction(override = {}, fallbackProfile = 'normal') {
|
|
75
67
|
const profile = resolveProfileName(override?.profile ?? fallbackProfile);
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
68
|
+
const base = PARTICIPANT_INTERACTION_PROFILES[profile];
|
|
69
|
+
return {
|
|
70
|
+
profile,
|
|
71
|
+
collidable: override?.collidable != null ? Boolean(override.collidable) : base.collidable,
|
|
72
|
+
detectableByRays: override?.detectableByRays != null ? Boolean(override.detectableByRays) : base.detectableByRays,
|
|
73
|
+
detectableAsNearby: override?.detectableAsNearby != null ? Boolean(override.detectableAsNearby) : base.detectableAsNearby,
|
|
74
|
+
blocksPitLane: override?.blocksPitLane != null ? Boolean(override.blocksPitLane) : base.blocksPitLane,
|
|
75
|
+
affectsRaceOrder: override?.affectsRaceOrder != null ? Boolean(override.affectsRaceOrder) : base.affectsRaceOrder,
|
|
76
|
+
};
|
|
81
77
|
}
|
|
82
78
|
|
|
83
79
|
export function canCollide(first, second) {
|
|
@@ -110,8 +106,21 @@ export function affectsRaceOrder(car) {
|
|
|
110
106
|
}
|
|
111
107
|
|
|
112
108
|
export function serializeParticipantInteraction(interaction) {
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
return resolveInteraction(interaction ?? {}, interaction?.profile ?? 'normal');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const SERIALIZED_INTERACTION_SOURCE = Symbol('serializedInteractionSource');
|
|
113
|
+
const SERIALIZED_INTERACTION_VALUE = Symbol('serializedInteractionValue');
|
|
114
|
+
|
|
115
|
+
// Render snapshots are pooled and rebuilt every frame; the interaction config
|
|
116
|
+
// only changes when a new object is attached, so cache the serialized form per
|
|
117
|
+
// car keyed on the interaction reference.
|
|
118
|
+
export function serializeParticipantInteractionCached(car) {
|
|
119
|
+
if (car[SERIALIZED_INTERACTION_SOURCE] !== car.interaction || !car[SERIALIZED_INTERACTION_VALUE]) {
|
|
120
|
+
car[SERIALIZED_INTERACTION_SOURCE] = car.interaction;
|
|
121
|
+
car[SERIALIZED_INTERACTION_VALUE] = serializeParticipantInteraction(car.interaction);
|
|
122
|
+
}
|
|
123
|
+
return car[SERIALIZED_INTERACTION_VALUE];
|
|
115
124
|
}
|
|
116
125
|
|
|
117
126
|
function resolveProfileName(profile) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { applyWheelSurfaceState } from '../vehicle/wheelSurface.js';
|
|
2
|
+
import { syncPitCarKinematics } from './pitKinematics.js';
|
|
3
|
+
import { getPitBoxRaceDistance } from './pitOccupancy.js';
|
|
4
|
+
|
|
5
|
+
// Pit control owns this pose while a car waits or receives stationary service.
|
|
6
|
+
export function holdPitCarAtBox(sim, car, box, { queue = false, updatePreviousPose = false } = {}) {
|
|
7
|
+
if (updatePreviousPose) {
|
|
8
|
+
car.previousX = car.x;
|
|
9
|
+
car.previousY = car.y;
|
|
10
|
+
car.previousHeading = car.heading;
|
|
11
|
+
}
|
|
12
|
+
const position = queue ? box.queuePoint : box.center;
|
|
13
|
+
car.x = position.x;
|
|
14
|
+
car.y = position.y;
|
|
15
|
+
car.heading = sim.track.pitLane.mainLane.heading;
|
|
16
|
+
car.speed = 0;
|
|
17
|
+
car.throttle = 0;
|
|
18
|
+
car.brake = 1;
|
|
19
|
+
car.steeringAngle = 0;
|
|
20
|
+
car.yawRate = 0;
|
|
21
|
+
car.turnRadius = Infinity;
|
|
22
|
+
syncPitCarKinematics(car, { physicsMode: sim.physicsMode });
|
|
23
|
+
applyWheelSurfaceState(car, sim.track);
|
|
24
|
+
car.progress = car.trackState.distance;
|
|
25
|
+
car.raceDistance = getPitBoxRaceDistance(sim, car.pitStop, queue ? {
|
|
26
|
+
...box,
|
|
27
|
+
distanceAlongLane: box.queueDistanceAlongLane ?? box.distanceAlongLane,
|
|
28
|
+
} : box);
|
|
29
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { clearCurrentDrsState } from '../timing/drsState.js';
|
|
1
2
|
import { pitLaneStatusSnapshot } from './pitSnapshots.js';
|
|
2
3
|
import {
|
|
3
4
|
firstDifferentCompound,
|
|
4
|
-
normalizePitIntent,
|
|
5
5
|
shouldStartPitStopForSimulation,
|
|
6
6
|
updateAutomaticPitIntentForSimulation,
|
|
7
7
|
} from './pitIntent.js';
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
isPitServiceQueueOccupied,
|
|
18
18
|
releasePitQueue,
|
|
19
19
|
} from './pitService.js';
|
|
20
|
-
import {
|
|
20
|
+
import { holdPitCarAtBox } from './pitCarPlacement.js';
|
|
21
21
|
import {
|
|
22
22
|
createPitApproachPoints,
|
|
23
23
|
createRoute,
|
|
@@ -27,13 +27,12 @@ import {
|
|
|
27
27
|
} from './pitRouting.js';
|
|
28
28
|
import { metersToSimUnits } from '../units.js';
|
|
29
29
|
import { applyWheelSurfaceState } from '../vehicle/wheelSurface.js';
|
|
30
|
+
import { PIT_ENTRY_APPROACH_DISTANCE, PIT_BOX_APPROACH_DISTANCE } from './pitServiceConstants.js';
|
|
30
31
|
|
|
31
|
-
const PIT_ENTRY_APPROACH_DISTANCE = metersToSimUnits(250);
|
|
32
|
-
const PIT_BOX_APPROACH_DISTANCE = metersToSimUnits(34);
|
|
33
32
|
const PIT_SERVICE_QUEUE_FALLBACK_GAP = metersToSimUnits(48);
|
|
34
33
|
const PIT_ENTRY_LATE_THRESHOLD_DISTANCE = metersToSimUnits(90);
|
|
35
34
|
|
|
36
|
-
export function isCarInActivePitStop(
|
|
35
|
+
export function isCarInActivePitStop(car) {
|
|
37
36
|
return Boolean(car?.pitStop && car.pitStop.status !== 'pending' && car.pitStop.status !== 'completed');
|
|
38
37
|
}
|
|
39
38
|
|
|
@@ -82,7 +81,7 @@ export function canStartPitStop(sim, car) {
|
|
|
82
81
|
let activeCount = 0;
|
|
83
82
|
for (let index = 0; index < sim.cars.length; index += 1) {
|
|
84
83
|
const candidate = sim.cars[index];
|
|
85
|
-
if (candidate === car || !isCarInActivePitStop(
|
|
84
|
+
if (candidate === car || !isCarInActivePitStop(candidate)) continue;
|
|
86
85
|
activeCount += 1;
|
|
87
86
|
if (activeCount >= maxConcurrentPitLaneCars) return false;
|
|
88
87
|
}
|
|
@@ -96,7 +95,7 @@ export function canStartPitStop(sim, car) {
|
|
|
96
95
|
const candidateDistance = car.raceDistance ?? 0;
|
|
97
96
|
for (let index = 0; index < sim.cars.length; index += 1) {
|
|
98
97
|
const candidate = sim.cars[index];
|
|
99
|
-
if (candidate === car || !isCarInActivePitStop(
|
|
98
|
+
if (candidate === car || !isCarInActivePitStop(candidate)) continue;
|
|
100
99
|
const gap = (candidate.raceDistance ?? 0) - candidateDistance;
|
|
101
100
|
if (gap >= 0 && gap < minimumGap) return false;
|
|
102
101
|
}
|
|
@@ -126,10 +125,7 @@ export function startPitStop(sim, car) {
|
|
|
126
125
|
if (!stop || !box || !pitLane?.enabled) return false;
|
|
127
126
|
|
|
128
127
|
car.gridLocked = false;
|
|
129
|
-
car
|
|
130
|
-
car.drsEligible = false;
|
|
131
|
-
car.drsZoneId = null;
|
|
132
|
-
car.drsZoneEnabled = false;
|
|
128
|
+
clearCurrentDrsState(car);
|
|
133
129
|
car.canAttack = false;
|
|
134
130
|
stop.targetTire = stop.targetTire ?? firstDifferentCompound(car.tire, sim.rules.modules?.tireStrategy?.compounds);
|
|
135
131
|
|
|
@@ -213,25 +209,7 @@ export function advancePitStopCar(sim, car, delta) {
|
|
|
213
209
|
if (stop.status === 'queued') {
|
|
214
210
|
const box = getPitStopBox(sim, stop);
|
|
215
211
|
if (!box) return true;
|
|
216
|
-
car
|
|
217
|
-
car.previousY = car.y;
|
|
218
|
-
car.previousHeading = car.heading;
|
|
219
|
-
car.x = box.queuePoint.x;
|
|
220
|
-
car.y = box.queuePoint.y;
|
|
221
|
-
car.heading = sim.track.pitLane.mainLane.heading;
|
|
222
|
-
car.speed = 0;
|
|
223
|
-
car.throttle = 0;
|
|
224
|
-
car.brake = 1;
|
|
225
|
-
car.steeringAngle = 0;
|
|
226
|
-
car.yawRate = 0;
|
|
227
|
-
car.turnRadius = Infinity;
|
|
228
|
-
syncPitCarKinematics(car, { physicsMode: sim.physicsMode });
|
|
229
|
-
applyWheelSurfaceState(car, sim.track);
|
|
230
|
-
car.progress = car.trackState.distance;
|
|
231
|
-
car.raceDistance = getPitBoxRaceDistance(sim, stop, {
|
|
232
|
-
...box,
|
|
233
|
-
distanceAlongLane: box.queueDistanceAlongLane ?? box.distanceAlongLane,
|
|
234
|
-
});
|
|
212
|
+
holdPitCarAtBox(sim, car, box, { queue: true, updatePreviousPose: true });
|
|
235
213
|
if (!isPitServiceBusy(sim, car, box)) releasePitQueue(sim, car, box);
|
|
236
214
|
return true;
|
|
237
215
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export const PIT_INTENT_NONE = 0;
|
|
2
|
-
export const PIT_INTENT_IF_FREE = 1;
|
|
3
|
-
export const PIT_INTENT_COMMITTED = 2;
|
|
4
2
|
|
|
5
3
|
export function firstDifferentCompound(currentTire, compounds) {
|
|
6
4
|
const available = Array.isArray(compounds) && compounds.length ? compounds : ['S', 'M', 'H'];
|
|
@@ -87,6 +85,9 @@ export function updateAutomaticPitIntentForSimulation(sim, car) {
|
|
|
87
85
|
if (nextIntent === 0 || nextIntent <= (normalizePitIntent(stop.intent) ?? 0)) return;
|
|
88
86
|
|
|
89
87
|
stop.intent = nextIntent;
|
|
90
|
-
if (stop.status === 'completed')
|
|
88
|
+
if (stop.status === 'completed') {
|
|
89
|
+
stop.targetTire = firstDifferentCompound(car.tire, sim.rules.modules?.tireStrategy?.compounds);
|
|
90
|
+
sim.rearmCompletedPitStop(car, stop);
|
|
91
|
+
}
|
|
91
92
|
else sim.schedulePitStopAtNextEntry(car, stop);
|
|
92
93
|
}
|
|
@@ -7,7 +7,7 @@ export function getPitStopBox(sim, stop) {
|
|
|
7
7
|
null;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export function isPitServiceAreaOccupied(
|
|
10
|
+
export function isPitServiceAreaOccupied(candidate, box, clearDistance) {
|
|
11
11
|
if (!blocksPitLane(candidate)) return false;
|
|
12
12
|
const status = candidate?.pitStop?.status;
|
|
13
13
|
const phase = candidate?.pitStop?.phase;
|
|
@@ -23,7 +23,7 @@ export function isPitServiceBusy(sim, car, box, clearDistance = PIT_SERVICE_CLEA
|
|
|
23
23
|
candidate !== car &&
|
|
24
24
|
blocksPitLane(candidate) &&
|
|
25
25
|
candidate.pitStop?.boxId === box?.id &&
|
|
26
|
-
isPitServiceAreaOccupied(
|
|
26
|
+
isPitServiceAreaOccupied(candidate, box, clearDistance)
|
|
27
27
|
));
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { applyWheelSurfaceState } from '../vehicle/wheelSurface.js';
|
|
2
1
|
import { createRoute, routePoint } from './pitRouting.js';
|
|
3
|
-
import {
|
|
2
|
+
import { holdPitCarAtBox } from './pitCarPlacement.js';
|
|
4
3
|
import { PIT_QUEUE_RELEASE_SPEED } from './pitServiceConstants.js';
|
|
5
4
|
import { getPitBoxRaceDistance } from './pitOccupancy.js';
|
|
6
5
|
|
|
@@ -12,22 +11,7 @@ export function beginPitQueue(sim, car, box) {
|
|
|
12
11
|
stop.route = null;
|
|
13
12
|
stop.routeProgress = 0;
|
|
14
13
|
stop.queueingForService = false;
|
|
15
|
-
car
|
|
16
|
-
car.y = box.queuePoint.y;
|
|
17
|
-
car.heading = sim.track.pitLane.mainLane.heading;
|
|
18
|
-
car.speed = 0;
|
|
19
|
-
car.throttle = 0;
|
|
20
|
-
car.brake = 1;
|
|
21
|
-
car.steeringAngle = 0;
|
|
22
|
-
car.yawRate = 0;
|
|
23
|
-
car.turnRadius = Infinity;
|
|
24
|
-
syncPitCarKinematics(car, { physicsMode: sim.physicsMode });
|
|
25
|
-
applyWheelSurfaceState(car, sim.track);
|
|
26
|
-
car.progress = car.trackState.distance;
|
|
27
|
-
car.raceDistance = getPitBoxRaceDistance(sim, stop, {
|
|
28
|
-
...box,
|
|
29
|
-
distanceAlongLane: box.queueDistanceAlongLane ?? box.distanceAlongLane,
|
|
30
|
-
});
|
|
14
|
+
holdPitCarAtBox(sim, car, box, { queue: true });
|
|
31
15
|
return true;
|
|
32
16
|
}
|
|
33
17
|
|
|
@@ -9,9 +9,6 @@ import {
|
|
|
9
9
|
sampleRouteInto,
|
|
10
10
|
} from './pitRouting.js';
|
|
11
11
|
import { syncPitCarKinematics } from './pitKinematics.js';
|
|
12
|
-
import { completePitPenaltyService } from './pitPenaltyService.js';
|
|
13
|
-
import { completePitService } from './pitTireService.js';
|
|
14
|
-
import { getPitBoxRaceDistance, getPitStopBox } from './pitOccupancy.js';
|
|
15
12
|
import {
|
|
16
13
|
PIT_BOX_STOP_SPEED,
|
|
17
14
|
PIT_ENTRY_BOX_CAPTURE_DISTANCE,
|
|
@@ -137,36 +134,4 @@ export function applyPitRoutePosition(sim, car, delta) {
|
|
|
137
134
|
return remainingAfter <= PIT_ROUTE_FINISH_DISTANCE;
|
|
138
135
|
}
|
|
139
136
|
|
|
140
|
-
export
|
|
141
|
-
const stop = car.pitStop;
|
|
142
|
-
const box = getPitStopBox(sim, stop);
|
|
143
|
-
if (!box) return true;
|
|
144
|
-
if (stop.phase === 'penalty') {
|
|
145
|
-
stop.penaltyServiceRemaining = Math.max(0, (stop.penaltyServiceRemaining ?? 0) - delta);
|
|
146
|
-
stop.serviceRemaining = stop.penaltyServiceRemaining;
|
|
147
|
-
} else {
|
|
148
|
-
stop.serviceRemaining = Math.max(0, (stop.serviceRemaining ?? 0) - delta);
|
|
149
|
-
}
|
|
150
|
-
car.previousX = car.x;
|
|
151
|
-
car.previousY = car.y;
|
|
152
|
-
car.previousHeading = car.heading;
|
|
153
|
-
car.x = box.center.x;
|
|
154
|
-
car.y = box.center.y;
|
|
155
|
-
car.heading = sim.track.pitLane.mainLane.heading;
|
|
156
|
-
car.speed = 0;
|
|
157
|
-
car.throttle = 0;
|
|
158
|
-
car.brake = 1;
|
|
159
|
-
car.steeringAngle = 0;
|
|
160
|
-
car.yawRate = 0;
|
|
161
|
-
car.turnRadius = Infinity;
|
|
162
|
-
syncPitCarKinematics(car, { physicsMode: sim.physicsMode });
|
|
163
|
-
applyWheelSurfaceState(car, sim.track);
|
|
164
|
-
car.progress = car.trackState.distance;
|
|
165
|
-
car.raceDistance = getPitBoxRaceDistance(sim, stop, box);
|
|
166
|
-
if (stop.phase === 'penalty' && stop.penaltyServiceRemaining <= 0) {
|
|
167
|
-
completePitPenaltyService(sim, car);
|
|
168
|
-
} else if (stop.serviceRemaining <= 0) {
|
|
169
|
-
completePitService(sim, car);
|
|
170
|
-
}
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
137
|
+
export { advancePitService } from './pitServiceProgress.js';
|
|
@@ -1,79 +1,14 @@
|
|
|
1
|
-
import { clamp
|
|
1
|
+
import { clamp } from '../simMath.js';
|
|
2
2
|
import { metersToSimUnits } from '../units.js';
|
|
3
3
|
import { nearestTrackState, offsetTrackPoint, pointAt } from '../track/trackModel.js';
|
|
4
|
+
import { PIT_ENTRY_APPROACH_DISTANCE } from './pitServiceConstants.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
export { clonePitLaneModel } from '../track/pitLaneModel.js';
|
|
7
|
+
export { shiftPreviousRenderPose } from '../vehicle/vehicleKinematics.js';
|
|
8
|
+
export { pointDistance } from './pitServiceConstants.js';
|
|
6
9
|
|
|
7
|
-
function clonePointLike(point) {
|
|
8
|
-
if (!point) return point;
|
|
9
|
-
return { ...point };
|
|
10
|
-
}
|
|
11
10
|
|
|
12
|
-
function clonePointArray(points) {
|
|
13
|
-
return Array.isArray(points) ? points.map(clonePointLike) : points;
|
|
14
|
-
}
|
|
15
11
|
|
|
16
|
-
export function clonePitLaneModel(pitLane) {
|
|
17
|
-
if (!pitLane) return pitLane;
|
|
18
|
-
return {
|
|
19
|
-
...pitLane,
|
|
20
|
-
entry: pitLane.entry ? {
|
|
21
|
-
...pitLane.entry,
|
|
22
|
-
trackPoint: clonePointLike(pitLane.entry.trackPoint),
|
|
23
|
-
edgePoint: clonePointLike(pitLane.entry.edgePoint),
|
|
24
|
-
trackConnectPoint: clonePointLike(pitLane.entry.trackConnectPoint),
|
|
25
|
-
lanePoint: clonePointLike(pitLane.entry.lanePoint),
|
|
26
|
-
roadCenterline: clonePointArray(pitLane.entry.roadCenterline),
|
|
27
|
-
connector: clonePointArray(pitLane.entry.connector),
|
|
28
|
-
} : pitLane.entry,
|
|
29
|
-
exit: pitLane.exit ? {
|
|
30
|
-
...pitLane.exit,
|
|
31
|
-
trackPoint: clonePointLike(pitLane.exit.trackPoint),
|
|
32
|
-
edgePoint: clonePointLike(pitLane.exit.edgePoint),
|
|
33
|
-
trackConnectPoint: clonePointLike(pitLane.exit.trackConnectPoint),
|
|
34
|
-
lanePoint: clonePointLike(pitLane.exit.lanePoint),
|
|
35
|
-
roadCenterline: clonePointArray(pitLane.exit.roadCenterline),
|
|
36
|
-
connector: clonePointArray(pitLane.exit.connector),
|
|
37
|
-
} : pitLane.exit,
|
|
38
|
-
mainLane: pitLane.mainLane ? {
|
|
39
|
-
...pitLane.mainLane,
|
|
40
|
-
start: clonePointLike(pitLane.mainLane.start),
|
|
41
|
-
end: clonePointLike(pitLane.mainLane.end),
|
|
42
|
-
points: clonePointArray(pitLane.mainLane.points),
|
|
43
|
-
} : pitLane.mainLane,
|
|
44
|
-
workingLane: pitLane.workingLane ? {
|
|
45
|
-
...pitLane.workingLane,
|
|
46
|
-
start: clonePointLike(pitLane.workingLane.start),
|
|
47
|
-
end: clonePointLike(pitLane.workingLane.end),
|
|
48
|
-
points: clonePointArray(pitLane.workingLane.points),
|
|
49
|
-
} : pitLane.workingLane,
|
|
50
|
-
fastLane: pitLane.fastLane ? { ...pitLane.fastLane } : pitLane.fastLane,
|
|
51
|
-
serviceNormal: clonePointLike(pitLane.serviceNormal),
|
|
52
|
-
boxes: Array.isArray(pitLane.boxes)
|
|
53
|
-
? pitLane.boxes.map((box) => ({
|
|
54
|
-
...box,
|
|
55
|
-
laneTarget: clonePointLike(box.laneTarget),
|
|
56
|
-
center: clonePointLike(box.center),
|
|
57
|
-
corners: clonePointArray(box.corners),
|
|
58
|
-
}))
|
|
59
|
-
: pitLane.boxes,
|
|
60
|
-
serviceAreas: Array.isArray(pitLane.serviceAreas)
|
|
61
|
-
? pitLane.serviceAreas.map((area) => ({
|
|
62
|
-
...area,
|
|
63
|
-
laneTarget: clonePointLike(area.laneTarget),
|
|
64
|
-
center: clonePointLike(area.center),
|
|
65
|
-
queuePoint: clonePointLike(area.queuePoint),
|
|
66
|
-
corners: clonePointArray(area.corners),
|
|
67
|
-
queueCorners: clonePointArray(area.queueCorners),
|
|
68
|
-
garageBoxIds: [...(area.garageBoxIds ?? [])],
|
|
69
|
-
pitCrew: area.pitCrew ? { ...area.pitCrew } : area.pitCrew,
|
|
70
|
-
}))
|
|
71
|
-
: pitLane.serviceAreas,
|
|
72
|
-
teams: Array.isArray(pitLane.teams)
|
|
73
|
-
? pitLane.teams.map((team) => ({ ...team, boxIds: [...(team.boxIds ?? [])], pitCrew: team.pitCrew ? { ...team.pitCrew } : team.pitCrew }))
|
|
74
|
-
: pitLane.teams,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
12
|
|
|
78
13
|
export function routePoint(point, heading = point?.heading, options = {}) {
|
|
79
14
|
if (!point) return null;
|
|
@@ -114,18 +49,7 @@ function sameRoutePoint(first, second) {
|
|
|
114
49
|
return first && second && Math.hypot(first.x - second.x, first.y - second.y) < 0.001;
|
|
115
50
|
}
|
|
116
51
|
|
|
117
|
-
export function shiftPreviousRenderPose(car, dx, dy, dheading = 0) {
|
|
118
|
-
car.previousX = Number.isFinite(car.previousX) ? car.previousX + dx : car.x + dx;
|
|
119
|
-
car.previousY = Number.isFinite(car.previousY) ? car.previousY + dy : car.y + dy;
|
|
120
|
-
car.previousHeading = normalizeAngle(
|
|
121
|
-
(Number.isFinite(car.previousHeading) ? car.previousHeading : car.heading) + dheading,
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
52
|
|
|
125
|
-
export function pointDistance(first, second) {
|
|
126
|
-
if (!first || !second) return Infinity;
|
|
127
|
-
return Math.hypot(first.x - second.x, first.y - second.y);
|
|
128
|
-
}
|
|
129
53
|
|
|
130
54
|
export function createRoute(points) {
|
|
131
55
|
const routePoints = [];
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { normalizePitCrewStats } from './pitState.js';
|
|
3
|
-
import { beginPitPenaltyService } from './pitPenaltyService.js';
|
|
4
|
-
import { beginTireService } from './pitTireService.js';
|
|
5
|
-
import { syncPitCarKinematics } from './pitKinematics.js';
|
|
6
|
-
import { getPitBoxRaceDistance } from './pitOccupancy.js';
|
|
7
|
-
|
|
8
|
-
export { normalizePitCrewStats };
|
|
1
|
+
export { normalizePitCrewStats } from './pitState.js';
|
|
9
2
|
export {
|
|
10
3
|
getPitBoxRaceDistance,
|
|
11
4
|
getPitStopBox,
|
|
@@ -17,27 +10,5 @@ export { beginPitQueue, releasePitQueue } from './pitQueue.js';
|
|
|
17
10
|
export { calculatePitServiceProfile } from './pitServiceProfile.js';
|
|
18
11
|
export { beginPitPenaltyService, completePitPenaltyService, getPitServicePenalties } from './pitPenaltyService.js';
|
|
19
12
|
export { beginTireService, completePitService, finishPitExit } from './pitTireService.js';
|
|
20
|
-
export {
|
|
21
|
-
|
|
22
|
-
export function beginPitService(sim, car, box) {
|
|
23
|
-
const stop = car.pitStop;
|
|
24
|
-
stop.status = 'servicing';
|
|
25
|
-
stop.route = null;
|
|
26
|
-
stop.routeProgress = 0;
|
|
27
|
-
car.x = box.center.x;
|
|
28
|
-
car.y = box.center.y;
|
|
29
|
-
car.heading = sim.track.pitLane.mainLane.heading;
|
|
30
|
-
car.speed = 0;
|
|
31
|
-
car.throttle = 0;
|
|
32
|
-
car.brake = 1;
|
|
33
|
-
car.steeringAngle = 0;
|
|
34
|
-
car.yawRate = 0;
|
|
35
|
-
car.turnRadius = Infinity;
|
|
36
|
-
syncPitCarKinematics(car, { physicsMode: sim.physicsMode });
|
|
37
|
-
applyWheelSurfaceState(car, sim.track);
|
|
38
|
-
car.progress = car.trackState.distance;
|
|
39
|
-
car.raceDistance = getPitBoxRaceDistance(sim, stop, box);
|
|
40
|
-
|
|
41
|
-
if (beginPitPenaltyService(sim, car)) return;
|
|
42
|
-
beginTireService(sim, car);
|
|
43
|
-
}
|
|
13
|
+
export { beginPitService, advancePitService } from './pitServiceProgress.js';
|
|
14
|
+
export { applyPitRoutePosition } from './pitRouteMovement.js';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { kphToSimSpeed, metersToSimUnits } from '../units.js';
|
|
2
2
|
import { VEHICLE_LIMITS } from '../vehicle/vehiclePhysics.js';
|
|
3
3
|
|
|
4
|
+
export const PIT_ENTRY_APPROACH_DISTANCE = metersToSimUnits(250);
|
|
4
5
|
export const PIT_ROUTE_FINISH_DISTANCE = metersToSimUnits(8.5);
|
|
5
6
|
export const PIT_QUEUE_RELEASE_FINISH_DISTANCE = metersToSimUnits(4);
|
|
6
7
|
export const PIT_QUEUE_CAPTURE_DISTANCE = metersToSimUnits(2.5);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { beginPitPenaltyService, completePitPenaltyService } from './pitPenaltyService.js';
|
|
2
|
+
import { beginTireService, completePitService } from './pitTireService.js';
|
|
3
|
+
import { getPitStopBox } from './pitOccupancy.js';
|
|
4
|
+
import { holdPitCarAtBox } from './pitCarPlacement.js';
|
|
5
|
+
|
|
6
|
+
export function beginPitService(sim, car, box) {
|
|
7
|
+
const stop = car.pitStop;
|
|
8
|
+
stop.status = 'servicing';
|
|
9
|
+
stop.route = null;
|
|
10
|
+
stop.routeProgress = 0;
|
|
11
|
+
holdPitCarAtBox(sim, car, box);
|
|
12
|
+
|
|
13
|
+
if (beginPitPenaltyService(sim, car)) return;
|
|
14
|
+
beginTireService(sim, car);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function advancePitService(sim, car, delta) {
|
|
18
|
+
const stop = car.pitStop;
|
|
19
|
+
const box = getPitStopBox(sim, stop);
|
|
20
|
+
if (!box) return true;
|
|
21
|
+
if (stop.phase === 'penalty') {
|
|
22
|
+
stop.penaltyServiceRemaining = Math.max(0, (stop.penaltyServiceRemaining ?? 0) - delta);
|
|
23
|
+
stop.serviceRemaining = stop.penaltyServiceRemaining;
|
|
24
|
+
} else {
|
|
25
|
+
stop.serviceRemaining = Math.max(0, (stop.serviceRemaining ?? 0) - delta);
|
|
26
|
+
}
|
|
27
|
+
holdPitCarAtBox(sim, car, box, { updatePreviousPose: true });
|
|
28
|
+
if (stop.phase === 'penalty' && stop.penaltyServiceRemaining <= 0) {
|
|
29
|
+
completePitPenaltyService(sim, car);
|
|
30
|
+
} else if (stop.serviceRemaining <= 0) {
|
|
31
|
+
completePitService(sim, car);
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { finiteOrNull } from '../
|
|
1
|
+
import { finiteOrNull } from '../simMath.js';
|
|
2
|
+
import { normalizePitIntent, PIT_INTENT_NONE } from './pitIntent.js';
|
|
2
3
|
|
|
3
4
|
export function pitLaneStatusSnapshot(raceControl, pitLane, pitStops) {
|
|
4
5
|
const enabled = Boolean(pitLane?.enabled && pitStops?.enabled);
|
|
@@ -13,7 +14,7 @@ export function pitLaneStatusSnapshot(raceControl, pitLane, pitStops) {
|
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
export function serializePitStop(pitStop
|
|
17
|
+
export function serializePitStop(pitStop) {
|
|
17
18
|
if (!pitStop) return null;
|
|
18
19
|
return {
|
|
19
20
|
status: pitStop.status,
|
|
@@ -34,7 +35,10 @@ export function serializePitStop(pitStop, normalizePitIntent, PIT_INTENT_NONE) {
|
|
|
34
35
|
penaltyServiceTotalSeconds: finiteOrNull(pitStop.penaltyServiceTotal),
|
|
35
36
|
servingPenaltyIds: [...(pitStop.servingPenaltyIds ?? [])],
|
|
36
37
|
targetTire: pitStop.targetTire ?? null,
|
|
37
|
-
serviceProfile: pitStop.serviceProfile ? {
|
|
38
|
+
serviceProfile: pitStop.serviceProfile ? {
|
|
39
|
+
...pitStop.serviceProfile,
|
|
40
|
+
...(pitStop.serviceProfile.pitCrew ? { pitCrew: { ...pitStop.serviceProfile.pitCrew } } : {}),
|
|
41
|
+
} : null,
|
|
38
42
|
};
|
|
39
43
|
}
|
|
40
44
|
|
|
@@ -47,7 +51,7 @@ export function serializeRenderPitStop(pitStop) {
|
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
53
|
|
|
50
|
-
export function serializeObservationPitStop(pitStop
|
|
54
|
+
export function serializeObservationPitStop(pitStop) {
|
|
51
55
|
if (!pitStop) return null;
|
|
52
56
|
return {
|
|
53
57
|
status: pitStop.status,
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { metersToSimUnits } from '../units.js';
|
|
2
1
|
import { firstDifferentCompound } from './pitIntent.js';
|
|
3
|
-
|
|
4
|
-
const PIT_ENTRY_APPROACH_DISTANCE = metersToSimUnits(250);
|
|
2
|
+
import { PIT_ENTRY_APPROACH_DISTANCE } from './pitServiceConstants.js';
|
|
5
3
|
|
|
6
4
|
export function normalizePitCrewStats(value) {
|
|
7
5
|
const source = value && typeof value === 'object' ? value : {};
|
|
@@ -73,7 +71,6 @@ export function initializePitStops({ cars, pitLane, pitStops, totalLaps, trackLe
|
|
|
73
71
|
|
|
74
72
|
cars.forEach((car, index) => {
|
|
75
73
|
const stopLapBase = trackLength * (1 + (index % pitWindowLapCount));
|
|
76
|
-
const trainPosition = Math.floor(index / pitWindowLapCount);
|
|
77
74
|
const teamIndex = Math.floor(index / boxesPerTeam);
|
|
78
75
|
const teamBoxIndex = index % boxesPerTeam;
|
|
79
76
|
const garageBoxIndex = Math.min(pitLane.boxes.length - 1, teamIndex * boxesPerTeam + teamBoxIndex);
|
|
@@ -94,7 +91,6 @@ export function initializePitStops({ cars, pitLane, pitStops, totalLaps, trackLe
|
|
|
94
91
|
entryRaceDistance: stopLapBase + pitLane.entry.distanceFromStart,
|
|
95
92
|
plannedRaceDistance: stopLapBase + pitLane.entry.distanceFromStart -
|
|
96
93
|
PIT_ENTRY_APPROACH_DISTANCE,
|
|
97
|
-
trainPosition,
|
|
98
94
|
lapBase: stopLapBase,
|
|
99
95
|
serviceRemaining: 0,
|
|
100
96
|
penaltyServiceRemaining: 0,
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { clamp } from '../simMath.js';
|
|
2
2
|
import { simUnitsToMeters } from '../units.js';
|
|
3
3
|
import { isRaceDnf, raceDnfCars } from './retirements.js';
|
|
4
|
-
|
|
5
|
-
function getPenaltyStats(statsByDriver, driverId) {
|
|
6
|
-
return statsByDriver.get(driverId) ?? {
|
|
7
|
-
seconds: 0,
|
|
8
|
-
positionDrop: 0,
|
|
9
|
-
disqualified: false,
|
|
10
|
-
};
|
|
11
|
-
}
|
|
4
|
+
import { getPenaltyStats } from '../rules/penaltyStats.js';
|
|
12
5
|
|
|
13
6
|
export function applyOutstandingServicePenalties(sim, applyUnservedServicePenalty) {
|
|
14
7
|
sim.penalties.forEach((penalty) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { clearCurrentDrsState } from '../timing/drsState.js';
|
|
1
2
|
import { isRaceDnf } from './retirements.js';
|
|
2
3
|
|
|
3
4
|
export function evaluateRaceFinishForSimulation(sim, orderedCars = sim.orderedCars()) {
|
|
@@ -23,10 +24,7 @@ export function evaluateRaceFinishForSimulation(sim, orderedCars = sim.orderedCa
|
|
|
23
24
|
car.classifiedRank = car.finishRank;
|
|
24
25
|
sim.raceControl.finishOrder.push(car.id);
|
|
25
26
|
if (!sim.raceControl.winnerId) sim.raceControl.winnerId = car.id;
|
|
26
|
-
car
|
|
27
|
-
car.drsEligible = false;
|
|
28
|
-
car.drsZoneId = null;
|
|
29
|
-
car.drsZoneEnabled = false;
|
|
27
|
+
clearCurrentDrsState(car);
|
|
30
28
|
car.canAttack = false;
|
|
31
29
|
sim.events.unshift({
|
|
32
30
|
type: 'car-finish',
|
|
@@ -67,10 +65,7 @@ export function evaluateRaceFinishForSimulation(sim, orderedCars = sim.orderedCa
|
|
|
67
65
|
const classified = classification.find((entry) => entry.id === car.id);
|
|
68
66
|
car.classifiedRank = classified?.rank ?? null;
|
|
69
67
|
car.desiredOffset = 0;
|
|
70
|
-
car
|
|
71
|
-
car.drsEligible = false;
|
|
72
|
-
car.drsZoneId = null;
|
|
73
|
-
car.drsZoneEnabled = false;
|
|
68
|
+
clearCurrentDrsState(car);
|
|
74
69
|
car.canAttack = false;
|
|
75
70
|
});
|
|
76
71
|
sim.events.unshift({
|
|
@@ -47,7 +47,7 @@ function collectLiveRaceOrderedCars(orderedCars, scratch) {
|
|
|
47
47
|
return physicalCars;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
function sortPhysicalCarsInTrackOrder(
|
|
50
|
+
function sortPhysicalCarsInTrackOrder(physicalCars) {
|
|
51
51
|
physicalCars.sort((a, b) => {
|
|
52
52
|
const progressDelta = (b.progress ?? b.raceDistance ?? 0) - (a.progress ?? a.raceDistance ?? 0);
|
|
53
53
|
if (progressDelta !== 0) return progressDelta;
|
|
@@ -121,7 +121,7 @@ function buildDrsReferenceArrayForSimulation(sim, orderedCars = orderedCarsForSi
|
|
|
121
121
|
sim.runtimeBenchmarkStats.drsReferenceOrderedFastPathCalls = (sim.runtimeBenchmarkStats.drsReferenceOrderedFastPathCalls ?? 0) + 1;
|
|
122
122
|
}
|
|
123
123
|
} else {
|
|
124
|
-
sortPhysicalCarsInTrackOrder(
|
|
124
|
+
sortPhysicalCarsInTrackOrder(physicalCars);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
const trackLength = sim.track.length;
|
|
@@ -219,17 +219,6 @@ export function driverRaceContextForSimulation(sim, orderedCars = orderedCarsFor
|
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
export function buildDrsReferenceByCarId(sim, orderedCars = orderedCarsForSimulation(sim)) {
|
|
223
|
-
const referencesByIndex = buildDrsReferenceArrayForSimulation(sim, orderedCars);
|
|
224
|
-
const references = new Map();
|
|
225
|
-
for (let index = 0; index < orderedCars.length; index += 1) {
|
|
226
|
-
const car = orderedCars[index];
|
|
227
|
-
if (!affectsRaceOrder(car) || isRaceDnf(car)) continue;
|
|
228
|
-
references.set(car.id, referencesByIndex[car.index] ?? null);
|
|
229
|
-
}
|
|
230
|
-
return references;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
222
|
export function assignDrsReferenceCarsForSimulation(sim, orderedCars = orderedCarsForSimulation(sim)) {
|
|
234
223
|
return buildDrsReferenceArrayForSimulation(sim, orderedCars);
|
|
235
224
|
}
|