@vgai/live 0.5.39 → 0.5.41
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.
|
@@ -226,6 +226,15 @@ export declare class GameClient {
|
|
|
226
226
|
providers(): Promise<ProviderInfo[]>;
|
|
227
227
|
commands(): Promise<DebugCommandInfo[]>;
|
|
228
228
|
snapshot(sinceSeq?: number): Promise<DebugSnapshot>;
|
|
229
|
+
/**
|
|
230
|
+
* Read only the simulation clock for a predicate-free wait.
|
|
231
|
+
*
|
|
232
|
+
* `snapshot()` intentionally batches every declared provider for `waitFor`, whose predicate may
|
|
233
|
+
* read any of them. `waitSimTime` has no predicate: serializing a large `unity` provider every
|
|
234
|
+
* 150ms can itself consume multiple frames and corrupt the performance window it is advancing.
|
|
235
|
+
* Keep the two hardening observers fed exactly as an ordinary snapshot does.
|
|
236
|
+
*/
|
|
237
|
+
private readTime;
|
|
229
238
|
/** Fixture-teardown perf read: p50/p95 effective ticks-per-second over all
|
|
230
239
|
* the snapshot polls this test performed. */
|
|
231
240
|
tpsStats(): TpsStats;
|
|
@@ -504,6 +504,20 @@ export class GameClient {
|
|
|
504
504
|
await this.#hiddenRecovery.observeTick(snap.time.tick);
|
|
505
505
|
return snap;
|
|
506
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Read only the simulation clock for a predicate-free wait.
|
|
509
|
+
*
|
|
510
|
+
* `snapshot()` intentionally batches every declared provider for `waitFor`, whose predicate may
|
|
511
|
+
* read any of them. `waitSimTime` has no predicate: serializing a large `unity` provider every
|
|
512
|
+
* 150ms can itself consume multiple frames and corrupt the performance window it is advancing.
|
|
513
|
+
* Keep the two hardening observers fed exactly as an ordinary snapshot does.
|
|
514
|
+
*/
|
|
515
|
+
async readTime() {
|
|
516
|
+
const time = await this.callBridge('state', 'time');
|
|
517
|
+
this.#tps.record(time.tick, Date.now());
|
|
518
|
+
await this.#hiddenRecovery.observeTick(time.tick);
|
|
519
|
+
return time;
|
|
520
|
+
}
|
|
507
521
|
/** Fixture-teardown perf read: p50/p95 effective ticks-per-second over all
|
|
508
522
|
* the snapshot polls this test performed. */
|
|
509
523
|
tpsStats() {
|
|
@@ -622,12 +636,15 @@ export class GameClient {
|
|
|
622
636
|
// goes heartbeat-silent well before this loop's own guard ever needs to.
|
|
623
637
|
let heartbeat = { lastEmitWallMs: startWall, lastEmitTick: start.time.tick };
|
|
624
638
|
for (;;) {
|
|
625
|
-
const
|
|
626
|
-
if (
|
|
639
|
+
const currentTime = await this.readTime();
|
|
640
|
+
if (currentTime.simSeconds - start.time.simSeconds >= budget.simSeconds)
|
|
627
641
|
return;
|
|
628
|
-
stalledPolls = lastTick !== null &&
|
|
629
|
-
lastTick =
|
|
642
|
+
stalledPolls = lastTick !== null && currentTime.tick === lastTick ? stalledPolls + 1 : 0;
|
|
643
|
+
lastTick = currentTime.tick;
|
|
630
644
|
if (stalledPolls >= WAIT_FOR_STALL_POLL_LIMIT) {
|
|
645
|
+
// Failure diagnostics still carry one honest complete terminal snapshot. The hot path above
|
|
646
|
+
// stays clock-only; the expensive provider batch is paid only when it will be printed.
|
|
647
|
+
const current = await this.snapshot();
|
|
631
648
|
throw await this.toSessionFailure(new WaitForTimeoutError({
|
|
632
649
|
budget,
|
|
633
650
|
startSnapshot: start,
|
|
@@ -639,8 +656,8 @@ export class GameClient {
|
|
|
639
656
|
}
|
|
640
657
|
const heartbeatResult = maybeHeartbeat({
|
|
641
658
|
nowMs: Date.now(),
|
|
642
|
-
tick:
|
|
643
|
-
simSeconds:
|
|
659
|
+
tick: currentTime.tick,
|
|
660
|
+
simSeconds: currentTime.simSeconds,
|
|
644
661
|
testTitle: this.#testTitle,
|
|
645
662
|
state: heartbeat,
|
|
646
663
|
});
|
|
@@ -171,7 +171,10 @@ export class RelayTransport {
|
|
|
171
171
|
}
|
|
172
172
|
async call(method, callArgs) {
|
|
173
173
|
const hidden = await this.preflightHidden();
|
|
174
|
-
|
|
174
|
+
// A predicate-free `waitSimTime` poll reads only the `time` provider. It needs the same hidden
|
|
175
|
+
// tab deterministic driver as a full snapshot or a hidden editor would freeze that lighter
|
|
176
|
+
// clock read forever.
|
|
177
|
+
if (method === 'snapshot' || (method === 'state' && callArgs[0] === 'time')) {
|
|
175
178
|
if (hidden) {
|
|
176
179
|
const now = Date.now();
|
|
177
180
|
const elapsed = this.hiddenDriveLastWallMs === null ? 1000 / 60 : now - this.hiddenDriveLastWallMs;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@vgai/live",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.41",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"prepack": "npm run build"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@vgai/editor-sdk": "0.5.
|
|
36
|
-
"@vgai/sdk": "0.5.
|
|
35
|
+
"@vgai/editor-sdk": "0.5.41",
|
|
36
|
+
"@vgai/sdk": "0.5.41"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@playwright/test": ">=1.58.2 <2"
|
|
@@ -628,6 +628,21 @@ export class GameClient {
|
|
|
628
628
|
return snap;
|
|
629
629
|
}
|
|
630
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Read only the simulation clock for a predicate-free wait.
|
|
633
|
+
*
|
|
634
|
+
* `snapshot()` intentionally batches every declared provider for `waitFor`, whose predicate may
|
|
635
|
+
* read any of them. `waitSimTime` has no predicate: serializing a large `unity` provider every
|
|
636
|
+
* 150ms can itself consume multiple frames and corrupt the performance window it is advancing.
|
|
637
|
+
* Keep the two hardening observers fed exactly as an ordinary snapshot does.
|
|
638
|
+
*/
|
|
639
|
+
private async readTime(): Promise<DebugSnapshot['time']> {
|
|
640
|
+
const time = await this.callBridge<DebugSnapshot['time']>('state', 'time');
|
|
641
|
+
this.#tps.record(time.tick, Date.now());
|
|
642
|
+
await this.#hiddenRecovery.observeTick(time.tick);
|
|
643
|
+
return time;
|
|
644
|
+
}
|
|
645
|
+
|
|
631
646
|
/** Fixture-teardown perf read: p50/p95 effective ticks-per-second over all
|
|
632
647
|
* the snapshot polls this test performed. */
|
|
633
648
|
tpsStats(): TpsStats {
|
|
@@ -755,11 +770,14 @@ export class GameClient {
|
|
|
755
770
|
// goes heartbeat-silent well before this loop's own guard ever needs to.
|
|
756
771
|
let heartbeat: HeartbeatState = { lastEmitWallMs: startWall, lastEmitTick: start.time.tick };
|
|
757
772
|
for (;;) {
|
|
758
|
-
const
|
|
759
|
-
if (
|
|
760
|
-
stalledPolls = lastTick !== null &&
|
|
761
|
-
lastTick =
|
|
773
|
+
const currentTime = await this.readTime();
|
|
774
|
+
if (currentTime.simSeconds - start.time.simSeconds >= budget.simSeconds) return;
|
|
775
|
+
stalledPolls = lastTick !== null && currentTime.tick === lastTick ? stalledPolls + 1 : 0;
|
|
776
|
+
lastTick = currentTime.tick;
|
|
762
777
|
if (stalledPolls >= WAIT_FOR_STALL_POLL_LIMIT) {
|
|
778
|
+
// Failure diagnostics still carry one honest complete terminal snapshot. The hot path above
|
|
779
|
+
// stays clock-only; the expensive provider batch is paid only when it will be printed.
|
|
780
|
+
const current = await this.snapshot();
|
|
763
781
|
throw await this.toSessionFailure(
|
|
764
782
|
new WaitForTimeoutError({
|
|
765
783
|
budget,
|
|
@@ -774,8 +792,8 @@ export class GameClient {
|
|
|
774
792
|
}
|
|
775
793
|
const heartbeatResult = maybeHeartbeat({
|
|
776
794
|
nowMs: Date.now(),
|
|
777
|
-
tick:
|
|
778
|
-
simSeconds:
|
|
795
|
+
tick: currentTime.tick,
|
|
796
|
+
simSeconds: currentTime.simSeconds,
|
|
779
797
|
testTitle: this.#testTitle,
|
|
780
798
|
state: heartbeat,
|
|
781
799
|
});
|
|
@@ -232,7 +232,10 @@ export class RelayTransport implements BridgeTransport {
|
|
|
232
232
|
|
|
233
233
|
async call(method: string, callArgs: unknown[]): Promise<BridgeCallOutcome> {
|
|
234
234
|
const hidden = await this.preflightHidden();
|
|
235
|
-
|
|
235
|
+
// A predicate-free `waitSimTime` poll reads only the `time` provider. It needs the same hidden
|
|
236
|
+
// tab deterministic driver as a full snapshot or a hidden editor would freeze that lighter
|
|
237
|
+
// clock read forever.
|
|
238
|
+
if (method === 'snapshot' || (method === 'state' && callArgs[0] === 'time')) {
|
|
236
239
|
if (hidden) {
|
|
237
240
|
const now = Date.now();
|
|
238
241
|
const elapsed =
|