@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
|
@@ -4,13 +4,13 @@ import { metersToSimUnits, simUnitsToMeters } from '../../simulation/units.js';
|
|
|
4
4
|
import {
|
|
5
5
|
ANALYTIC_TRACK_RAY_MAX_CURVATURE,
|
|
6
6
|
DRIVER_RAY_REFINE_STEPS,
|
|
7
|
-
PIT_CONNECTOR_RAY_FALLBACK_METERS,
|
|
8
7
|
TRACK_RAY_REFINE_STEPS,
|
|
9
8
|
TRACK_RAY_STEP_METERS,
|
|
10
9
|
} from './rayDefaults.js';
|
|
11
10
|
import { canUseIndexedRecoveryRayApproximation } from './rayGuards.js';
|
|
12
11
|
import { pointOnRay } from './rayGeometry.js';
|
|
13
12
|
import { findIndexedTrackBandBoundaries } from './indexedRayBands.js';
|
|
13
|
+
import { isNearPitConnector } from './pitConnectorProximity.js';
|
|
14
14
|
|
|
15
15
|
export function requestedSurfaceChannels(channels = []) {
|
|
16
16
|
const requested = [];
|
|
@@ -55,7 +55,7 @@ export function estimateSurfaceHits(
|
|
|
55
55
|
|
|
56
56
|
const originState = context?.precision === precision
|
|
57
57
|
? context.originState
|
|
58
|
-
: nearestRayTrackState(snapshot.track, car, origin, car.progress
|
|
58
|
+
: nearestRayTrackState(snapshot.track, car, origin, car.progress);
|
|
59
59
|
writeSurfaceHitsAtOrigin(hits, requested, originState);
|
|
60
60
|
const indexedHits = estimateIndexedSurfaceHits({
|
|
61
61
|
car,
|
|
@@ -65,7 +65,6 @@ export function estimateSurfaceHits(
|
|
|
65
65
|
vector,
|
|
66
66
|
requested,
|
|
67
67
|
originState,
|
|
68
|
-
precision,
|
|
69
68
|
sharedRayQuery,
|
|
70
69
|
hits,
|
|
71
70
|
});
|
|
@@ -90,7 +89,7 @@ export function estimateSurfaceHits(
|
|
|
90
89
|
let previousState = null;
|
|
91
90
|
|
|
92
91
|
for (let distance = 0; distance <= maxDistance; distance += step) {
|
|
93
|
-
const state = nearestRayTrackState(snapshot.track, car, pointOnRay(origin, vector, distance), car.progress
|
|
92
|
+
const state = nearestRayTrackState(snapshot.track, car, pointOnRay(origin, vector, distance), car.progress);
|
|
94
93
|
if (pendingKerb && matchesSurfaceChannel('kerb', state)) {
|
|
95
94
|
const hitDistance = previousState
|
|
96
95
|
? refineSurfaceTransition(snapshot.track, car, origin, vector, car.progress, previousDistance, distance, 'kerb', refineStepsForPrecision(precision))
|
|
@@ -187,7 +186,7 @@ function estimateAnalyticSurfaceHits({ car, track, ray, vector, requested, origi
|
|
|
187
186
|
return hits;
|
|
188
187
|
}
|
|
189
188
|
|
|
190
|
-
function estimateIndexedSurfaceHits({ car, track, ray, origin, vector, requested, originState,
|
|
189
|
+
function estimateIndexedSurfaceHits({ car, track, ray, origin, vector, requested, originState, sharedRayQuery, hits }) {
|
|
191
190
|
if (!originState || car.inPitLane || originState.inPitLane) return null;
|
|
192
191
|
if (!usesMainTrackOnlyRays(car) && isNearPitConnector(track, originState)) return null;
|
|
193
192
|
|
|
@@ -224,23 +223,9 @@ function estimateIndexedSurfaceHits({ car, track, ray, origin, vector, requested
|
|
|
224
223
|
writeSurfaceMiss(hits[channel], ray.lengthMeters);
|
|
225
224
|
continue;
|
|
226
225
|
}
|
|
227
|
-
const hitDistance = usesMainTrackOnlyRays(car) || refineStepsForPrecision(precision) <= 0 || precision === 'debug'
|
|
228
|
-
? boundaryDistance
|
|
229
|
-
: sampledIndexedSurfaceDistance({
|
|
230
|
-
track,
|
|
231
|
-
car,
|
|
232
|
-
origin,
|
|
233
|
-
vector,
|
|
234
|
-
progressHint: car.progress,
|
|
235
|
-
distance: boundaryDistance,
|
|
236
|
-
maxDistance: metersToSimUnits(ray.lengthMeters),
|
|
237
|
-
channel,
|
|
238
|
-
precision,
|
|
239
|
-
});
|
|
240
|
-
if (hitDistance == null) return null;
|
|
241
226
|
writeSurfaceHit(
|
|
242
227
|
hits[channel],
|
|
243
|
-
simUnitsToMeters(
|
|
228
|
+
simUnitsToMeters(boundaryDistance),
|
|
244
229
|
channel === 'kerb'
|
|
245
230
|
? 'kerb'
|
|
246
231
|
: surfaceBeyondKerb(track, originState.signedOffset ?? 0, lateral, metersToSimUnits(ray.lengthMeters)),
|
|
@@ -250,28 +235,6 @@ function estimateIndexedSurfaceHits({ car, track, ray, origin, vector, requested
|
|
|
250
235
|
return hits;
|
|
251
236
|
}
|
|
252
237
|
|
|
253
|
-
function sampledIndexedSurfaceDistance({
|
|
254
|
-
track,
|
|
255
|
-
car,
|
|
256
|
-
origin,
|
|
257
|
-
vector,
|
|
258
|
-
progressHint,
|
|
259
|
-
distance,
|
|
260
|
-
maxDistance,
|
|
261
|
-
channel,
|
|
262
|
-
precision,
|
|
263
|
-
}) {
|
|
264
|
-
const step = metersToSimUnits(TRACK_RAY_STEP_METERS);
|
|
265
|
-
const firstIndex = Math.max(0, Math.floor(Math.max(0, distance - step * 1.5) / step));
|
|
266
|
-
const lastIndex = Math.ceil(Math.min(maxDistance, distance + step * 8) / step);
|
|
267
|
-
for (let index = firstIndex; index <= lastIndex; index += 1) {
|
|
268
|
-
const sampleDistance = Math.min(maxDistance, index * step);
|
|
269
|
-
const state = nearestRayTrackState(track, car, pointOnRay(origin, vector, sampleDistance), progressHint, precision);
|
|
270
|
-
if (matchesSurfaceChannel(channel, state)) return sampleDistance;
|
|
271
|
-
}
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
238
|
function usesMainTrackOnlyRays(car) {
|
|
276
239
|
return car?.interaction?.profile === 'batch-training';
|
|
277
240
|
}
|
|
@@ -320,24 +283,6 @@ function surfaceBeyondKerb(track, offset, lateral, maxDistance) {
|
|
|
320
283
|
return hitAbs <= gravelOuter ? 'gravel' : 'grass';
|
|
321
284
|
}
|
|
322
285
|
|
|
323
|
-
function isNearPitConnector(track, state) {
|
|
324
|
-
const pitLane = track.pitLane;
|
|
325
|
-
if (!pitLane?.enabled || !Number.isFinite(state?.distance)) return false;
|
|
326
|
-
const window = metersToSimUnits(PIT_CONNECTOR_RAY_FALLBACK_METERS);
|
|
327
|
-
const entryDistance = pitLane.entry?.trackDistance ?? pitLane.entry?.distanceFromStart;
|
|
328
|
-
const exitDistance = pitLane.exit?.trackDistance ?? pitLane.exit?.distanceFromStart;
|
|
329
|
-
return wrappedTrackDistance(state.distance, entryDistance, track.length) <= window ||
|
|
330
|
-
wrappedTrackDistance(state.distance, exitDistance, track.length) <= window;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
function wrappedTrackDistance(first, second, totalLength) {
|
|
334
|
-
if (!Number.isFinite(first) || !Number.isFinite(second) || !Number.isFinite(totalLength) || totalLength <= 0) {
|
|
335
|
-
return Infinity;
|
|
336
|
-
}
|
|
337
|
-
const delta = Math.abs(first - second);
|
|
338
|
-
return Math.min(delta, totalLength - delta);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
286
|
function refineSurfaceTransition(
|
|
342
287
|
track,
|
|
343
288
|
car,
|
|
@@ -396,7 +341,7 @@ function canSampleRecoverySurface(track, originState, vector) {
|
|
|
396
341
|
return offset > 0 ? lateral < 0 : lateral > 0;
|
|
397
342
|
}
|
|
398
343
|
|
|
399
|
-
function nearestRayTrackState(track, car, point, progressHint
|
|
344
|
+
function nearestRayTrackState(track, car, point, progressHint) {
|
|
400
345
|
return nearestTrackState(track, point, progressHint, {
|
|
401
346
|
allowPitOverride: pitOverrideAllowedForCar(car),
|
|
402
347
|
});
|
|
@@ -6,13 +6,13 @@ import { metersToSimUnits, simUnitsToMeters } from '../../simulation/units.js';
|
|
|
6
6
|
import {
|
|
7
7
|
ANALYTIC_TRACK_RAY_MAX_CURVATURE,
|
|
8
8
|
DRIVER_RAY_REFINE_STEPS,
|
|
9
|
-
PIT_CONNECTOR_RAY_FALLBACK_METERS,
|
|
10
9
|
TRACK_RAY_REFINE_STEPS,
|
|
11
10
|
TRACK_RAY_STEP_METERS,
|
|
12
11
|
} from './rayDefaults.js';
|
|
13
12
|
import { canUseIndexedRecoveryRayApproximation } from './rayGuards.js';
|
|
14
13
|
import { degreesToRadians, getCarRayOrigin, getCarRayVector, pointOnRay } from './rayGeometry.js';
|
|
15
14
|
import { findIndexedTrackBandBoundaries } from './indexedRayBands.js';
|
|
15
|
+
import { isNearPitConnector } from './pitConnectorProximity.js';
|
|
16
16
|
|
|
17
17
|
const RAY_TRACK_STATE_REUSE_POSITION_TOLERANCE = metersToSimUnits(1);
|
|
18
18
|
const RAY_TRACK_STATE_REUSE_PROGRESS_TOLERANCE = metersToSimUnits(0.25);
|
|
@@ -25,7 +25,7 @@ export function createTrackRayContext(car, snapshot, origin, precision = 'debug'
|
|
|
25
25
|
const reusedOriginState = reusableRayOriginState(snapshot.track, car, origin);
|
|
26
26
|
return {
|
|
27
27
|
origin,
|
|
28
|
-
originState: reusedOriginState ?? nearestRayTrackState(snapshot.track, car, origin, car.progress
|
|
28
|
+
originState: reusedOriginState ?? nearestRayTrackState(snapshot.track, car, origin, car.progress),
|
|
29
29
|
precision,
|
|
30
30
|
};
|
|
31
31
|
}
|
|
@@ -48,7 +48,7 @@ export function estimateTrackHit(
|
|
|
48
48
|
const step = metersToSimUnits(TRACK_RAY_STEP_METERS);
|
|
49
49
|
const originState = context?.precision === precision
|
|
50
50
|
? context.originState
|
|
51
|
-
: nearestRayTrackState(snapshot.track, car, origin, car.progress
|
|
51
|
+
: nearestRayTrackState(snapshot.track, car, origin, car.progress);
|
|
52
52
|
const includePitLane = Boolean(car.inPitLane || car.pitLanePart || originState.inPitLane);
|
|
53
53
|
const indexedHit = estimateIndexedTrackHit({
|
|
54
54
|
car,
|
|
@@ -62,22 +62,9 @@ export function estimateTrackHit(
|
|
|
62
62
|
sharedRayQuery,
|
|
63
63
|
});
|
|
64
64
|
if (indexedHit) return indexedHit;
|
|
65
|
-
const directionalAnalyticHit = canUseDirectionalAnalyticTrackHit({ car, track: snapshot.track, originState, ray, includePitLane })
|
|
66
|
-
? estimateAnalyticMainTrackHit({
|
|
67
|
-
car,
|
|
68
|
-
track: snapshot.track,
|
|
69
|
-
origin,
|
|
70
|
-
originState,
|
|
71
|
-
ray,
|
|
72
|
-
lengthMeters,
|
|
73
|
-
includePitLane,
|
|
74
|
-
})
|
|
75
|
-
: null;
|
|
76
|
-
if (directionalAnalyticHit) return directionalAnalyticHit;
|
|
77
65
|
const analyticHit = estimateAnalyticMainTrackHit({
|
|
78
66
|
car,
|
|
79
67
|
track: snapshot.track,
|
|
80
|
-
origin,
|
|
81
68
|
originState,
|
|
82
69
|
ray,
|
|
83
70
|
lengthMeters,
|
|
@@ -88,7 +75,7 @@ export function estimateTrackHit(
|
|
|
88
75
|
let previousInside = null;
|
|
89
76
|
|
|
90
77
|
for (let distance = 0; distance <= maxDistance; distance += step) {
|
|
91
|
-
const state = nearestRayTrackState(snapshot.track, car, pointOnRay(origin, ray, distance), car.progress
|
|
78
|
+
const state = nearestRayTrackState(snapshot.track, car, pointOnRay(origin, ray, distance), car.progress);
|
|
92
79
|
const inside = isInsideTrackBorder(state, snapshot.track, includePitLane);
|
|
93
80
|
if (previousInside == null) {
|
|
94
81
|
previousInside = inside;
|
|
@@ -109,7 +96,6 @@ export function estimateTrackHit(
|
|
|
109
96
|
kind,
|
|
110
97
|
includePitLane,
|
|
111
98
|
refineStepsForPrecision(precision),
|
|
112
|
-
precision,
|
|
113
99
|
);
|
|
114
100
|
return {
|
|
115
101
|
hit: true,
|
|
@@ -132,7 +118,7 @@ export function createTrackMiss(lengthMeters) {
|
|
|
132
118
|
};
|
|
133
119
|
}
|
|
134
120
|
|
|
135
|
-
function estimateAnalyticMainTrackHit({ car, track,
|
|
121
|
+
function estimateAnalyticMainTrackHit({ car, track, originState, ray, lengthMeters, includePitLane }) {
|
|
136
122
|
if (includePitLane || (!usesMainTrackOnlyRays(car) && isNearPitConnector(track, originState))) return null;
|
|
137
123
|
if (!canUseIndexedRecoveryRayApproximation(track, originState)) return null;
|
|
138
124
|
if (Math.abs(originState.curvature ?? 0) > ANALYTIC_TRACK_RAY_MAX_CURVATURE) return null;
|
|
@@ -162,15 +148,6 @@ function estimateAnalyticMainTrackHit({ car, track, origin, originState, ray, le
|
|
|
162
148
|
};
|
|
163
149
|
}
|
|
164
150
|
|
|
165
|
-
function canUseDirectionalAnalyticTrackHit({ car, track, originState, ray, includePitLane }) {
|
|
166
|
-
if (includePitLane || (!usesMainTrackOnlyRays(car) && isNearPitConnector(track, originState))) return false;
|
|
167
|
-
if (!canUseIndexedRecoveryRayApproximation(track, originState)) return false;
|
|
168
|
-
if (Math.abs(originState.curvature ?? 0) > ANALYTIC_TRACK_RAY_MAX_CURVATURE) return false;
|
|
169
|
-
|
|
170
|
-
const lateral = ray.x * originState.normalX + ray.y * originState.normalY;
|
|
171
|
-
return Math.abs(lateral) >= 0.08;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
151
|
function estimateIndexedTrackHit({ car, track, origin, originState, ray, lengthMeters, includePitLane, precision, sharedRayQuery }) {
|
|
175
152
|
if (includePitLane || (!usesMainTrackOnlyRays(car) && isNearPitConnector(track, originState))) return null;
|
|
176
153
|
const trackHalfWidth = track.width / 2;
|
|
@@ -205,7 +182,6 @@ function estimateIndexedTrackHit({ car, track, origin, originState, ray, lengthM
|
|
|
205
182
|
kind,
|
|
206
183
|
includePitLane,
|
|
207
184
|
precision,
|
|
208
|
-
originInside: inside,
|
|
209
185
|
});
|
|
210
186
|
if (hitDistance == null) return null;
|
|
211
187
|
return {
|
|
@@ -219,24 +195,6 @@ function usesMainTrackOnlyRays(car) {
|
|
|
219
195
|
return car?.interaction?.profile === 'batch-training';
|
|
220
196
|
}
|
|
221
197
|
|
|
222
|
-
function isNearPitConnector(track, state) {
|
|
223
|
-
const pitLane = track.pitLane;
|
|
224
|
-
if (!pitLane?.enabled || !Number.isFinite(state?.distance)) return false;
|
|
225
|
-
const window = metersToSimUnits(PIT_CONNECTOR_RAY_FALLBACK_METERS);
|
|
226
|
-
const entryDistance = pitLane.entry?.trackDistance ?? pitLane.entry?.distanceFromStart;
|
|
227
|
-
const exitDistance = pitLane.exit?.trackDistance ?? pitLane.exit?.distanceFromStart;
|
|
228
|
-
return wrappedTrackDistance(state.distance, entryDistance, track.length) <= window ||
|
|
229
|
-
wrappedTrackDistance(state.distance, exitDistance, track.length) <= window;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function wrappedTrackDistance(first, second, totalLength) {
|
|
233
|
-
if (!Number.isFinite(first) || !Number.isFinite(second) || !Number.isFinite(totalLength) || totalLength <= 0) {
|
|
234
|
-
return Infinity;
|
|
235
|
-
}
|
|
236
|
-
const delta = Math.abs(first - second);
|
|
237
|
-
return Math.min(delta, totalLength - delta);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
198
|
function estimateLocalTrackHit(car, snapshot, angleDegrees, lengthMeters) {
|
|
241
199
|
const trackHalfWidthMeters = simUnitsToMeters(snapshot.track.width / 2);
|
|
242
200
|
const offsetMeters = simUnitsToMeters(car.signedOffset ?? 0);
|
|
@@ -277,13 +235,12 @@ function refineTrackTransitionDistance(
|
|
|
277
235
|
kind,
|
|
278
236
|
includePitLane = true,
|
|
279
237
|
refineSteps = TRACK_RAY_REFINE_STEPS,
|
|
280
|
-
precision = 'debug',
|
|
281
238
|
) {
|
|
282
239
|
let low = lowDistance;
|
|
283
240
|
let high = highDistance;
|
|
284
241
|
for (let index = 0; index < refineSteps; index += 1) {
|
|
285
242
|
const middle = (low + high) / 2;
|
|
286
|
-
const state = nearestRayTrackState(track, car, pointOnRay(origin, ray, middle), progressHint
|
|
243
|
+
const state = nearestRayTrackState(track, car, pointOnRay(origin, ray, middle), progressHint);
|
|
287
244
|
const inside = isInsideTrackBorder(state, track, includePitLane);
|
|
288
245
|
if (kind === 'entry') {
|
|
289
246
|
if (inside) high = middle;
|
|
@@ -297,7 +254,7 @@ function refineTrackTransitionDistance(
|
|
|
297
254
|
return high;
|
|
298
255
|
}
|
|
299
256
|
|
|
300
|
-
function nearestRayTrackState(track, car, point, progressHint
|
|
257
|
+
function nearestRayTrackState(track, car, point, progressHint) {
|
|
301
258
|
return nearestTrackState(track, point, progressHint, {
|
|
302
259
|
allowPitOverride: pitOverrideAllowedForCar(car),
|
|
303
260
|
});
|
|
@@ -440,7 +397,6 @@ function validatedIndexedTransitionDistance({
|
|
|
440
397
|
kind,
|
|
441
398
|
includePitLane,
|
|
442
399
|
precision = 'driver',
|
|
443
|
-
originInside = kind === 'exit',
|
|
444
400
|
}) {
|
|
445
401
|
const step = metersToSimUnits(TRACK_RAY_STEP_METERS);
|
|
446
402
|
const refineSteps = refineStepsForPrecision(precision);
|
|
@@ -460,7 +416,6 @@ function validatedIndexedTransitionDistance({
|
|
|
460
416
|
? !previousInside && inside
|
|
461
417
|
: previousInside && !inside;
|
|
462
418
|
if (matched) {
|
|
463
|
-
if (refineSteps <= 0) return distance;
|
|
464
419
|
return refineValidatedTransitionDistance(
|
|
465
420
|
track,
|
|
466
421
|
car,
|
|
@@ -479,34 +434,6 @@ function validatedIndexedTransitionDistance({
|
|
|
479
434
|
return null;
|
|
480
435
|
}
|
|
481
436
|
|
|
482
|
-
function sampledIndexedTransitionDistance({
|
|
483
|
-
track,
|
|
484
|
-
car,
|
|
485
|
-
origin,
|
|
486
|
-
ray,
|
|
487
|
-
progressHint,
|
|
488
|
-
distance,
|
|
489
|
-
maxDistance,
|
|
490
|
-
kind,
|
|
491
|
-
includePitLane,
|
|
492
|
-
}) {
|
|
493
|
-
const step = metersToSimUnits(TRACK_RAY_STEP_METERS);
|
|
494
|
-
const firstIndex = Math.max(1, Math.floor(Math.max(0, distance - step * 1.5) / step));
|
|
495
|
-
const lastIndex = Math.ceil(Math.min(maxDistance, distance + step * 8) / step);
|
|
496
|
-
for (let index = firstIndex; index <= lastIndex; index += 1) {
|
|
497
|
-
const high = Math.min(maxDistance, index * step);
|
|
498
|
-
const low = Math.max(0, high - step);
|
|
499
|
-
if (high <= low) continue;
|
|
500
|
-
const previousInside = validatedInsideTrackBorder(track, car, origin, ray, low, progressHint, includePitLane);
|
|
501
|
-
const inside = validatedInsideTrackBorder(track, car, origin, ray, high, progressHint, includePitLane);
|
|
502
|
-
const matched = kind === 'entry'
|
|
503
|
-
? !previousInside && inside
|
|
504
|
-
: previousInside && !inside;
|
|
505
|
-
if (matched) return high;
|
|
506
|
-
}
|
|
507
|
-
return null;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
437
|
function refineValidatedTransitionDistance(track, car, origin, ray, progressHint, lowDistance, highDistance, kind, includePitLane, refineSteps) {
|
|
511
438
|
let low = lowDistance;
|
|
512
439
|
let high = highDistance;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createRaceSimulation, FIXED_STEP } from '../simulation/raceSimulation.js';
|
|
2
|
+
import { disableWarmupOptions, runWarmupWithGuard } from '../simulation/warmup/runtimeWarmup.js';
|
|
3
|
+
import { applyControlledRunoffResponse, initializeControlledPitIntentForSimulation } from './driverReset.js';
|
|
4
|
+
import { buildEnvironmentObservation } from './observations.js';
|
|
5
|
+
import { applyEnvironmentScenario } from './scenarios.js';
|
|
6
|
+
|
|
7
|
+
export function createSimulationWithEnvironmentScenario(options) {
|
|
8
|
+
runWarmupWithGuard({
|
|
9
|
+
options,
|
|
10
|
+
surface: 'environment',
|
|
11
|
+
execute: ({ warmup }) => {
|
|
12
|
+
const warmupSimulation = createRaceSimulation(disableWarmupOptions(options, warmup.surface));
|
|
13
|
+
initializeControlledPitIntentForSimulation(warmupSimulation, options);
|
|
14
|
+
applyEnvironmentScenario(warmupSimulation, options);
|
|
15
|
+
applyControlledRunoffResponse(warmupSimulation, options);
|
|
16
|
+
for (let index = 0; index < warmup.steps; index += 1) warmupSimulation.step(FIXED_STEP);
|
|
17
|
+
const warmupSnapshot = warmupSimulation.snapshotObservation?.() ?? warmupSimulation.snapshot();
|
|
18
|
+
buildEnvironmentObservation({
|
|
19
|
+
snapshot: warmupSnapshot,
|
|
20
|
+
options,
|
|
21
|
+
events: [],
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
const sim = createRaceSimulation(disableWarmupOptions(options, 'environment'));
|
|
26
|
+
initializeControlledPitIntentForSimulation(sim, options);
|
|
27
|
+
applyEnvironmentScenario(sim, options);
|
|
28
|
+
applyControlledRunoffResponse(sim, options);
|
|
29
|
+
return sim;
|
|
30
|
+
}
|
package/src/environment/specs.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { normalizeLookaheadMeters } from './observationOptions.js';
|
|
2
|
-
import { effectiveSensorOptions } from './
|
|
3
|
-
import { normalizeRayOptions } from './sensors.js';
|
|
4
|
-
|
|
5
|
-
const MODEL_RAY_SURFACE_CHANNELS = Object.freeze(['kerb', 'illegalSurface']);
|
|
2
|
+
import { effectiveSensorOptions } from './sensorOptions.js';
|
|
3
|
+
import { normalizeRayOptions } from './sensors/rayConfig.js';
|
|
4
|
+
import { buildObservationVectorSchema } from './observationSchema.js';
|
|
6
5
|
|
|
7
6
|
export function buildActionSpec(options) {
|
|
8
7
|
const compounds = Array.isArray(options.rules?.modules?.tireStrategy?.compounds) &&
|
|
@@ -119,7 +118,13 @@ export function buildObservationSpec(options) {
|
|
|
119
118
|
events: { type: 'array' },
|
|
120
119
|
},
|
|
121
120
|
vector: {
|
|
122
|
-
schema:
|
|
121
|
+
schema: buildObservationVectorSchema({
|
|
122
|
+
profile,
|
|
123
|
+
lookaheadCount: lookaheadMeters.length,
|
|
124
|
+
rayCount: rayOptions.enabled ? rayOptions.anglesDegrees.length : 0,
|
|
125
|
+
rayChannels: rayOptions.channels,
|
|
126
|
+
nearbyCount: nearbyOptions.enabled ? nearbyOptions.maxCars : 0,
|
|
127
|
+
}),
|
|
123
128
|
},
|
|
124
129
|
perDriver: buildPerDriverObservationSpecs(options, { rayOptions, nearbyOptions, lookaheadMeters, profile }),
|
|
125
130
|
};
|
|
@@ -136,11 +141,12 @@ function buildPerDriverObservationSpecs(options, { rayOptions, nearbyOptions, lo
|
|
|
136
141
|
nearbyCars: buildNearbyObjectSpec(sensors.nearbyCars),
|
|
137
142
|
},
|
|
138
143
|
vector: {
|
|
139
|
-
schema:
|
|
140
|
-
rayOptions: sensors.rays,
|
|
141
|
-
nearbyOptions: sensors.nearbyCars,
|
|
142
|
-
lookaheadMeters,
|
|
144
|
+
schema: buildObservationVectorSchema({
|
|
143
145
|
profile,
|
|
146
|
+
lookaheadCount: lookaheadMeters.length,
|
|
147
|
+
rayCount: sensors.rays.enabled ? sensors.rays.anglesDegrees.length : 0,
|
|
148
|
+
rayChannels: sensors.rays.channels,
|
|
149
|
+
nearbyCount: sensors.nearbyCars.enabled ? sensors.nearbyCars.maxCars : 0,
|
|
144
150
|
}),
|
|
145
151
|
},
|
|
146
152
|
}];
|
|
@@ -187,106 +193,6 @@ function buildNearbyObjectSpec(nearbyOptions) {
|
|
|
187
193
|
};
|
|
188
194
|
}
|
|
189
195
|
|
|
190
|
-
function buildVectorSchema({ rayOptions, nearbyOptions, lookaheadMeters, profile = 'default' }) {
|
|
191
|
-
const includePhysicalDriverSenses = profile === 'physical-driver';
|
|
192
|
-
const schema = [
|
|
193
|
-
{ name: 'self.speedKph', unit: 'kph', scale: 'fixed:400' },
|
|
194
|
-
{ name: 'self.speedMetersPerSecond', unit: 'm/s', scale: 'fixed:120' },
|
|
195
|
-
{ name: 'self.steeringAngleRadians', unit: 'rad', scale: 'fixed:pi' },
|
|
196
|
-
{ name: 'self.throttle', scale: '0..1' },
|
|
197
|
-
{ name: 'self.brake', scale: '0..1' },
|
|
198
|
-
{ name: 'self.lateralG', scale: 'fixed:8g' },
|
|
199
|
-
{ name: 'self.longitudinalG', scale: 'fixed:6g' },
|
|
200
|
-
{ name: 'self.gripUsage', scale: '0..2' },
|
|
201
|
-
{ name: 'self.slipAngleRadians', unit: 'rad', scale: 'fixed:pi' },
|
|
202
|
-
{ name: 'self.tractionLimited', scale: 'boolean' },
|
|
203
|
-
{ name: 'self.lapProgressRatio', scale: '0..1' },
|
|
204
|
-
{ name: 'self.trackOffsetMeters', unit: 'm', scale: 'fixed:meters' },
|
|
205
|
-
{ name: 'self.trackHeadingErrorRadians', unit: 'rad', scale: 'fixed:pi' },
|
|
206
|
-
{ name: 'self.onTrack', scale: 'boolean' },
|
|
207
|
-
{ name: 'self.inPitLane', scale: 'boolean' },
|
|
208
|
-
{ name: 'self.tireEnergy', scale: '0..100' },
|
|
209
|
-
{ name: 'self.pitIntent', scale: '0..2' },
|
|
210
|
-
{ name: 'self.pitStopActive', scale: 'boolean' },
|
|
211
|
-
{ name: 'race.positionNormalized', scale: '0..1' },
|
|
212
|
-
{ name: 'race.raceModeGreen', scale: 'boolean' },
|
|
213
|
-
{ name: 'race.raceModeSafetyCar', scale: 'boolean' },
|
|
214
|
-
{ name: 'race.redFlag', scale: 'boolean' },
|
|
215
|
-
{ name: 'race.pitLaneOpen', scale: 'boolean' },
|
|
216
|
-
{ name: 'track.curvature', scale: 'track-curvature' },
|
|
217
|
-
];
|
|
218
|
-
if (includePhysicalDriverSenses) {
|
|
219
|
-
schema.push(
|
|
220
|
-
{ name: 'self.yawRateRadiansPerSecond', unit: 'rad/s', scale: 'fixed:pi' },
|
|
221
|
-
{ name: 'trackRelation.leftBoundaryMeters', unit: 'm', scale: 'fixed:meters' },
|
|
222
|
-
{ name: 'trackRelation.rightBoundaryMeters', unit: 'm', scale: 'fixed:meters' },
|
|
223
|
-
{ name: 'trackRelation.legalWidthMeters', unit: 'm', scale: 'fixed:meters' },
|
|
224
|
-
);
|
|
225
|
-
for (let index = 0; index < 4; index += 1) {
|
|
226
|
-
schema.push(
|
|
227
|
-
{ name: `contactPatches[${index}].present`, scale: 'boolean' },
|
|
228
|
-
{ name: `contactPatches[${index}].surfaceCode`, scale: 'surface-code' },
|
|
229
|
-
{ name: `contactPatches[${index}].onLegalSurface`, scale: 'boolean' },
|
|
230
|
-
{ name: `contactPatches[${index}].signedOffsetMeters`, unit: 'm', scale: 'fixed:meters' },
|
|
231
|
-
{ name: `contactPatches[${index}].crossTrackErrorMeters`, unit: 'm', scale: 'fixed:meters' },
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
lookaheadMeters.forEach((_, index) => {
|
|
236
|
-
schema.push(
|
|
237
|
-
{ name: `track.lookahead[${index}].curvature`, scale: 'track-curvature' },
|
|
238
|
-
{ name: `track.lookahead[${index}].headingDeltaRadians`, unit: 'rad', scale: 'fixed:pi' },
|
|
239
|
-
);
|
|
240
|
-
});
|
|
241
|
-
if (rayOptions.enabled) {
|
|
242
|
-
rayOptions.anglesDegrees.forEach((_, index) => {
|
|
243
|
-
schema.push(
|
|
244
|
-
{ name: `rays[${index}].track.distanceRatio`, scale: '0..1' },
|
|
245
|
-
{ name: `rays[${index}].track.hit`, scale: 'boolean' },
|
|
246
|
-
{ name: `rays[${index}].track.kindExit`, scale: 'boolean' },
|
|
247
|
-
{ name: `rays[${index}].track.kindEntry`, scale: 'boolean' },
|
|
248
|
-
{ name: `rays[${index}].car.distanceRatio`, scale: '0..1' },
|
|
249
|
-
{ name: `rays[${index}].car.hit`, scale: 'boolean' },
|
|
250
|
-
{ name: `rays[${index}].car.relativeSpeedKph`, unit: 'kph', scale: 'fixed:200' },
|
|
251
|
-
{ name: `rays[${index}].car.targetTypeReplayGhost`, scale: 'boolean' },
|
|
252
|
-
);
|
|
253
|
-
MODEL_RAY_SURFACE_CHANNELS.forEach((channel) => {
|
|
254
|
-
if (rayOptions.channels?.includes?.(channel)) {
|
|
255
|
-
schema.push(
|
|
256
|
-
{ name: `rays[${index}].${channel}.distanceRatio`, scale: '0..1' },
|
|
257
|
-
{ name: `rays[${index}].${channel}.hit`, scale: 'boolean' },
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
if (nearbyOptions.enabled) {
|
|
264
|
-
for (let index = 0; index < nearbyOptions.maxCars; index += 1) {
|
|
265
|
-
schema.push(
|
|
266
|
-
{ name: `nearbyCars[${index}].present`, scale: 'boolean' },
|
|
267
|
-
{ name: `nearbyCars[${index}].relativeForwardRatio`, scale: '-1..1' },
|
|
268
|
-
{ name: `nearbyCars[${index}].relativeRightRatio`, scale: '-1..1' },
|
|
269
|
-
{ name: `nearbyCars[${index}].relativeDistanceRatio`, scale: '0..1' },
|
|
270
|
-
{ name: `nearbyCars[${index}].relativeSpeedKph`, unit: 'kph', scale: 'fixed:200' },
|
|
271
|
-
{ name: `nearbyCars[${index}].relativeHeadingRadians`, unit: 'rad', scale: 'fixed:pi' },
|
|
272
|
-
{ name: `nearbyCars[${index}].ahead`, scale: 'boolean' },
|
|
273
|
-
{ name: `nearbyCars[${index}].sameLap`, scale: 'boolean' },
|
|
274
|
-
{ name: `nearbyCars[${index}].entityTypeReplayGhost`, scale: 'boolean' },
|
|
275
|
-
);
|
|
276
|
-
if (includePhysicalDriverSenses) {
|
|
277
|
-
schema.push(
|
|
278
|
-
{ name: `nearbyCars[${index}].behind`, scale: 'boolean' },
|
|
279
|
-
{ name: `nearbyCars[${index}].closingRateMetersPerSecond`, unit: 'm/s', scale: 'fixed:100' },
|
|
280
|
-
{ name: `nearbyCars[${index}].timeToContactSeconds`, unit: 's', scale: 'fixed:10' },
|
|
281
|
-
{ name: `nearbyCars[${index}].leftOverlap`, scale: 'boolean' },
|
|
282
|
-
{ name: `nearbyCars[${index}].rightOverlap`, scale: 'boolean' },
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return schema;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
196
|
function surfaceRaySpec(lengthMeters) {
|
|
291
197
|
return {
|
|
292
198
|
distanceMeters: { unit: 'm', noHitValue: lengthMeters },
|