A test that waits for a deadline somebody guessed is waiting for the wrong thing, so it waits for the editor (#93)
game-maker / suite (push) Successful in 6m48s
game-maker / suite (push) Successful in 6m48s
The suite spent 88% of its step time asleep: 564 s of steps, 496 s of
them in sleep(n) - fixed spans estimated by hand and then copied from
step to step. That is why it was slow, and why it flickered.
The signal is afterFrames(count, timeout) in ui/render.ts, exposed as
__gm.afterFrames(). It wakes the loop itself, because an editor that
draws nothing would never redeem a promise of a frame, and it gives up
after a timeout instead of hanging the run. settle() in the harness
waits two drawn frames (~32 ms) instead of 150-300 ms and falls back to
sleep(150) when the hook is missing (an old build): silently not
waiting would make every later check a coin toss.
Every action goes through it now - click, doubleClick, wheel, drag,
dragAsset, press, typeText, select, mutate, undo, redo - and with that
about 550 sleep() calls behind those actions became redundant, helpers
that are nothing but a mutate in a coat included. What a frame cannot
answer got its own condition instead: waitUntil(expr), play()/stop()
waiting on __gm.state.mode rather than on 300 ms, saved() for the
autosave (the two hand-written polling loops sampled at 300 ms for
something that arrives after a second), and showTab() as a real tool -
47 places called evaluate("__gm.showTab(...)") raw, and 24 of them
waited for nothing at all and read the old panel.
564 s -> 243 s of step time, the waiting share 88% -> 76%. Three kinds
of wait were kept, and each one bit when it was taken away: loading
bytes (textures, fonts), game time that a repaint cannot stand in for
(time scale, shader and particle clocks, the live values a running
graph carries), and the inertia the scroll step measures on purpose.
Two things the new speed uncovered, both real: 25-animation read the
frame menu unfiltered and had frozen an incomplete list (the CI failure
on c990dbc), and 33-render-on-change measured idleness while the
autosave of the step before was still painting - it waits for
saveStatus to leave dirty/saving now, so it measures that nothing
happens any more instead of that it waited long enough.
This commit is contained in:
1 parent
c990dbcb26
commit
7e5003b590
41 files changed
+362
-732
No files matched your search
+4
-14
@@ -46,6 +46,7 @@ export async function pause(t) {
|
||||
select,
|
||||
evaluate,
|
||||
asset,
|
||||
showTab,
|
||||
} = t;
|
||||
const playInfo = () => json('__gm.playInfo()');
|
||||
const boxX = async () => (await entity('p-box'))?.x ?? NaN;
|
||||
@@ -78,7 +79,6 @@ export async function pause(t) {
|
||||
// 18b. The toolbar button holds it. Both the clock and the box have to stop – a world that keeps
|
||||
// ticking while the picture happens to look the same would pass a position check alone.
|
||||
await clickText('❚❚ Pause');
|
||||
await sleep(200);
|
||||
const held = await playInfo();
|
||||
const heldX = await boxX();
|
||||
await sleep(1000);
|
||||
@@ -108,11 +108,9 @@ export async function pause(t) {
|
||||
const hitsWhilePaused = await keyHits();
|
||||
await press('ArrowRight');
|
||||
await press('ArrowRight');
|
||||
await sleep(200);
|
||||
|
||||
// 18d. Ctrl+Enter resumes, the same shortcut that started play.
|
||||
await press('Enter', { ctrl: true });
|
||||
await sleep(400);
|
||||
const resumed = await playInfo();
|
||||
const resumedX = await boxX();
|
||||
check(
|
||||
@@ -132,7 +130,6 @@ export async function pause(t) {
|
||||
);
|
||||
// Without this the check above would also pass on a graph that never logs anything at all.
|
||||
await press('ArrowRight');
|
||||
await sleep(300);
|
||||
check(
|
||||
'the same key does fire once the game is running again',
|
||||
(await keyHits()) === hitsBefore + 1,
|
||||
@@ -142,7 +139,6 @@ export async function pause(t) {
|
||||
// 18e. A hold must never outlive its play: Esc stops from a paused game, and the next run starts
|
||||
// moving. A pause left standing would leave the editor unable to run anything.
|
||||
await press('Enter', { ctrl: true });
|
||||
await sleep(200);
|
||||
check('Ctrl+Enter holds it again', (await playInfo()).paused === true);
|
||||
await stop();
|
||||
const afterStop = await playInfo();
|
||||
@@ -162,7 +158,9 @@ export async function pause(t) {
|
||||
// 18f. The graph stays editable while the game runs, with the mouse as in edit mode: a click
|
||||
// selects the Move node, Delete removes it, and the running world stops drifting the box.
|
||||
await select({ kind: 'asset', assetId: 'pauser' });
|
||||
await evaluate(`__gm.showTab('graph')`);
|
||||
await showTab('graph');
|
||||
// The live values are not drawn, they are carried: the running graph has to execute once while
|
||||
// this tab is open before a node output holds anything. That is game time, not frames.
|
||||
await sleep(150);
|
||||
const outputs = (id) => json(`__gm.graph.nodeOutputs(${JSON.stringify(id)})`);
|
||||
const live = {
|
||||
@@ -193,7 +191,6 @@ export async function pause(t) {
|
||||
);
|
||||
const beforeKey = await beadsOn('p-e4');
|
||||
await press('ArrowRight');
|
||||
await sleep(80);
|
||||
const onKey = await beadsOn('p-e4');
|
||||
await sleep(500);
|
||||
const afterKey = await beadsOn('p-e4');
|
||||
@@ -204,7 +201,6 @@ export async function pause(t) {
|
||||
);
|
||||
const movePos = await json(`__gm.graph.nodeAt('p-move')`);
|
||||
await click(movePos.x, movePos.y);
|
||||
await sleep(100);
|
||||
check(
|
||||
'a click selects a node while playing',
|
||||
JSON.stringify(await json('__gm.graph.selected()')) === '["p-move"]',
|
||||
@@ -212,17 +208,14 @@ export async function pause(t) {
|
||||
);
|
||||
const area = await json('__gm.graph.canvasRect()');
|
||||
await click(area.x + area.w - 15, area.y + area.h - 15, 'right');
|
||||
await sleep(100);
|
||||
check('right-clicking the canvas opens the node palette while playing', await has('Search nodes…'));
|
||||
await press('Escape');
|
||||
await sleep(100);
|
||||
check(
|
||||
'Escape closes the palette and leaves the game running',
|
||||
!(await has('Search nodes…')) && (await playInfo()).playing === true,
|
||||
);
|
||||
await click(movePos.x, movePos.y);
|
||||
await press('Delete');
|
||||
await sleep(150);
|
||||
const stoppedAt = await boxX();
|
||||
await sleep(500);
|
||||
check(
|
||||
@@ -232,7 +225,6 @@ export async function pause(t) {
|
||||
`x ${stoppedAt} → ${await boxX()}`,
|
||||
);
|
||||
await stop();
|
||||
await sleep(200);
|
||||
check(
|
||||
'stopping takes the values off the nodes',
|
||||
JSON.stringify(await outputs('p-owner')) === '["object"]',
|
||||
@@ -267,7 +259,6 @@ export async function pause(t) {
|
||||
await sleep(400);
|
||||
const runningClock = await clock();
|
||||
await clickText('❚❚ Pause');
|
||||
await sleep(150);
|
||||
const heldClock = await clock();
|
||||
await sleep(800);
|
||||
const stillHeldClock = await clock();
|
||||
@@ -283,7 +274,6 @@ export async function pause(t) {
|
||||
// Twice the scale has to move the clock and the world by the same factor: the delta a behavior
|
||||
// reads is the step the clock took, not a second measurement of the wall clock.
|
||||
await press('Enter', { ctrl: true });
|
||||
await sleep(150);
|
||||
const slowFrom = { t: await clock(), x: await boxX() };
|
||||
await sleep(600);
|
||||
const slowTo = { t: await clock(), x: await boxX() };
|
||||
|
||||
Reference in new issue
Block a user