@inventure71/paddockjs 4.2.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 +34 -0
- package/INSTALL_AND_UPDATE.md +23 -4
- package/README.md +31 -2
- package/docs/advanced_ai_pace.md +131 -0
- package/docs/advanced_physics_rebuild.md +166 -0
- package/docs/architecture.md +109 -30
- package/docs/cleanup_coverage.md +284 -0
- package/docs/component_inventory.md +31 -15
- 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/grid_walk.md +80 -0
- package/docs/index.md +1 -0
- package/docs/keyboard_driving_fix.md +118 -0
- package/docs/limit_driving_2026-10-14.md +88 -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 +36 -11
- package/docs/testing-reliability-guide.md +5 -0
- package/docs/v11_improvements.md +108 -0
- package/package.json +23 -13
- 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 +13 -259
- 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 +21 -140
- 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 +34 -259
- 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 +5 -11
- 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 +14 -3
- package/src/simulation/driver/edgeRecovery.js +0 -1
- package/src/simulation/driver/racingControls.js +10 -406
- package/src/simulation/driver/racingDriverProfile.js +48 -0
- package/src/simulation/driver/racingLinePlan.js +48 -15
- package/src/simulation/driver/rejoinControls.js +58 -111
- package/src/simulation/driver/safetyCarControls.js +12 -0
- package/src/simulation/driver/trafficScan.js +89 -6
- 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 +1 -1
- package/src/simulation/race/redFlag.js +2 -4
- package/src/simulation/race/safetyCar.js +3 -8
- 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/rulesReview.js +1 -7
- 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 +3 -3
- 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 +1 -25
- 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 +4 -241
- 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 +20 -6
- 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 +0 -56
- package/src/simulation/vehicle/vehicleKinematics.js +10 -0
- package/src/simulation/vehicle/vehiclePhysics.js +35 -194
- package/src/simulation/vehicle/vehicleSnapshots.js +13 -4
- package/src/simulation/vehicle/vehicleState.js +2 -1
- 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/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
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { integrateAdvancedVehiclePhysics } from './advancedVehiclePhysics.js';
|
|
1
2
|
import { clamp, normalizeAngle } from '../simMath.js';
|
|
2
3
|
import {
|
|
3
4
|
REAL_F1_WHEELBASE_METERS,
|
|
4
5
|
SIM_UNITS_PER_METER,
|
|
5
6
|
TOP_SPEED_SIM_UNITS_PER_SECOND,
|
|
6
|
-
metersPerSecondToSimSpeed,
|
|
7
7
|
simUnitsToMeters,
|
|
8
8
|
metersToSimUnits,
|
|
9
9
|
} from '../units.js';
|
|
@@ -37,18 +37,6 @@ const SURFACE_MODEL = {
|
|
|
37
37
|
const WHEEL_DRAG_YAW_GAIN = 0.08;
|
|
38
38
|
const MAX_WHEEL_DRAG_YAW_RATE = 0.22;
|
|
39
39
|
|
|
40
|
-
const SIMULATOR_SURFACE_MODEL = {
|
|
41
|
-
track: { grip: 1, drag: 0, rollingResistance: 0.008, scrub: 0 },
|
|
42
|
-
'pit-entry': { grip: 0.92, drag: 0.06, rollingResistance: 0.018, scrub: 1.2 },
|
|
43
|
-
'pit-lane': { grip: 0.9, drag: 0.08, rollingResistance: 0.02, scrub: 1.4 },
|
|
44
|
-
'pit-exit': { grip: 0.92, drag: 0.06, rollingResistance: 0.018, scrub: 1.2 },
|
|
45
|
-
'pit-box': { grip: 0.82, drag: 0.12, rollingResistance: 0.035, scrub: 2.5 },
|
|
46
|
-
kerb: { grip: 0.78, drag: 0.42, rollingResistance: 0.09, scrub: 8.5 },
|
|
47
|
-
gravel: { grip: 0.36, drag: 5.4, rollingResistance: 0.24, scrub: 18 },
|
|
48
|
-
grass: { grip: 0.3, drag: 3.4, rollingResistance: 0.2, scrub: 15 },
|
|
49
|
-
barrier: { grip: 0.08, drag: 15, rollingResistance: 2.4, scrub: 30 },
|
|
50
|
-
};
|
|
51
|
-
|
|
52
40
|
export function normalizePhysicsMode(value) {
|
|
53
41
|
return PHYSICS_MODES.includes(value) ? value : DEFAULT_PHYSICS_MODE;
|
|
54
42
|
}
|
|
@@ -67,11 +55,39 @@ function brakingLimit(speed, surfaceGrip) {
|
|
|
67
55
|
return SIM_UNITS_PER_METER * surfaceGrip * (20 + speedRatio * 14);
|
|
68
56
|
}
|
|
69
57
|
|
|
58
|
+
// Policy accessors use the same arcade model without changing its integrator.
|
|
59
|
+
// Surface grip is the base coefficient; callers apply tire condition once.
|
|
60
|
+
export function arcadeSurfaceGrip(car) {
|
|
61
|
+
return (SURFACE_MODEL[car.trackState?.surface] ?? SURFACE_MODEL.track).grip;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function arcadeResistanceForce(car, speedMetersPerSecond) {
|
|
65
|
+
const surface = SURFACE_MODEL[car.trackState?.surface] ?? SURFACE_MODEL.track;
|
|
66
|
+
const dragMultiplier = car.drsActive ? 0.42 : 1;
|
|
67
|
+
return (car.dragCoefficient * dragMultiplier * 0.12 + surface.drag) * speedMetersPerSecond ** 2 +
|
|
68
|
+
surface.rollingResistance * car.mass * G;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// The existing limits take speed and return acceleration in simulator units.
|
|
72
|
+
export { accelerationLimit as arcadeAccelerationLimit, brakingLimit as arcadeBrakingLimit };
|
|
73
|
+
|
|
70
74
|
export function tirePerformanceFactor(tireEnergy = 100) {
|
|
71
75
|
const normalized = clamp((Number(tireEnergy) || 1) / 100, 0.01, 1);
|
|
72
76
|
return clamp(0.45 + 0.55 * normalized ** 0.72, 0.45, 1);
|
|
73
77
|
}
|
|
74
78
|
|
|
79
|
+
export function arcadeTrackCornerSpeedLimit(car, curvature, gripShare) {
|
|
80
|
+
const tire = tirePerformanceFactor(car.tireEnergy ?? 100);
|
|
81
|
+
// On tarmac the arcade yaw limit is (static + aero * speed²) / speed.
|
|
82
|
+
// Invert that same law for a future corner; the driver owns its grip reserve.
|
|
83
|
+
const staticCapacity = car.tireGrip * G * tire * tire;
|
|
84
|
+
const aeroCapacity = car.downforceCoefficient / car.mass * tire;
|
|
85
|
+
const denominator = Math.abs(curvature) - gripShare * aeroCapacity;
|
|
86
|
+
return denominator > 0
|
|
87
|
+
? Math.min(simUnitsToMeters(VEHICLE_LIMITS.maxSpeed), Math.sqrt(gripShare * staticCapacity / denominator))
|
|
88
|
+
: simUnitsToMeters(VEHICLE_LIMITS.maxSpeed);
|
|
89
|
+
}
|
|
90
|
+
|
|
75
91
|
function surfaceResistance(surfaceName, model = SURFACE_MODEL) {
|
|
76
92
|
const surface = model[surfaceName] ?? model.track;
|
|
77
93
|
return surface.drag * 0.14 + surface.rollingResistance * 2.4 + (1 - surface.grip) * 0.65;
|
|
@@ -126,7 +142,12 @@ function setPhysicsTelemetry(car, {
|
|
|
126
142
|
export function integrateVehiclePhysics(car, controls, dt, options = {}) {
|
|
127
143
|
const mode = normalizePhysicsMode(options.physicsMode);
|
|
128
144
|
if (mode === 'advanced') {
|
|
129
|
-
return
|
|
145
|
+
return integrateAdvancedVehiclePhysics(car, controls, dt, {
|
|
146
|
+
tireFactor: tirePerformanceFactor(car.tireEnergy ?? 100),
|
|
147
|
+
tireDegradationEnabled: options.tireDegradationEnabled,
|
|
148
|
+
maxSteer: VEHICLE_LIMITS.maxSteer,
|
|
149
|
+
steerRate: VEHICLE_LIMITS.steerRate,
|
|
150
|
+
});
|
|
130
151
|
}
|
|
131
152
|
return integrateArcadeVehiclePhysics(car, controls, dt, options);
|
|
132
153
|
}
|
|
@@ -201,184 +222,4 @@ function integrateArcadeVehiclePhysics(car, controls, dt, options = {}) {
|
|
|
201
222
|
return car;
|
|
202
223
|
}
|
|
203
224
|
|
|
204
|
-
function simulatorSurface(surfaceName) {
|
|
205
|
-
return SIMULATOR_SURFACE_MODEL[surfaceName] ?? SIMULATOR_SURFACE_MODEL.track;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function aggregateSimulatorSurface(car) {
|
|
209
|
-
const wheels = Array.isArray(car.wheelStates) ? car.wheelStates : [];
|
|
210
|
-
if (!wheels.length) return simulatorSurface(car.trackState?.surface ?? 'track');
|
|
211
|
-
let grip = 0;
|
|
212
|
-
let drag = 0;
|
|
213
|
-
let rollingResistance = 0;
|
|
214
|
-
let scrub = 0;
|
|
215
|
-
for (let index = 0; index < wheels.length; index += 1) {
|
|
216
|
-
const surface = simulatorSurface(wheels[index].surface);
|
|
217
|
-
grip += surface.grip;
|
|
218
|
-
drag += surface.drag;
|
|
219
|
-
rollingResistance += surface.rollingResistance;
|
|
220
|
-
scrub += surface.scrub;
|
|
221
|
-
}
|
|
222
|
-
return {
|
|
223
|
-
grip: grip / wheels.length,
|
|
224
|
-
drag: drag / wheels.length,
|
|
225
|
-
rollingResistance: rollingResistance / wheels.length,
|
|
226
|
-
scrub: scrub / wheels.length,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function simulatorStabilityState({ gripUsage, slipAngle, surfaceName, brake, throttle }) {
|
|
231
|
-
if (gripUsage > 1.32 || Math.abs(slipAngle) > 0.42) return 'spin-risk';
|
|
232
|
-
if (gripUsage > 1.02) return brake > 0.2 && throttle < 0.2 ? 'oversteer' : 'understeer';
|
|
233
|
-
if (surfaceName === 'kerb' && gripUsage > 0.72) return 'oversteer';
|
|
234
|
-
if ((surfaceName === 'gravel' || surfaceName === 'grass') && gripUsage > 0.5) return 'understeer';
|
|
235
|
-
return 'stable';
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function ensureSimulatorVelocity(car) {
|
|
239
|
-
if (Number.isFinite(car.velocityX) && Number.isFinite(car.velocityY)) return;
|
|
240
|
-
const speed = clamp(Number(car.speed) || 0, 0, VEHICLE_LIMITS.maxSpeed);
|
|
241
|
-
car.velocityX = Math.cos(car.heading ?? 0) * speed;
|
|
242
|
-
car.velocityY = Math.sin(car.heading ?? 0) * speed;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function limitSimulatorSpeed(car) {
|
|
246
|
-
const speed = Math.hypot(car.velocityX, car.velocityY);
|
|
247
|
-
if (speed <= VEHICLE_LIMITS.maxSpeed || speed <= 0) return speed;
|
|
248
|
-
const scale = VEHICLE_LIMITS.maxSpeed / speed;
|
|
249
|
-
car.velocityX *= scale;
|
|
250
|
-
car.velocityY *= scale;
|
|
251
|
-
return VEHICLE_LIMITS.maxSpeed;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function integrateSimulatorVehiclePhysics(car, controls, dt, options = {}) {
|
|
255
|
-
ensureSimulatorVelocity(car);
|
|
256
|
-
const steeringTarget = clamp(controls.steering ?? 0, -VEHICLE_LIMITS.maxSteer, VEHICLE_LIMITS.maxSteer);
|
|
257
|
-
const steerDelta = clamp(
|
|
258
|
-
steeringTarget - car.steeringAngle,
|
|
259
|
-
-VEHICLE_LIMITS.steerRate * dt,
|
|
260
|
-
VEHICLE_LIMITS.steerRate * dt,
|
|
261
|
-
);
|
|
262
|
-
car.steeringAngle += steerDelta;
|
|
263
|
-
|
|
264
|
-
const throttle = clamp(controls.throttle ?? 0, 0, 1);
|
|
265
|
-
const brake = clamp(controls.brake ?? 0, 0, 1);
|
|
266
|
-
const surfaceName = car.trackState?.surface ?? 'track';
|
|
267
|
-
const surface = aggregateSimulatorSurface(car);
|
|
268
|
-
const tireFactor = tirePerformanceFactor(car.tireEnergy ?? 100);
|
|
269
|
-
const surfaceGrip = surface.grip * tireFactor;
|
|
270
|
-
const speedBefore = Math.hypot(car.velocityX, car.velocityY);
|
|
271
|
-
const speedBeforeMps = simUnitsToMeters(speedBefore);
|
|
272
|
-
const speedRatio = clamp(speedBefore / VEHICLE_LIMITS.maxSpeed, 0, 1);
|
|
273
|
-
const downforceGrip = car.downforceCoefficient * speedBeforeMps * speedBeforeMps / car.mass;
|
|
274
|
-
const totalGripAcceleration = Math.max(0.1, (car.tireGrip * tireFactor * G + downforceGrip) * surfaceGrip);
|
|
275
|
-
const heading = car.heading ?? 0;
|
|
276
|
-
const forwardX = Math.cos(heading);
|
|
277
|
-
const forwardY = Math.sin(heading);
|
|
278
|
-
const rightX = -forwardY;
|
|
279
|
-
const rightY = forwardX;
|
|
280
|
-
const forwardVelocity = car.velocityX * forwardX + car.velocityY * forwardY;
|
|
281
|
-
const lateralVelocity = car.velocityX * rightX + car.velocityY * rightY;
|
|
282
|
-
const forwardSpeedMps = simUnitsToMeters(forwardVelocity);
|
|
283
|
-
const lateralSpeedMps = simUnitsToMeters(lateralVelocity);
|
|
284
|
-
const currentSlipAngle = Math.atan2(lateralSpeedMps, Math.max(Math.abs(forwardSpeedMps), 0.1));
|
|
285
|
-
const engineForce = throttle *
|
|
286
|
-
car.powerNewtons *
|
|
287
|
-
(car.drsActive ? 1.07 : 1) *
|
|
288
|
-
Math.max(0.08, 1 - speedRatio ** 1.22);
|
|
289
|
-
const brakeForce = brake * car.brakeNewtons;
|
|
290
|
-
const driveAcceleration = Math.min(
|
|
291
|
-
engineForce / car.mass,
|
|
292
|
-
accelerationLimit(car.speed, surfaceGrip) / SIM_UNITS_PER_METER,
|
|
293
|
-
);
|
|
294
|
-
const brakeDeceleration = Math.min(
|
|
295
|
-
brakeForce / car.mass,
|
|
296
|
-
brakingLimit(car.speed, surfaceGrip) / SIM_UNITS_PER_METER,
|
|
297
|
-
);
|
|
298
|
-
const dragMultiplier = car.drsActive ? 0.46 : 1;
|
|
299
|
-
const dragAcceleration = (
|
|
300
|
-
(car.dragCoefficient * dragMultiplier * 0.28 + surface.drag * 0.018) *
|
|
301
|
-
speedBeforeMps * speedBeforeMps
|
|
302
|
-
) / car.mass;
|
|
303
|
-
const rollingAcceleration = surface.rollingResistance * G;
|
|
304
|
-
const normalizedSteer = Math.abs(car.steeringAngle) / VEHICLE_LIMITS.maxSteer;
|
|
305
|
-
const speedSensitiveSteer = 1 / (1 + (Math.abs(forwardSpeedMps) / 58) ** 1.85 * 2.35);
|
|
306
|
-
const effectiveSteeringAngle = car.steeringAngle * clamp(speedSensitiveSteer, 0.16, 1);
|
|
307
|
-
const rawYawRate = Math.abs(forwardSpeedMps) <= 0.05
|
|
308
|
-
? 0
|
|
309
|
-
: (forwardSpeedMps / REAL_F1_WHEELBASE_METERS) * Math.tan(effectiveSteeringAngle);
|
|
310
|
-
const sideSlipDamping = 4.2 + surfaceGrip * 2.1 + speedRatio * 1.6;
|
|
311
|
-
const desiredLateralAcceleration = forwardSpeedMps * rawYawRate - lateralSpeedMps * sideSlipDamping;
|
|
312
|
-
const longitudinalDemand = Math.max(driveAcceleration, brakeDeceleration);
|
|
313
|
-
const longitudinalUsage = clamp(longitudinalDemand / Math.max(totalGripAcceleration * 0.52, 1), 0, 0.94);
|
|
314
|
-
const lateralCapacity = totalGripAcceleration * Math.sqrt(Math.max(0.08, 1 - longitudinalUsage ** 2));
|
|
315
|
-
const desiredLateralAbs = Math.abs(desiredLateralAcceleration);
|
|
316
|
-
const lateralUsage = desiredLateralAbs / Math.max(lateralCapacity, 0.1);
|
|
317
|
-
const gripUsage = Math.sqrt(lateralUsage ** 2 + longitudinalUsage ** 2);
|
|
318
|
-
const tractionLimited = gripUsage > 1 || longitudinalUsage > 0.9;
|
|
319
|
-
const actualLateralAcceleration = clamp(desiredLateralAcceleration, -lateralCapacity, lateralCapacity);
|
|
320
|
-
const steeringYawRate = Math.abs(forwardSpeedMps) <= 0.05 ? 0 : actualLateralAcceleration / Math.max(Math.abs(forwardSpeedMps), 0.1);
|
|
321
|
-
const steeringScrubAcceleration = normalizedSteer ** 1.55 *
|
|
322
|
-
speedRatio ** 1.05 *
|
|
323
|
-
(42 + surface.scrub + Math.max(0, gripUsage - 0.55) * 18);
|
|
324
|
-
const tractionPowerScale = tractionLimited
|
|
325
|
-
? clamp(1 - (gripUsage - 1) * 0.55 - longitudinalUsage * 0.18, 0.12, 1)
|
|
326
|
-
: 1;
|
|
327
|
-
const brakingDirection = forwardSpeedMps >= -0.2 ? 1 : -1;
|
|
328
|
-
const scrubDirection = forwardSpeedMps >= 0 ? 1 : -1;
|
|
329
|
-
const longitudinalAcceleration =
|
|
330
|
-
driveAcceleration * tractionPowerScale -
|
|
331
|
-
brakeDeceleration * brakingDirection -
|
|
332
|
-
dragAcceleration * Math.sign(forwardSpeedMps || 1) -
|
|
333
|
-
rollingAcceleration * Math.sign(forwardSpeedMps || 1) -
|
|
334
|
-
steeringScrubAcceleration * scrubDirection;
|
|
335
|
-
|
|
336
|
-
const requestedWheelDragYawRate = wheelDragYawRate(car, SIMULATOR_SURFACE_MODEL) * (surfaceName === 'kerb' ? 1.6 : 1);
|
|
337
|
-
const maxYawRate = speedBeforeMps <= 0.05 ? 0 : totalGripAcceleration / Math.max(speedBeforeMps, 0.1);
|
|
338
|
-
const slipSteeringAuthority = clamp(1 - Math.abs(currentSlipAngle) * 1.8, 0.35, 1);
|
|
339
|
-
const yawTarget = clamp(steeringYawRate * slipSteeringAuthority + requestedWheelDragYawRate, -maxYawRate, maxYawRate);
|
|
340
|
-
const yawResponse = 1.6 + surfaceGrip * 0.9 + speedRatio * 0.5;
|
|
341
|
-
const yawAccelerationCap = speedRatio < 0.18 ? 6.2 : 3.2;
|
|
342
|
-
const maxYawDelta = Math.min(Math.max(0.08, maxYawRate * yawResponse), yawAccelerationCap) * dt;
|
|
343
|
-
car.yawRate = clamp(
|
|
344
|
-
(car.yawRate ?? 0) + clamp(yawTarget - (car.yawRate ?? 0), -maxYawDelta, maxYawDelta),
|
|
345
|
-
-maxYawRate,
|
|
346
|
-
maxYawRate,
|
|
347
|
-
);
|
|
348
|
-
car.wheelDragYawRate = requestedWheelDragYawRate;
|
|
349
|
-
car.heading = normalizeAngle(car.heading + car.yawRate * dt);
|
|
350
|
-
|
|
351
|
-
const accelerationX = forwardX * longitudinalAcceleration + rightX * actualLateralAcceleration;
|
|
352
|
-
const accelerationY = forwardY * longitudinalAcceleration + rightY * actualLateralAcceleration;
|
|
353
|
-
car.velocityX += metersToSimUnits(accelerationX) * dt;
|
|
354
|
-
car.velocityY += metersToSimUnits(accelerationY) * dt;
|
|
355
|
-
car.speed = limitSimulatorSpeed(car);
|
|
356
|
-
car.x += car.velocityX * dt;
|
|
357
|
-
car.y += car.velocityY * dt;
|
|
358
|
-
car.throttle = throttle;
|
|
359
|
-
car.brake = brake;
|
|
360
|
-
car.steerSaturation = rawYawRate === 0 ? 0 : Math.abs(steeringYawRate / rawYawRate);
|
|
361
|
-
car.turnRadius = Math.abs(car.yawRate) < 0.001 ? Infinity : car.speed / Math.abs(car.yawRate);
|
|
362
|
-
const velocityHeading = car.speed <= 0.01 ? car.heading : Math.atan2(car.velocityY, car.velocityX);
|
|
363
|
-
const slipAngle = normalizeAngle(velocityHeading - car.heading);
|
|
364
|
-
setPhysicsTelemetry(car, {
|
|
365
|
-
lateralAcceleration: actualLateralAcceleration,
|
|
366
|
-
longitudinalAcceleration,
|
|
367
|
-
gripUsage,
|
|
368
|
-
slipAngleRadians: slipAngle,
|
|
369
|
-
tractionLimited,
|
|
370
|
-
stabilityState: simulatorStabilityState({ gripUsage, slipAngle, surfaceName, brake, throttle }),
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
if (options.tireDegradationEnabled !== false) {
|
|
374
|
-
const tyreLoad = Math.abs(car.lateralAcceleration) / G;
|
|
375
|
-
const tireCare = clamp(Number(car.tireCare) || 1, 0.45, 1.8);
|
|
376
|
-
const heatPenalty = Math.max(0, gripUsage - 0.72) * 0.24 + normalizedSteer * speedRatio * 0.08;
|
|
377
|
-
const wearRate = (0.045 + tyreLoad * 0.16 + brake * 0.09 + throttle * 0.035 + heatPenalty) / tireCare;
|
|
378
|
-
car.tireEnergy = clamp((car.tireEnergy ?? 100) - wearRate * dt, 1, 100);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return car;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
225
|
export { getCarCorners };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { finiteOrNull } from '../simMath.js';
|
|
2
|
+
export { finiteOrNull } from '../simMath.js';
|
|
3
|
+
|
|
1
4
|
import {
|
|
2
5
|
serializeParticipantInteraction,
|
|
3
6
|
serializeParticipantInteractionCached,
|
|
4
7
|
} from '../participants/participantInteractions.js';
|
|
5
8
|
|
|
6
|
-
export function finiteOrNull(value) {
|
|
7
|
-
return Number.isFinite(value) ? value : null;
|
|
8
|
-
}
|
|
9
9
|
|
|
10
10
|
function serializeAppliedControls(car, dependencies) {
|
|
11
11
|
const { VEHICLE_LIMITS } = dependencies;
|
|
@@ -24,6 +24,15 @@ function serializeVelocityComponent(car, component, dependencies) {
|
|
|
24
24
|
return finiteOrNull(car[component]);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
function serializeTeam(team) {
|
|
28
|
+
if (!team) return null;
|
|
29
|
+
return {
|
|
30
|
+
...team,
|
|
31
|
+
...(team.pitCrew && typeof team.pitCrew === 'object' ? { pitCrew: { ...team.pitCrew } } : {}),
|
|
32
|
+
...(team.pitCrewStats && typeof team.pitCrewStats === 'object' ? { pitCrewStats: { ...team.pitCrewStats } } : {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
export function serializeWheels(wheels = []) {
|
|
28
37
|
return wheels.map((wheel) => ({
|
|
29
38
|
id: wheel.id,
|
|
@@ -60,7 +69,7 @@ export function serializeCar(car, rank, penaltySeconds = 0, dependencies) {
|
|
|
60
69
|
raceName: car.raceName,
|
|
61
70
|
name: car.name,
|
|
62
71
|
color: car.color,
|
|
63
|
-
team: car.team
|
|
72
|
+
team: serializeTeam(car.team),
|
|
64
73
|
tire: car.tire,
|
|
65
74
|
personality: { ...car.personality },
|
|
66
75
|
aggression: car.aggression,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildDriverPersonality } from '../
|
|
1
|
+
import { buildDriverPersonality } from '../driver/driverPersonality.js';
|
|
2
2
|
import { clamp, normalizeAngle, seededRange } from '../simMath.js';
|
|
3
3
|
import { offsetTrackPoint, pointAt } from '../track/trackModel.js';
|
|
4
4
|
import { kphToSimSpeed, metersToSimUnits } from '../units.js';
|
|
@@ -76,6 +76,7 @@ export function createCar(driver, index, random, track, { standingStart = false,
|
|
|
76
76
|
driverModel: driver.driverModel ?? vehicle.driverModel ?? null,
|
|
77
77
|
pace,
|
|
78
78
|
racecraft,
|
|
79
|
+
consistency: Number.isFinite(driver.consistency) ? clamp(driver.consistency, 0, 1) : 0.75,
|
|
79
80
|
personality,
|
|
80
81
|
aggression: personality.baseAggression,
|
|
81
82
|
gridLocked: standingStart,
|