@inventure71/paddockjs 0.3.0 → 1.0.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 +39 -0
- package/INSTALL_AND_UPDATE.md +3 -1
- package/README.md +142 -9
- package/docs/architecture.md +49 -15
- package/docs/concepts.md +20 -3
- package/docs/data_contract.md +185 -27
- package/docs/data_model.md +1 -1
- package/docs/learnings.md +1 -1
- package/docs/rules.md +140 -19
- package/docs/system_specs.md +39 -16
- package/docs/training.md +103 -1
- package/examples/train-basic-policy.mjs +5 -6
- package/examples/trainingData.mjs +133 -0
- package/package.json +5 -2
- package/src/api/PaddockSimulatorController.js +32 -2
- package/src/app/F1SimulatorApp.js +1101 -128
- package/src/app/domBindings.js +10 -1
- package/src/config/defaultOptions.js +4 -4
- package/src/environment/actions.js +25 -2
- package/src/environment/evaluation.js +184 -0
- package/src/environment/index.d.ts +281 -1
- package/src/environment/index.js +13 -0
- package/src/environment/observationOptions.js +12 -0
- package/src/environment/observations.js +189 -17
- package/src/environment/options.js +7 -0
- package/src/environment/recorder.js +28 -0
- package/src/environment/runtime.js +41 -6
- package/src/environment/scenarios.js +220 -0
- package/src/environment/sensors.js +145 -35
- package/src/environment/specs.js +92 -8
- package/src/environment/workerProtocol.js +52 -0
- package/src/index.d.ts +366 -3
- package/src/index.js +21 -0
- package/src/rendering/proceduralTrackAsset.js +336 -23
- package/src/simulation/collisionGeometry.js +214 -0
- package/src/simulation/driverController.js +431 -65
- package/src/simulation/raceSimulation.js +2132 -171
- package/src/simulation/rules/collisionSteward.js +69 -0
- package/src/simulation/rules/penaltyLedger.js +153 -0
- package/src/simulation/rules/pitLaneSpeedingSteward.js +71 -0
- package/src/simulation/rules/tireRequirementSteward.js +29 -0
- package/src/simulation/rules/trackLimitsSteward.js +85 -0
- package/src/simulation/rulesConfig.js +352 -0
- package/src/simulation/trackModel.js +1154 -76
- package/src/simulation/units.js +6 -4
- package/src/simulation/vehicleGeometry.js +247 -0
- package/src/simulation/vehiclePhysics.js +82 -50
- package/src/simulation/wheelSurface.js +338 -0
- package/src/styles.css +300 -42
- package/src/ui/bannerTemplates.js +69 -0
- package/src/ui/componentTemplates.js +36 -96
- package/src/ui/raceControlStatusBanner.js +39 -0
- package/src/ui/shellTemplate.js +1 -1
- package/src/ui/templateUtils.js +23 -0
package/src/index.d.ts
CHANGED
|
@@ -3,7 +3,17 @@ import type { PaddockActionSpec, PaddockObservationSpec } from './environment/in
|
|
|
3
3
|
export type { PaddockActionSpec, PaddockObservationSpec } from './environment/index.js';
|
|
4
4
|
|
|
5
5
|
export type TireCompound = 'S' | 'M' | 'H';
|
|
6
|
-
export type
|
|
6
|
+
export type PaddockPitIntent = 0 | 1 | 2;
|
|
7
|
+
export type PaddockPitIntentRequest = PaddockPitIntent | {
|
|
8
|
+
intent?: PaddockPitIntent;
|
|
9
|
+
pitIntent?: PaddockPitIntent;
|
|
10
|
+
targetCompound?: TireCompound | string;
|
|
11
|
+
compound?: TireCompound | string;
|
|
12
|
+
pitCompound?: TireCompound | string;
|
|
13
|
+
pitTargetCompound?: TireCompound | string;
|
|
14
|
+
targetTire?: TireCompound | string;
|
|
15
|
+
};
|
|
16
|
+
export type CameraMode = 'overview' | 'leader' | 'selected' | 'show-all' | 'pit';
|
|
7
17
|
export type RaceBannerMode = 'project' | 'radio' | 'hidden';
|
|
8
18
|
export type RaceBannerEnabledMode = 'project' | 'radio';
|
|
9
19
|
export type RaceDataBannerSize = 'auto' | 'custom';
|
|
@@ -26,6 +36,14 @@ export interface TeamData {
|
|
|
26
36
|
name?: string;
|
|
27
37
|
color?: string;
|
|
28
38
|
icon?: string;
|
|
39
|
+
pitCrew?: PaddockPitCrewStats;
|
|
40
|
+
pitCrewStats?: PaddockPitCrewStats;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface PaddockPitCrewStats {
|
|
44
|
+
speed?: number;
|
|
45
|
+
consistency?: number;
|
|
46
|
+
reliability?: number;
|
|
29
47
|
}
|
|
30
48
|
|
|
31
49
|
export interface SimulatorDriver {
|
|
@@ -184,6 +202,9 @@ export interface F1SimulatorUiOptions {
|
|
|
184
202
|
};
|
|
185
203
|
raceDataBannerSize?: RaceDataBannerSize;
|
|
186
204
|
raceDataTelemetryDetail?: boolean;
|
|
205
|
+
penaltyBanners?: boolean;
|
|
206
|
+
timingPenaltyBadges?: boolean;
|
|
207
|
+
simulationSpeedControl?: boolean;
|
|
187
208
|
timingTowerVerticalFit?: TimingTowerVerticalFit;
|
|
188
209
|
}
|
|
189
210
|
|
|
@@ -206,9 +227,113 @@ export interface TrackSnapshot {
|
|
|
206
227
|
width?: number;
|
|
207
228
|
length?: number;
|
|
208
229
|
sectors?: TrackSectorSnapshot[];
|
|
230
|
+
pitLane?: PitLaneSnapshot;
|
|
209
231
|
[key: string]: unknown;
|
|
210
232
|
}
|
|
211
233
|
|
|
234
|
+
export interface TrackPointSnapshot {
|
|
235
|
+
x: number;
|
|
236
|
+
y: number;
|
|
237
|
+
heading?: number;
|
|
238
|
+
distance?: number;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export interface PitLaneSnapshot {
|
|
242
|
+
enabled: boolean;
|
|
243
|
+
side: -1 | 1;
|
|
244
|
+
width: number;
|
|
245
|
+
offset?: number;
|
|
246
|
+
boxCount: number;
|
|
247
|
+
teamCount: number;
|
|
248
|
+
boxesPerTeam: number;
|
|
249
|
+
entry: {
|
|
250
|
+
trackDistance: number;
|
|
251
|
+
distanceFromStart: number;
|
|
252
|
+
trackPoint: TrackPointSnapshot;
|
|
253
|
+
edgePoint: TrackPointSnapshot;
|
|
254
|
+
trackConnectPoint: TrackPointSnapshot;
|
|
255
|
+
lanePoint: TrackPointSnapshot;
|
|
256
|
+
roadCenterline: TrackPointSnapshot[];
|
|
257
|
+
connector: TrackPointSnapshot[];
|
|
258
|
+
};
|
|
259
|
+
exit: {
|
|
260
|
+
trackDistance: number;
|
|
261
|
+
distanceFromStart: number;
|
|
262
|
+
trackPoint: TrackPointSnapshot;
|
|
263
|
+
edgePoint: TrackPointSnapshot;
|
|
264
|
+
trackConnectPoint: TrackPointSnapshot;
|
|
265
|
+
lanePoint: TrackPointSnapshot;
|
|
266
|
+
roadCenterline: TrackPointSnapshot[];
|
|
267
|
+
connector: TrackPointSnapshot[];
|
|
268
|
+
};
|
|
269
|
+
mainLane: {
|
|
270
|
+
start: TrackPointSnapshot;
|
|
271
|
+
end: TrackPointSnapshot;
|
|
272
|
+
points: TrackPointSnapshot[];
|
|
273
|
+
length: number;
|
|
274
|
+
heading: number;
|
|
275
|
+
};
|
|
276
|
+
fastLane?: {
|
|
277
|
+
offset: number;
|
|
278
|
+
width: number;
|
|
279
|
+
};
|
|
280
|
+
workingLane?: {
|
|
281
|
+
start: TrackPointSnapshot;
|
|
282
|
+
end: TrackPointSnapshot;
|
|
283
|
+
points: TrackPointSnapshot[];
|
|
284
|
+
offset: number;
|
|
285
|
+
width: number;
|
|
286
|
+
};
|
|
287
|
+
serviceNormal: { x: number; y: number };
|
|
288
|
+
teams?: PitTeamSnapshot[];
|
|
289
|
+
boxes: PitBoxSnapshot[];
|
|
290
|
+
serviceAreas?: PitServiceAreaSnapshot[];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export interface PitTeamSnapshot {
|
|
294
|
+
id: string;
|
|
295
|
+
name: string;
|
|
296
|
+
color: string;
|
|
297
|
+
index: number;
|
|
298
|
+
boxIds: string[];
|
|
299
|
+
serviceAreaId?: string | null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface PitBoxSnapshot {
|
|
303
|
+
id: string;
|
|
304
|
+
index: number;
|
|
305
|
+
teamIndex: number;
|
|
306
|
+
teamBoxIndex: number;
|
|
307
|
+
teamId?: string;
|
|
308
|
+
teamName?: string;
|
|
309
|
+
teamColor?: string;
|
|
310
|
+
distanceAlongLane: number;
|
|
311
|
+
laneTarget: TrackPointSnapshot;
|
|
312
|
+
center: TrackPointSnapshot;
|
|
313
|
+
length: number;
|
|
314
|
+
depth: number;
|
|
315
|
+
corners: TrackPointSnapshot[];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export interface PitServiceAreaSnapshot {
|
|
319
|
+
id: string;
|
|
320
|
+
index: number;
|
|
321
|
+
teamIndex: number;
|
|
322
|
+
teamId?: string;
|
|
323
|
+
teamName?: string;
|
|
324
|
+
teamColor?: string;
|
|
325
|
+
distanceAlongLane: number;
|
|
326
|
+
queueDistanceAlongLane: number;
|
|
327
|
+
laneTarget: TrackPointSnapshot;
|
|
328
|
+
center: TrackPointSnapshot;
|
|
329
|
+
queuePoint: TrackPointSnapshot;
|
|
330
|
+
length: number;
|
|
331
|
+
depth: number;
|
|
332
|
+
corners: TrackPointSnapshot[];
|
|
333
|
+
queueCorners: TrackPointSnapshot[];
|
|
334
|
+
garageBoxIds: string[];
|
|
335
|
+
}
|
|
336
|
+
|
|
212
337
|
export interface TrackSectorSnapshot {
|
|
213
338
|
index: number;
|
|
214
339
|
id: string;
|
|
@@ -227,6 +352,8 @@ export interface LapTelemetrySnapshot {
|
|
|
227
352
|
currentSectorElapsed: number | null;
|
|
228
353
|
currentSectorProgress: number | null;
|
|
229
354
|
currentSectors: Array<number | null>;
|
|
355
|
+
sectorProgress: Array<number | null>;
|
|
356
|
+
liveSectors: Array<number | null>;
|
|
230
357
|
sectorPerformance: {
|
|
231
358
|
current: Array<SectorPerformanceStatus | null>;
|
|
232
359
|
last: Array<SectorPerformanceStatus | null>;
|
|
@@ -239,12 +366,187 @@ export interface LapTelemetrySnapshot {
|
|
|
239
366
|
completedLaps: number;
|
|
240
367
|
}
|
|
241
368
|
|
|
369
|
+
export interface PitStopSnapshot {
|
|
370
|
+
status: 'pending' | 'entering' | 'queued' | 'servicing' | 'exiting' | 'completed';
|
|
371
|
+
intent: PaddockPitIntent;
|
|
372
|
+
phase: 'entry' | 'queue' | 'queue-release' | 'penalty' | 'service' | 'exit' | null;
|
|
373
|
+
boxIndex: number;
|
|
374
|
+
boxId: string;
|
|
375
|
+
garageBoxIndex?: number | null;
|
|
376
|
+
garageBoxId?: string | null;
|
|
377
|
+
teamId?: string | null;
|
|
378
|
+
teamColor?: string | null;
|
|
379
|
+
stopsCompleted: number;
|
|
380
|
+
queueingForService?: boolean;
|
|
381
|
+
plannedRaceDistance: number | null;
|
|
382
|
+
entryRaceDistance: number | null;
|
|
383
|
+
serviceRemainingSeconds: number | null;
|
|
384
|
+
penaltyServiceRemainingSeconds: number | null;
|
|
385
|
+
penaltyServiceTotalSeconds: number | null;
|
|
386
|
+
servingPenaltyIds: string[];
|
|
387
|
+
targetTire?: TireCompound | string | null;
|
|
388
|
+
serviceProfile?: {
|
|
389
|
+
baseSeconds: number;
|
|
390
|
+
seconds: number;
|
|
391
|
+
perfect: boolean;
|
|
392
|
+
variabilityEnabled: boolean;
|
|
393
|
+
teamId?: string | null;
|
|
394
|
+
pitCrew: Required<PaddockPitCrewStats>;
|
|
395
|
+
speedDeltaSeconds: number;
|
|
396
|
+
consistencyDeltaSeconds: number;
|
|
397
|
+
issueDelaySeconds: number;
|
|
398
|
+
issue?: string | null;
|
|
399
|
+
} | null;
|
|
400
|
+
}
|
|
401
|
+
|
|
242
402
|
export interface RaceEvent {
|
|
243
403
|
type: string;
|
|
244
404
|
at?: number;
|
|
405
|
+
firstShapeId?: string;
|
|
406
|
+
secondShapeId?: string;
|
|
407
|
+
contactType?: 'body-body' | 'body-wheel' | 'wheel-body' | 'wheel-wheel' | string;
|
|
408
|
+
depth?: number;
|
|
409
|
+
timeOfImpact?: number;
|
|
410
|
+
[key: string]: unknown;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export type PaddockRulesetName = 'paddock' | 'custom' | 'grandPrix2025' | 'fia2025';
|
|
414
|
+
|
|
415
|
+
export interface PaddockPitStopRules {
|
|
416
|
+
enabled?: boolean;
|
|
417
|
+
pitLaneSpeedLimitKph?: number;
|
|
418
|
+
defaultStopSeconds?: number;
|
|
419
|
+
variability?: {
|
|
420
|
+
enabled?: boolean;
|
|
421
|
+
perfect?: boolean;
|
|
422
|
+
speedImpactSeconds?: number;
|
|
423
|
+
consistencyJitterSeconds?: number;
|
|
424
|
+
issueChance?: number;
|
|
425
|
+
issueMaxDelaySeconds?: number;
|
|
426
|
+
};
|
|
427
|
+
maxConcurrentPitLaneCars?: number;
|
|
428
|
+
minimumPitLaneGapMeters?: number;
|
|
429
|
+
doubleStacking?: boolean;
|
|
430
|
+
tirePitRequestThresholdPercent?: number;
|
|
431
|
+
tirePitCommitThresholdPercent?: number;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export interface PaddockTireStrategyRules {
|
|
435
|
+
enabled?: boolean;
|
|
436
|
+
compounds?: TireCompound[];
|
|
437
|
+
mandatoryDistinctDryCompounds?: number | null;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export interface PaddockPenaltySubsectionRules {
|
|
441
|
+
strictness?: number;
|
|
442
|
+
timePenaltySeconds?: number;
|
|
443
|
+
consequences?: PaddockPenaltyConsequence[];
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export type PaddockPenaltyConsequence =
|
|
447
|
+
| { type: 'warning' }
|
|
448
|
+
| { type: 'time'; seconds: number }
|
|
449
|
+
| { type: 'driveThrough'; conversionSeconds?: number }
|
|
450
|
+
| { type: 'stopGo'; seconds?: number; conversionSeconds?: number }
|
|
451
|
+
| { type: 'positionDrop'; positions: number }
|
|
452
|
+
| { type: 'gridDrop'; positions: number }
|
|
453
|
+
| { type: 'disqualification' };
|
|
454
|
+
|
|
455
|
+
export type PaddockPenaltyStatus = 'issued' | 'served' | 'applied' | 'cancelled';
|
|
456
|
+
|
|
457
|
+
export interface PaddockTrackLimitPenaltyRules extends PaddockPenaltySubsectionRules {
|
|
458
|
+
warningsBeforePenalty?: number;
|
|
459
|
+
relaxedMarginMeters?: number;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export interface PaddockCollisionPenaltyRules extends PaddockPenaltySubsectionRules {
|
|
463
|
+
minimumSeverity?: number;
|
|
464
|
+
relaxedSeverityMargin?: number;
|
|
465
|
+
minimumImpactSpeedKph?: number;
|
|
466
|
+
relaxedImpactSpeedKph?: number;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export interface PaddockPitLaneSpeedingPenaltyRules extends PaddockPenaltySubsectionRules {
|
|
470
|
+
speedLimitKph?: number;
|
|
471
|
+
marginKph?: number;
|
|
472
|
+
relaxedMarginKph?: number;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export interface PaddockPenaltyRules {
|
|
476
|
+
enabled?: boolean;
|
|
477
|
+
stewardStrictness?: number;
|
|
478
|
+
trackLimits?: PaddockTrackLimitPenaltyRules;
|
|
479
|
+
collision?: PaddockCollisionPenaltyRules;
|
|
480
|
+
tireRequirement?: PaddockPenaltySubsectionRules;
|
|
481
|
+
pitLaneSpeeding?: PaddockPitLaneSpeedingPenaltyRules;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export interface PaddockRaceModules {
|
|
485
|
+
pitStops?: PaddockPitStopRules;
|
|
486
|
+
tireStrategy?: PaddockTireStrategyRules;
|
|
487
|
+
penalties?: PaddockPenaltyRules;
|
|
488
|
+
weather?: { enabled?: boolean };
|
|
489
|
+
reliability?: { enabled?: boolean };
|
|
490
|
+
fuelLoad?: { enabled?: boolean };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export interface PaddockRaceRules {
|
|
494
|
+
ruleset?: PaddockRulesetName;
|
|
495
|
+
profile?: PaddockRulesetName;
|
|
496
|
+
modules?: PaddockRaceModules;
|
|
497
|
+
drsDetectionSeconds?: number;
|
|
498
|
+
safetyCarSpeed?: number;
|
|
499
|
+
safetyCarLeadDistance?: number;
|
|
500
|
+
safetyCarGap?: number;
|
|
501
|
+
collisionRestitution?: number;
|
|
502
|
+
standingStart?: boolean;
|
|
503
|
+
startLightCount?: number;
|
|
504
|
+
startLightInterval?: number;
|
|
505
|
+
startLightsOutHold?: number;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export interface PaddockPenaltyEntry {
|
|
509
|
+
id: string;
|
|
510
|
+
type: string;
|
|
511
|
+
at: number;
|
|
512
|
+
lap: number;
|
|
513
|
+
driverId: string;
|
|
514
|
+
strictness: number;
|
|
515
|
+
status: PaddockPenaltyStatus;
|
|
516
|
+
penaltySeconds: number;
|
|
517
|
+
pendingPenaltySeconds?: number;
|
|
518
|
+
consequences: PaddockPenaltyConsequence[];
|
|
519
|
+
serviceType?: 'driveThrough' | 'stopGo' | null;
|
|
520
|
+
serviceRequired?: boolean;
|
|
521
|
+
serviceServedAt?: number | null;
|
|
522
|
+
appliedAt?: number;
|
|
523
|
+
cancelledAt?: number;
|
|
524
|
+
unserved?: boolean;
|
|
525
|
+
positionDrop?: number;
|
|
526
|
+
gridDrop?: number;
|
|
527
|
+
disqualified?: boolean;
|
|
528
|
+
reason?: string;
|
|
529
|
+
otherCarId?: string;
|
|
530
|
+
aheadDriverId?: string;
|
|
531
|
+
atFaultDriverId?: string;
|
|
532
|
+
sharedFault?: boolean;
|
|
533
|
+
impactSpeedKph?: number;
|
|
534
|
+
impactSpeedThresholdKph?: number;
|
|
245
535
|
[key: string]: unknown;
|
|
246
536
|
}
|
|
247
537
|
|
|
538
|
+
export interface WheelSurfaceSnapshot {
|
|
539
|
+
id: string;
|
|
540
|
+
x: number;
|
|
541
|
+
y: number;
|
|
542
|
+
signedOffset: number;
|
|
543
|
+
crossTrackError: number;
|
|
544
|
+
surface: string;
|
|
545
|
+
onTrack: boolean;
|
|
546
|
+
inPitLane: boolean;
|
|
547
|
+
fullyOutsideWhiteLine: boolean;
|
|
548
|
+
}
|
|
549
|
+
|
|
248
550
|
export interface CarSnapshot {
|
|
249
551
|
id: string;
|
|
250
552
|
rank: number;
|
|
@@ -255,12 +557,32 @@ export interface CarSnapshot {
|
|
|
255
557
|
tire: TireCompound;
|
|
256
558
|
lap: number;
|
|
257
559
|
speedKph: number;
|
|
560
|
+
finishRank?: number | null;
|
|
561
|
+
status?: 'racing' | 'waved-flag' | string;
|
|
562
|
+
raceStatus?: 'racing' | 'waved-flag' | string;
|
|
563
|
+
wavedFlag?: boolean;
|
|
258
564
|
finished?: boolean;
|
|
259
565
|
finishTime?: number | null;
|
|
566
|
+
penaltySeconds?: number;
|
|
567
|
+
adjustedFinishTime?: number | null;
|
|
260
568
|
classifiedRank?: number | null;
|
|
261
569
|
intervalAheadSeconds?: number | null;
|
|
262
570
|
leaderGapSeconds?: number | null;
|
|
571
|
+
gapAheadLaps?: number;
|
|
572
|
+
intervalAheadLaps?: number;
|
|
573
|
+
leaderGapLaps?: number;
|
|
263
574
|
lapTelemetry?: LapTelemetrySnapshot;
|
|
575
|
+
surface?: string;
|
|
576
|
+
signedOffset?: number;
|
|
577
|
+
crossTrackError?: number;
|
|
578
|
+
inPitLane?: boolean;
|
|
579
|
+
wheels?: WheelSurfaceSnapshot[];
|
|
580
|
+
pitLanePart?: 'entry' | 'fast-lane' | 'working-lane' | 'exit' | 'service-box' | 'garage-box' | null;
|
|
581
|
+
pitBoxId?: string | null;
|
|
582
|
+
pitLaneCrossTrackError?: number | null;
|
|
583
|
+
usedTireCompounds?: Array<TireCompound | string>;
|
|
584
|
+
pitIntent?: PaddockPitIntent;
|
|
585
|
+
pitStop?: PitStopSnapshot | null;
|
|
264
586
|
[key: string]: unknown;
|
|
265
587
|
}
|
|
266
588
|
|
|
@@ -271,6 +593,12 @@ export interface RaceClassificationEntry {
|
|
|
271
593
|
lap: number;
|
|
272
594
|
finished: boolean;
|
|
273
595
|
finishTime?: number | null;
|
|
596
|
+
penaltySeconds?: number;
|
|
597
|
+
adjustedFinishTime?: number | null;
|
|
598
|
+
gapLaps?: number;
|
|
599
|
+
intervalLaps?: number;
|
|
600
|
+
positionDrop?: number;
|
|
601
|
+
disqualified?: boolean;
|
|
274
602
|
[key: string]: unknown;
|
|
275
603
|
}
|
|
276
604
|
|
|
@@ -285,6 +613,15 @@ export interface RaceSnapshot {
|
|
|
285
613
|
totalLaps: number;
|
|
286
614
|
raceControl: {
|
|
287
615
|
mode: string;
|
|
616
|
+
redFlag: boolean;
|
|
617
|
+
pitLaneOpen: boolean;
|
|
618
|
+
pitLaneStatus?: {
|
|
619
|
+
enabled: boolean;
|
|
620
|
+
open: boolean;
|
|
621
|
+
reason: string;
|
|
622
|
+
color: string;
|
|
623
|
+
light: string;
|
|
624
|
+
};
|
|
288
625
|
finished: boolean;
|
|
289
626
|
finishedAt: number | null;
|
|
290
627
|
winner: CarSnapshot | null;
|
|
@@ -294,12 +631,20 @@ export interface RaceSnapshot {
|
|
|
294
631
|
[key: string]: unknown;
|
|
295
632
|
};
|
|
296
633
|
};
|
|
634
|
+
pitLaneStatus?: {
|
|
635
|
+
enabled: boolean;
|
|
636
|
+
open: boolean;
|
|
637
|
+
reason: string;
|
|
638
|
+
color: string;
|
|
639
|
+
light: string;
|
|
640
|
+
};
|
|
297
641
|
safetyCar: {
|
|
298
642
|
deployed: boolean;
|
|
299
643
|
[key: string]: unknown;
|
|
300
644
|
};
|
|
301
|
-
rules:
|
|
645
|
+
rules: PaddockRaceRules;
|
|
302
646
|
events: RaceEvent[];
|
|
647
|
+
penalties: PaddockPenaltyEntry[];
|
|
303
648
|
cars: CarSnapshot[];
|
|
304
649
|
}
|
|
305
650
|
|
|
@@ -313,7 +658,7 @@ export interface F1SimulatorCallbacks {
|
|
|
313
658
|
onLoadingChange?: (state: { loading: boolean; phase: string }) => void;
|
|
314
659
|
onReady?: (payload: { snapshot: RaceSnapshot }) => void;
|
|
315
660
|
onError?: (error: unknown, context: LifecycleErrorContext) => void;
|
|
316
|
-
onDriverSelect?: (driver:
|
|
661
|
+
onDriverSelect?: (driver: NormalizedSimulatorDriver, snapshot: RaceSnapshot) => void;
|
|
317
662
|
onRaceEvent?: (event: RaceEvent, snapshot: RaceSnapshot) => void;
|
|
318
663
|
onLapChange?: (payload: {
|
|
319
664
|
previousLeaderLap: number | null;
|
|
@@ -341,6 +686,9 @@ export interface F1SimulatorExpertAction {
|
|
|
341
686
|
steering: number;
|
|
342
687
|
throttle: number;
|
|
343
688
|
brake: number;
|
|
689
|
+
pitIntent?: PaddockPitIntent;
|
|
690
|
+
pitCompound?: TireCompound | string;
|
|
691
|
+
pitTargetCompound?: TireCompound | string;
|
|
344
692
|
}
|
|
345
693
|
|
|
346
694
|
export interface F1SimulatorExpertApi {
|
|
@@ -360,6 +708,7 @@ export interface F1SimulatorOptions extends F1SimulatorCallbacks {
|
|
|
360
708
|
seed?: number;
|
|
361
709
|
trackSeed?: number;
|
|
362
710
|
totalLaps?: number;
|
|
711
|
+
rules?: PaddockRaceRules;
|
|
363
712
|
initialCameraMode?: CameraMode;
|
|
364
713
|
theme?: F1SimulatorTheme;
|
|
365
714
|
title?: string;
|
|
@@ -397,9 +746,16 @@ export interface F1MountedSimulator {
|
|
|
397
746
|
restart(nextOptions?: F1SimulatorRestartOptions): void;
|
|
398
747
|
selectDriver(driverId: string): void;
|
|
399
748
|
setSafetyCarDeployed(deployed: boolean): void;
|
|
749
|
+
setRedFlagDeployed(deployed: boolean): void;
|
|
750
|
+
setPitLaneOpen(open: boolean): void;
|
|
400
751
|
callSafetyCar(): void;
|
|
401
752
|
clearSafetyCar(): void;
|
|
402
753
|
toggleSafetyCar(): void;
|
|
754
|
+
setPitIntent(driverId: string, intent: PaddockPitIntentRequest, targetCompound?: TireCompound | string): boolean;
|
|
755
|
+
getPitIntent(driverId: string): PaddockPitIntent;
|
|
756
|
+
getPitTargetCompound(driverId: string): TireCompound | string | null;
|
|
757
|
+
servePenalty(penaltyId: string): PaddockPenaltyEntry | null;
|
|
758
|
+
cancelPenalty(penaltyId: string): PaddockPenaltyEntry | null;
|
|
403
759
|
getSnapshot(): RaceSnapshot | null;
|
|
404
760
|
}
|
|
405
761
|
|
|
@@ -426,9 +782,16 @@ export interface PaddockSimulatorController {
|
|
|
426
782
|
restart(nextOptions?: F1SimulatorRestartOptions): void;
|
|
427
783
|
selectDriver(driverId: string): void;
|
|
428
784
|
setSafetyCarDeployed(deployed: boolean): void;
|
|
785
|
+
setRedFlagDeployed(deployed: boolean): void;
|
|
786
|
+
setPitLaneOpen(open: boolean): void;
|
|
429
787
|
callSafetyCar(): void;
|
|
430
788
|
clearSafetyCar(): void;
|
|
431
789
|
toggleSafetyCar(): void;
|
|
790
|
+
setPitIntent(driverId: string, intent: PaddockPitIntentRequest, targetCompound?: TireCompound | string): boolean;
|
|
791
|
+
getPitIntent(driverId: string): PaddockPitIntent;
|
|
792
|
+
getPitTargetCompound(driverId: string): TireCompound | string | null;
|
|
793
|
+
servePenalty(penaltyId: string): PaddockPenaltyEntry | null;
|
|
794
|
+
cancelPenalty(penaltyId: string): PaddockPenaltyEntry | null;
|
|
432
795
|
getSnapshot(): RaceSnapshot | null;
|
|
433
796
|
}
|
|
434
797
|
|
package/src/index.js
CHANGED
|
@@ -109,6 +109,12 @@ export async function mountF1Simulator(root, options = {}) {
|
|
|
109
109
|
setSafetyCarDeployed(deployed) {
|
|
110
110
|
app.setSafetyCarDeployed(deployed);
|
|
111
111
|
},
|
|
112
|
+
setRedFlagDeployed(deployed) {
|
|
113
|
+
app.setRedFlagDeployed(deployed);
|
|
114
|
+
},
|
|
115
|
+
setPitLaneOpen(open) {
|
|
116
|
+
app.setPitLaneOpen(open);
|
|
117
|
+
},
|
|
112
118
|
callSafetyCar() {
|
|
113
119
|
app.setSafetyCarDeployed(true);
|
|
114
120
|
},
|
|
@@ -119,6 +125,21 @@ export async function mountF1Simulator(root, options = {}) {
|
|
|
119
125
|
const active = app.getSnapshot()?.raceControl.mode === 'safety-car';
|
|
120
126
|
app.setSafetyCarDeployed(!active);
|
|
121
127
|
},
|
|
128
|
+
setPitIntent(driverId, intent, targetCompound) {
|
|
129
|
+
return app.setPitIntent(driverId, intent, targetCompound);
|
|
130
|
+
},
|
|
131
|
+
getPitIntent(driverId) {
|
|
132
|
+
return app.getPitIntent(driverId);
|
|
133
|
+
},
|
|
134
|
+
getPitTargetCompound(driverId) {
|
|
135
|
+
return app.getPitTargetCompound(driverId);
|
|
136
|
+
},
|
|
137
|
+
servePenalty(penaltyId) {
|
|
138
|
+
return app.servePenalty(penaltyId);
|
|
139
|
+
},
|
|
140
|
+
cancelPenalty(penaltyId) {
|
|
141
|
+
return app.cancelPenalty(penaltyId);
|
|
142
|
+
},
|
|
122
143
|
getSnapshot() {
|
|
123
144
|
return app.getSnapshot();
|
|
124
145
|
},
|