@bitmagic/cli 0.1.35 → 0.1.37
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/README.md +4 -2
- package/dist/commands/forge.js +39 -26
- package/dist/commands/forge.js.map +1 -1
- package/dist/editor/server.js +6 -3
- package/dist/editor/server.js.map +1 -1
- package/dist/editor/shell-page.js +122 -4
- package/dist/editor/shell-page.js.map +1 -1
- package/dist/forge/browser-host.d.ts +0 -10
- package/dist/forge/browser-host.js +0 -12
- package/dist/forge/browser-host.js.map +1 -1
- package/dist/forge/progress.d.ts +80 -0
- package/dist/forge/progress.js +158 -0
- package/dist/forge/progress.js.map +1 -0
- package/dist/forge/run-pipeline.d.ts +11 -2
- package/dist/forge/run-pipeline.js +9 -7
- package/dist/forge/run-pipeline.js.map +1 -1
- package/dist/forge/stream.d.ts +14 -3
- package/dist/forge/stream.js +62 -9
- package/dist/forge/stream.js.map +1 -1
- package/dist/forge/transport.js +14 -3
- package/dist/forge/transport.js.map +1 -1
- package/dist/project/jobs.d.ts +34 -1
- package/dist/project/jobs.js +85 -7
- package/dist/project/jobs.js.map +1 -1
- package/dist/scaffold/project-files.js +6 -6
- package/package.json +3 -3
- package/dist/forge/bake-progress.d.ts +0 -44
- package/dist/forge/bake-progress.js +0 -77
- package/dist/forge/bake-progress.js.map +0 -1
package/dist/project/jobs.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ForgeProgressSnapshot } from '../forge/progress.js';
|
|
1
2
|
/** Which command is running. Shown as-is in the dev view, so these are creator-facing words. */
|
|
2
3
|
export type JobKind = 'skybox' | 'sound' | 'image' | 'character' | 'animation' | 'prop' | 'vehicle' | 'forge' | 'cover' | 'hq';
|
|
3
4
|
export interface JobRecord {
|
|
@@ -10,6 +11,16 @@ export interface JobRecord {
|
|
|
10
11
|
status: 'running' | 'failed';
|
|
11
12
|
/** The generation's most recent progress line. See `withJobRecord`. */
|
|
12
13
|
message: string;
|
|
14
|
+
/**
|
|
15
|
+
* Structured progress, for the one kind that has any: a forge's five steps, how far through the
|
|
16
|
+
* current one is, and what the level being built contains.
|
|
17
|
+
*
|
|
18
|
+
* Optional because it is a forge-only enrichment of {@link message}, never a replacement for it —
|
|
19
|
+
* every other kind has a single sentence and nothing more to say, and a reader (a `bitmagic dev`
|
|
20
|
+
* from an older install, or the creator's agent reading this directory by hand) must still make
|
|
21
|
+
* sense of a record without it.
|
|
22
|
+
*/
|
|
23
|
+
progress?: ForgeProgressSnapshot;
|
|
13
24
|
pid: number;
|
|
14
25
|
startedAt: string;
|
|
15
26
|
updatedAt: string;
|
|
@@ -26,6 +37,18 @@ export declare function jobsDirPath(root: string): string;
|
|
|
26
37
|
* not worth failing a read that also carries five healthy ones.
|
|
27
38
|
*/
|
|
28
39
|
export declare function readJobs(root: string): JobRecord[];
|
|
40
|
+
/**
|
|
41
|
+
* What the dev view shows: the generations still working.
|
|
42
|
+
*
|
|
43
|
+
* A failed job leaves the panel exactly the way a successful one does — by disappearing — and the
|
|
44
|
+
* difference between them shows up where it means something to the person seeing it. The creator
|
|
45
|
+
* gets an asset, or does not; the agent gets the reason, on the terminal where it can act on it.
|
|
46
|
+
* See the header for why the reason does not belong in both places.
|
|
47
|
+
*
|
|
48
|
+
* Dead `running` records drop out here too, because `readJobs` reports them as failed. That is what
|
|
49
|
+
* stops a SIGKILLed generation spinning in the panel for the rest of the session.
|
|
50
|
+
*/
|
|
51
|
+
export declare function readRunningJobs(root: string): JobRecord[];
|
|
29
52
|
/**
|
|
30
53
|
* Drop failed records older than a day. Called by `dev` at startup rather than on a timer: this is
|
|
31
54
|
* housekeeping, and the moment someone opens the dev view is the moment a day-old failure stops
|
|
@@ -36,7 +59,11 @@ export interface JobHandle {
|
|
|
36
59
|
readonly jobId: string;
|
|
37
60
|
/** Record the latest progress line. */
|
|
38
61
|
update(message: string): void;
|
|
62
|
+
/** Record structured progress alongside the line. Only a forge has any; see {@link JobRecord}. */
|
|
63
|
+
setProgress(progress: ForgeProgressSnapshot): void;
|
|
39
64
|
}
|
|
65
|
+
/** What a body reports structured progress through. A no-op when the record could not be started. */
|
|
66
|
+
export type JobProgressReporter = (progress: ForgeProgressSnapshot) => void;
|
|
40
67
|
export interface StartJobOptions {
|
|
41
68
|
root: string;
|
|
42
69
|
kind: JobKind;
|
|
@@ -53,6 +80,12 @@ export declare function startJob(options: StartJobOptions): JobHandle;
|
|
|
53
80
|
* way since it shipped, and it means a command gains live progress in the dev view without a single
|
|
54
81
|
* new call site inside it.
|
|
55
82
|
*
|
|
83
|
+
* The SECOND argument is for the one command that has more than a sentence to say. A forge runs
|
|
84
|
+
* for half an hour across five steps on two machines, and a line-at-a-time record can only ever
|
|
85
|
+
* show the most recent one — so `forge` also reports a snapshot of all five (see
|
|
86
|
+
* `forge/progress.ts`). Every other caller ignores this parameter, which is the point: the log tap
|
|
87
|
+
* above stays the default, and structured progress is opt-in for the kind that needs it.
|
|
88
|
+
*
|
|
56
89
|
* **Never fails the generation it is watching.** Bookkeeping that breaks a paid, minutes-long
|
|
57
90
|
* generation would be a far worse bug than the missing progress line it is trying to provide, so
|
|
58
91
|
* every filesystem error here is swallowed. The body's own errors propagate untouched, after being
|
|
@@ -60,7 +93,7 @@ export declare function startJob(options: StartJobOptions): JobHandle;
|
|
|
60
93
|
*/
|
|
61
94
|
export declare function withJobRecord<T>(options: StartJobOptions & {
|
|
62
95
|
log: (message: string) => void;
|
|
63
|
-
}, body: (log: (message: string) => void) => Promise<T>): Promise<T>;
|
|
96
|
+
}, body: (log: (message: string) => void, report: JobProgressReporter) => Promise<T>): Promise<T>;
|
|
64
97
|
/** Success: the asset is in world.json, and that is the record. */
|
|
65
98
|
export declare function removeJob(root: string, jobId: string): void;
|
|
66
99
|
/** Failure: nothing else records it, so the record stays and carries the reason. */
|
package/dist/project/jobs.js
CHANGED
|
@@ -19,14 +19,21 @@
|
|
|
19
19
|
* `cat` this directory to see what it has in flight. The dev sidecar watches the directory, so the
|
|
20
20
|
* latency is a filesystem event, not a poll.
|
|
21
21
|
*
|
|
22
|
-
* ── Removed on success, kept on failure
|
|
22
|
+
* ── Removed on success, kept on failure — and a failure is for the agent, not the creator ────
|
|
23
23
|
*
|
|
24
24
|
* A finished asset is in `world.json`, and that IS the completion record — the browser reloads
|
|
25
25
|
* because the file changed, and the asset appears in the panel. A record left behind saying "done"
|
|
26
26
|
* would be a second, staler source of truth for the same fact.
|
|
27
27
|
*
|
|
28
|
-
* A
|
|
29
|
-
*
|
|
28
|
+
* A failed record is kept, but the dev view does not render it. What a generation fails with is a
|
|
29
|
+
* tool diagnostic — `Unknown preset "?". Valid: SEDAN, HATCHBACK, …` — addressed to whoever chose
|
|
30
|
+
* the arguments, actionable only by them, and already printed on their terminal by the command that
|
|
31
|
+
* exited non-zero. In an agent-driven session that reader is the agent. Repeating the same text as a
|
|
32
|
+
* red card beside the creator's game hands them an enum list they can do nothing with, in the one
|
|
33
|
+
* window that is supposed to be about the game rather than the toolchain.
|
|
34
|
+
*
|
|
35
|
+
* So `readRunningJobs` is what the sidecar serves, and the record stays on disk for the agent to
|
|
36
|
+
* `cat` and for `pruneJobs` to age out.
|
|
30
37
|
*
|
|
31
38
|
* ── Staleness is the reader's problem ────────────────────────────────────────────────────────
|
|
32
39
|
*
|
|
@@ -43,7 +50,7 @@ import * as fs from 'fs';
|
|
|
43
50
|
import * as path from 'path';
|
|
44
51
|
import { isProcessAlive, readDevHandle } from './dev-handle.js';
|
|
45
52
|
export const JOBS_DIR = path.join('.bitmagic', 'jobs');
|
|
46
|
-
/** Failed records are kept
|
|
53
|
+
/** Failed records are kept for the agent to read back — but not forever. */
|
|
47
54
|
const FAILED_RECORD_TTL_MS = 24 * 60 * 60 * 1000;
|
|
48
55
|
export function jobsDirPath(root) {
|
|
49
56
|
return path.join(root, JOBS_DIR);
|
|
@@ -76,6 +83,40 @@ function writeRecord(root, record) {
|
|
|
76
83
|
function isRecord(value) {
|
|
77
84
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
78
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Read a progress snapshot off a record, or `undefined` when there is not a well-formed one.
|
|
88
|
+
*
|
|
89
|
+
* These files cross a process boundary and a VERSION boundary — the writer is whichever
|
|
90
|
+
* `bitmagic` binary started the generation, the reader is whichever `bitmagic dev` happens to be
|
|
91
|
+
* running — so the field is treated as untrusted input rather than as something this build wrote.
|
|
92
|
+
* Dropping it is the right degradation and matches the rest of this file: the record still carries
|
|
93
|
+
* its `message`, so a reader that cannot make sense of the steps falls back to the sentence.
|
|
94
|
+
*
|
|
95
|
+
* `summary` is passed through unshaped on purpose. It is display-only, every field is optional,
|
|
96
|
+
* and its contents are the pipeline's schema, not this file's — re-deriving that shape here would
|
|
97
|
+
* be a second copy to keep in step for no invariant worth protecting.
|
|
98
|
+
*/
|
|
99
|
+
function parseProgress(value) {
|
|
100
|
+
if (!isRecord(value) || !Array.isArray(value.steps))
|
|
101
|
+
return undefined;
|
|
102
|
+
const steps = value.steps.filter((step) => isRecord(step) && typeof step.key === 'string' && typeof step.label === 'string'
|
|
103
|
+
&& (step.status === 'pending' || step.status === 'running' || step.status === 'done'));
|
|
104
|
+
if (steps.length === 0)
|
|
105
|
+
return undefined;
|
|
106
|
+
return {
|
|
107
|
+
steps: steps.map((step) => ({
|
|
108
|
+
key: step.key,
|
|
109
|
+
label: step.label,
|
|
110
|
+
status: step.status,
|
|
111
|
+
...(typeof step.durationMs === 'number' ? { durationMs: step.durationMs } : {}),
|
|
112
|
+
...(typeof step.completed === 'number' ? { completed: step.completed } : {}),
|
|
113
|
+
...(typeof step.total === 'number' ? { total: step.total } : {}),
|
|
114
|
+
...(typeof step.detail === 'string' ? { detail: step.detail } : {}),
|
|
115
|
+
...(step.resumed === true ? { resumed: true } : {}),
|
|
116
|
+
})),
|
|
117
|
+
...(isRecord(value.summary) ? { summary: value.summary } : {}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
79
120
|
function parseRecord(raw) {
|
|
80
121
|
let parsed;
|
|
81
122
|
try {
|
|
@@ -89,6 +130,7 @@ function parseRecord(raw) {
|
|
|
89
130
|
const { jobId, kind, label, status, message, pid, startedAt, updatedAt } = parsed;
|
|
90
131
|
if (typeof jobId !== 'string' || typeof kind !== 'string' || typeof pid !== 'number')
|
|
91
132
|
return null;
|
|
133
|
+
const progress = parseProgress(parsed.progress);
|
|
92
134
|
return {
|
|
93
135
|
jobId,
|
|
94
136
|
kind: kind,
|
|
@@ -96,6 +138,7 @@ function parseRecord(raw) {
|
|
|
96
138
|
...(typeof parsed.assetId === 'string' ? { assetId: parsed.assetId } : {}),
|
|
97
139
|
status: status === 'failed' ? 'failed' : 'running',
|
|
98
140
|
message: typeof message === 'string' ? message : '',
|
|
141
|
+
...(progress ? { progress } : {}),
|
|
99
142
|
pid,
|
|
100
143
|
startedAt: typeof startedAt === 'string' ? startedAt : '',
|
|
101
144
|
updatedAt: typeof updatedAt === 'string' ? updatedAt : '',
|
|
@@ -144,6 +187,20 @@ export function readJobs(root) {
|
|
|
144
187
|
}
|
|
145
188
|
return jobs.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
|
|
146
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* What the dev view shows: the generations still working.
|
|
192
|
+
*
|
|
193
|
+
* A failed job leaves the panel exactly the way a successful one does — by disappearing — and the
|
|
194
|
+
* difference between them shows up where it means something to the person seeing it. The creator
|
|
195
|
+
* gets an asset, or does not; the agent gets the reason, on the terminal where it can act on it.
|
|
196
|
+
* See the header for why the reason does not belong in both places.
|
|
197
|
+
*
|
|
198
|
+
* Dead `running` records drop out here too, because `readJobs` reports them as failed. That is what
|
|
199
|
+
* stops a SIGKILLed generation spinning in the panel for the rest of the session.
|
|
200
|
+
*/
|
|
201
|
+
export function readRunningJobs(root) {
|
|
202
|
+
return readJobs(root).filter((job) => job.status === 'running');
|
|
203
|
+
}
|
|
147
204
|
/**
|
|
148
205
|
* Drop failed records older than a day. Called by `dev` at startup rather than on a timer: this is
|
|
149
206
|
* housekeeping, and the moment someone opens the dev view is the moment a day-old failure stops
|
|
@@ -227,12 +284,19 @@ export function startJob(options) {
|
|
|
227
284
|
updatedAt: now,
|
|
228
285
|
};
|
|
229
286
|
writeRecord(options.root, record);
|
|
287
|
+
const touch = () => {
|
|
288
|
+
record.updatedAt = new Date().toISOString();
|
|
289
|
+
writeRecord(options.root, record);
|
|
290
|
+
};
|
|
230
291
|
return {
|
|
231
292
|
jobId: record.jobId,
|
|
232
293
|
update: (message) => {
|
|
233
294
|
record.message = message;
|
|
234
|
-
|
|
235
|
-
|
|
295
|
+
touch();
|
|
296
|
+
},
|
|
297
|
+
setProgress: (progress) => {
|
|
298
|
+
record.progress = progress;
|
|
299
|
+
touch();
|
|
236
300
|
},
|
|
237
301
|
};
|
|
238
302
|
}
|
|
@@ -245,6 +309,12 @@ export function startJob(options) {
|
|
|
245
309
|
* way since it shipped, and it means a command gains live progress in the dev view without a single
|
|
246
310
|
* new call site inside it.
|
|
247
311
|
*
|
|
312
|
+
* The SECOND argument is for the one command that has more than a sentence to say. A forge runs
|
|
313
|
+
* for half an hour across five steps on two machines, and a line-at-a-time record can only ever
|
|
314
|
+
* show the most recent one — so `forge` also reports a snapshot of all five (see
|
|
315
|
+
* `forge/progress.ts`). Every other caller ignores this parameter, which is the point: the log tap
|
|
316
|
+
* above stays the default, and structured progress is opt-in for the kind that needs it.
|
|
317
|
+
*
|
|
248
318
|
* **Never fails the generation it is watching.** Bookkeeping that breaks a paid, minutes-long
|
|
249
319
|
* generation would be a far worse bug than the missing progress line it is trying to provide, so
|
|
250
320
|
* every filesystem error here is swallowed. The body's own errors propagate untouched, after being
|
|
@@ -268,8 +338,16 @@ export async function withJobRecord(options, body) {
|
|
|
268
338
|
// Same.
|
|
269
339
|
}
|
|
270
340
|
};
|
|
341
|
+
const report = (progress) => {
|
|
342
|
+
try {
|
|
343
|
+
handle?.setProgress(progress);
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
// Same.
|
|
347
|
+
}
|
|
348
|
+
};
|
|
271
349
|
try {
|
|
272
|
-
const result = await body(log);
|
|
350
|
+
const result = await body(log, report);
|
|
273
351
|
if (handle)
|
|
274
352
|
removeJob(options.root, handle.jobId);
|
|
275
353
|
return result;
|
package/dist/project/jobs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../src/project/jobs.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../src/project/jobs.ts"],"names":[],"mappings":"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"}
|
|
@@ -554,12 +554,12 @@ alone:
|
|
|
554
554
|
- **An image pasted into the conversation is probably a frame from their running game.** The dev
|
|
555
555
|
view has a Screenshot button that copies the current frame to the clipboard, so "look at this"
|
|
556
556
|
usually means the game as it is right now — not a reference or a mock-up.
|
|
557
|
-
- **They can watch your generations happen.** Every \`bitmagic generate\`
|
|
558
|
-
records itself in \`.bitmagic/jobs/\` while it runs, and the dev view lists
|
|
559
|
-
progress lines and the prompt you used.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
a forge and a prop each want a headless browser and will fight over one.
|
|
557
|
+
- **They can watch your generations happen — but not your failures.** Every \`bitmagic generate\`
|
|
558
|
+
and \`bitmagic forge\` records itself in \`.bitmagic/jobs/\` while it runs, and the dev view lists
|
|
559
|
+
those with your progress lines and the prompt you used. One that FAILS simply drops off that list,
|
|
560
|
+
with the error reaching your terminal and nowhere else — so a failure you do not mention is one
|
|
561
|
+
they never learn about. Those files are yours to read too: check them before starting a second
|
|
562
|
+
expensive generation, because a forge and a prop each want a headless browser and will fight over one.
|
|
563
563
|
- Prefer changing the entries you mean to change over regenerating \`environmentObjects\`
|
|
564
564
|
wholesale, so their placements survive your edit.
|
|
565
565
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitmagic/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.37",
|
|
4
4
|
"description": "Build Bitmagic games from your own agent tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"citty": "^0.2.2",
|
|
20
20
|
"playwright-core": "^1.59.1",
|
|
21
21
|
"tar": "^7.4.3",
|
|
22
|
-
"@bitmagic/
|
|
23
|
-
"@bitmagic/
|
|
22
|
+
"@bitmagic/asset-core": "0.1.2",
|
|
23
|
+
"@bitmagic/world-forger": "0.1.4"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@eslint/js": "^9.38.0",
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Terminal progress for the level bake.
|
|
3
|
-
*
|
|
4
|
-
* The bake is the one step that can legitimately run for many minutes, and its transport wait is
|
|
5
|
-
* an IDLE timeout of 20 minutes (`VOXELIZE_TIMEOUT_MS`) — per-chunk progress re-arms the timer but
|
|
6
|
-
* is otherwise consumed silently inside the transport. Without a printed line a creator watching a
|
|
7
|
-
* still terminal concludes the command has hung and kills it mid-bake, losing the whole step. So
|
|
8
|
-
* the command subscribes to the page's own `VOXELIZE_GLB_AS_LEVEL_PROGRESS` messages
|
|
9
|
-
* (`game/src/engine/template/VoxelMessageHandlers.ts`) and prints them.
|
|
10
|
-
*
|
|
11
|
-
* Throttled, because the engine emits one message per chunk and a large level has thousands: an
|
|
12
|
-
* unthrottled relay would bury every other line of output. The formatter and the throttle are pure
|
|
13
|
-
* and separate from the subscription so both are testable without a browser.
|
|
14
|
-
*/
|
|
15
|
-
/** The engine's per-chunk progress payload. `chunkIndex: -1` marks the post-bake upload phase. */
|
|
16
|
-
export interface BakeProgress {
|
|
17
|
-
chunkIndex: number;
|
|
18
|
-
totalChunks: number;
|
|
19
|
-
nonEmptyChunks?: number;
|
|
20
|
-
label?: string;
|
|
21
|
-
}
|
|
22
|
-
export declare const BAKE_PROGRESS_TYPE = "VOXELIZE_GLB_AS_LEVEL_PROGRESS";
|
|
23
|
-
/** Minimum gap between printed bake lines. Long enough not to flood, short enough that the
|
|
24
|
-
* terminal never looks frozen. */
|
|
25
|
-
export declare const BAKE_PROGRESS_MIN_INTERVAL_MS = 3000;
|
|
26
|
-
/** Read a bake-progress payload off a page message, or null if it is not one. */
|
|
27
|
-
export declare function asBakeProgress(message: unknown): BakeProgress | null;
|
|
28
|
-
/**
|
|
29
|
-
* The line to print for one progress message.
|
|
30
|
-
*
|
|
31
|
-
* `chunkIndex: -1` / `totalChunks: -1` is the engine's sentinel for the upload phase that follows
|
|
32
|
-
* the chunk loop; it carries a label instead of a count, so it is rendered as that label rather
|
|
33
|
-
* than as a nonsensical "chunk -1 of -1".
|
|
34
|
-
*/
|
|
35
|
-
export declare function formatBakeProgress(progress: BakeProgress): string;
|
|
36
|
-
/**
|
|
37
|
-
* A printer that emits at most one line per `minIntervalMs` — except for the final chunk and the
|
|
38
|
-
* label-only phases, which always print. The last chunk is what tells a creator the loop finished
|
|
39
|
-
* rather than stalled, so dropping it to a throttle would remove the single most informative line.
|
|
40
|
-
*/
|
|
41
|
-
export declare function createBakeProgressPrinter(log: (message: string) => void, options?: {
|
|
42
|
-
minIntervalMs?: number;
|
|
43
|
-
now?: () => number;
|
|
44
|
-
}): (message: unknown) => void;
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Terminal progress for the level bake.
|
|
3
|
-
*
|
|
4
|
-
* The bake is the one step that can legitimately run for many minutes, and its transport wait is
|
|
5
|
-
* an IDLE timeout of 20 minutes (`VOXELIZE_TIMEOUT_MS`) — per-chunk progress re-arms the timer but
|
|
6
|
-
* is otherwise consumed silently inside the transport. Without a printed line a creator watching a
|
|
7
|
-
* still terminal concludes the command has hung and kills it mid-bake, losing the whole step. So
|
|
8
|
-
* the command subscribes to the page's own `VOXELIZE_GLB_AS_LEVEL_PROGRESS` messages
|
|
9
|
-
* (`game/src/engine/template/VoxelMessageHandlers.ts`) and prints them.
|
|
10
|
-
*
|
|
11
|
-
* Throttled, because the engine emits one message per chunk and a large level has thousands: an
|
|
12
|
-
* unthrottled relay would bury every other line of output. The formatter and the throttle are pure
|
|
13
|
-
* and separate from the subscription so both are testable without a browser.
|
|
14
|
-
*/
|
|
15
|
-
export const BAKE_PROGRESS_TYPE = 'VOXELIZE_GLB_AS_LEVEL_PROGRESS';
|
|
16
|
-
/** Minimum gap between printed bake lines. Long enough not to flood, short enough that the
|
|
17
|
-
* terminal never looks frozen. */
|
|
18
|
-
export const BAKE_PROGRESS_MIN_INTERVAL_MS = 3000;
|
|
19
|
-
function isRecord(value) {
|
|
20
|
-
return typeof value === 'object' && value !== null;
|
|
21
|
-
}
|
|
22
|
-
/** Read a bake-progress payload off a page message, or null if it is not one. */
|
|
23
|
-
export function asBakeProgress(message) {
|
|
24
|
-
if (!isRecord(message) || message.type !== BAKE_PROGRESS_TYPE)
|
|
25
|
-
return null;
|
|
26
|
-
const { chunkIndex, totalChunks } = message;
|
|
27
|
-
if (typeof chunkIndex !== 'number' || typeof totalChunks !== 'number')
|
|
28
|
-
return null;
|
|
29
|
-
return {
|
|
30
|
-
chunkIndex,
|
|
31
|
-
totalChunks,
|
|
32
|
-
...(typeof message.nonEmptyChunks === 'number' ? { nonEmptyChunks: message.nonEmptyChunks } : {}),
|
|
33
|
-
...(typeof message.label === 'string' ? { label: message.label } : {}),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* The line to print for one progress message.
|
|
38
|
-
*
|
|
39
|
-
* `chunkIndex: -1` / `totalChunks: -1` is the engine's sentinel for the upload phase that follows
|
|
40
|
-
* the chunk loop; it carries a label instead of a count, so it is rendered as that label rather
|
|
41
|
-
* than as a nonsensical "chunk -1 of -1".
|
|
42
|
-
*/
|
|
43
|
-
export function formatBakeProgress(progress) {
|
|
44
|
-
if (progress.totalChunks <= 0) {
|
|
45
|
-
return ` bake: ${progress.label ?? 'working…'}`;
|
|
46
|
-
}
|
|
47
|
-
const percent = Math.floor(((progress.chunkIndex + 1) / progress.totalChunks) * 100);
|
|
48
|
-
const filled = progress.nonEmptyChunks !== undefined ? `, ${progress.nonEmptyChunks} non-empty` : '';
|
|
49
|
-
const label = progress.label ? ` — ${progress.label}` : '';
|
|
50
|
-
return ` bake: chunk ${progress.chunkIndex + 1}/${progress.totalChunks} (${percent}%${filled})${label}`;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* A printer that emits at most one line per `minIntervalMs` — except for the final chunk and the
|
|
54
|
-
* label-only phases, which always print. The last chunk is what tells a creator the loop finished
|
|
55
|
-
* rather than stalled, so dropping it to a throttle would remove the single most informative line.
|
|
56
|
-
*/
|
|
57
|
-
export function createBakeProgressPrinter(log, options = {}) {
|
|
58
|
-
const minIntervalMs = options.minIntervalMs ?? BAKE_PROGRESS_MIN_INTERVAL_MS;
|
|
59
|
-
const now = options.now ?? (() => Date.now());
|
|
60
|
-
// -Infinity, not 0: the FIRST message must always print. A zero start throttles it whenever
|
|
61
|
-
// `now()` begins near zero — which a monotonic clock does, and which is exactly the moment the
|
|
62
|
-
// creator most needs to see that the bake has begun.
|
|
63
|
-
let lastAt = -Infinity;
|
|
64
|
-
return (message) => {
|
|
65
|
-
const progress = asBakeProgress(message);
|
|
66
|
-
if (progress === null)
|
|
67
|
-
return;
|
|
68
|
-
const isFinalChunk = progress.totalChunks > 0 && progress.chunkIndex + 1 >= progress.totalChunks;
|
|
69
|
-
const isPhaseLabel = progress.totalChunks <= 0;
|
|
70
|
-
const at = now();
|
|
71
|
-
if (!isFinalChunk && !isPhaseLabel && at - lastAt < minIntervalMs)
|
|
72
|
-
return;
|
|
73
|
-
lastAt = at;
|
|
74
|
-
log(formatBakeProgress(progress));
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
//# sourceMappingURL=bake-progress.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bake-progress.js","sourceRoot":"","sources":["../../src/forge/bake-progress.ts"],"names":[],"mappings":"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"}
|