@yagejs/debug 0.1.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/README.md +45 -0
- package/dist/api.cjs +34 -0
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.cts +68 -0
- package/dist/api.d.ts +68 -0
- package/dist/api.js +7 -0
- package/dist/api.js.map +1 -0
- package/dist/chunk-QSE3OVXA.js +12 -0
- package/dist/chunk-QSE3OVXA.js.map +1 -0
- package/dist/index.cjs +655 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +82 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +624 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DebugRegistryKey,
|
|
3
|
+
__name
|
|
4
|
+
} from "./chunk-QSE3OVXA.js";
|
|
5
|
+
|
|
6
|
+
// src/DebugPlugin.ts
|
|
7
|
+
import { SystemSchedulerKey, InspectorKey, GameLoopKey } from "@yagejs/core";
|
|
8
|
+
import { RendererKey, RenderLayerManagerKey, CameraKey } from "@yagejs/renderer";
|
|
9
|
+
|
|
10
|
+
// src/DebugClock.ts
|
|
11
|
+
var DebugClock = class {
|
|
12
|
+
constructor(gameLoop, stopTicker, startTicker, render) {
|
|
13
|
+
this.gameLoop = gameLoop;
|
|
14
|
+
this.stopTicker = stopTicker;
|
|
15
|
+
this.startTicker = startTicker;
|
|
16
|
+
this.render = render;
|
|
17
|
+
}
|
|
18
|
+
gameLoop;
|
|
19
|
+
stopTicker;
|
|
20
|
+
startTicker;
|
|
21
|
+
render;
|
|
22
|
+
static {
|
|
23
|
+
__name(this, "DebugClock");
|
|
24
|
+
}
|
|
25
|
+
_isManual = false;
|
|
26
|
+
get isManual() {
|
|
27
|
+
return this._isManual;
|
|
28
|
+
}
|
|
29
|
+
startAuto() {
|
|
30
|
+
if (!this._isManual) return;
|
|
31
|
+
this.startTicker();
|
|
32
|
+
this._isManual = false;
|
|
33
|
+
}
|
|
34
|
+
stopAuto() {
|
|
35
|
+
if (this._isManual) return;
|
|
36
|
+
this.stopTicker();
|
|
37
|
+
this._isManual = true;
|
|
38
|
+
}
|
|
39
|
+
step(dtMs) {
|
|
40
|
+
if (!this._isManual) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"Manual clock is not active. Call clock.stopAuto() first."
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
const dt = dtMs ?? this.gameLoop.fixedTimestep;
|
|
46
|
+
this.gameLoop.tick(dt);
|
|
47
|
+
this.render();
|
|
48
|
+
}
|
|
49
|
+
stepFrames(count, dtMs) {
|
|
50
|
+
if (!Number.isInteger(count) || count < 0) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
"stepFrames(count) requires a non-negative integer count."
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
for (let i = 0; i < count; i++) {
|
|
56
|
+
this.step(dtMs);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Enter or exit manual mode. Used by DebugPlugin for config-driven init. */
|
|
60
|
+
setManual(enabled) {
|
|
61
|
+
if (enabled === this._isManual) return;
|
|
62
|
+
if (enabled) {
|
|
63
|
+
this.stopTicker();
|
|
64
|
+
} else {
|
|
65
|
+
this.startTicker();
|
|
66
|
+
}
|
|
67
|
+
this._isManual = enabled;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/DebugRegistryImpl.ts
|
|
72
|
+
var DebugRegistryImpl = class {
|
|
73
|
+
static {
|
|
74
|
+
__name(this, "DebugRegistryImpl");
|
|
75
|
+
}
|
|
76
|
+
contributors = /* @__PURE__ */ new Map();
|
|
77
|
+
enabled = false;
|
|
78
|
+
flags = /* @__PURE__ */ new Map();
|
|
79
|
+
register(contributor) {
|
|
80
|
+
if (this.contributors.has(contributor.name)) return;
|
|
81
|
+
this.contributors.set(contributor.name, contributor);
|
|
82
|
+
for (const flag of contributor.flags) {
|
|
83
|
+
this.flags.set(`${contributor.name}.${flag}`, true);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
isEnabled() {
|
|
87
|
+
return this.enabled;
|
|
88
|
+
}
|
|
89
|
+
isFlagEnabled(contributorName, flag) {
|
|
90
|
+
return this.flags.get(`${contributorName}.${flag}`) ?? true;
|
|
91
|
+
}
|
|
92
|
+
toggle() {
|
|
93
|
+
this.enabled = !this.enabled;
|
|
94
|
+
}
|
|
95
|
+
toggleFlag(contributorName, flag) {
|
|
96
|
+
const key = `${contributorName}.${flag}`;
|
|
97
|
+
this.flags.set(key, !(this.flags.get(key) ?? true));
|
|
98
|
+
}
|
|
99
|
+
setFlag(contributorName, flag, value) {
|
|
100
|
+
this.flags.set(`${contributorName}.${flag}`, value);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// src/StatsStore.ts
|
|
105
|
+
var WINDOW_SIZE = 120;
|
|
106
|
+
var StatsStore = class {
|
|
107
|
+
static {
|
|
108
|
+
__name(this, "StatsStore");
|
|
109
|
+
}
|
|
110
|
+
rings = /* @__PURE__ */ new Map();
|
|
111
|
+
push(key, value) {
|
|
112
|
+
let ring = this.rings.get(key);
|
|
113
|
+
if (!ring) {
|
|
114
|
+
ring = { data: new Float64Array(WINDOW_SIZE), count: 0, index: 0 };
|
|
115
|
+
this.rings.set(key, ring);
|
|
116
|
+
}
|
|
117
|
+
ring.data[ring.index] = value;
|
|
118
|
+
ring.index = (ring.index + 1) % WINDOW_SIZE;
|
|
119
|
+
if (ring.count < WINDOW_SIZE) ring.count++;
|
|
120
|
+
}
|
|
121
|
+
average(key) {
|
|
122
|
+
const ring = this.rings.get(key);
|
|
123
|
+
if (!ring || ring.count === 0) return 0;
|
|
124
|
+
const { data, count } = ring;
|
|
125
|
+
let sum = 0;
|
|
126
|
+
for (let i = 0; i < count; i++) sum += data[i] ?? 0;
|
|
127
|
+
return sum / count;
|
|
128
|
+
}
|
|
129
|
+
latest(key) {
|
|
130
|
+
const ring = this.rings.get(key);
|
|
131
|
+
if (!ring || ring.count === 0) return 0;
|
|
132
|
+
return ring.data[(ring.index - 1 + WINDOW_SIZE) % WINDOW_SIZE] ?? 0;
|
|
133
|
+
}
|
|
134
|
+
min(key) {
|
|
135
|
+
const ring = this.rings.get(key);
|
|
136
|
+
if (!ring || ring.count === 0) return 0;
|
|
137
|
+
const { data, count } = ring;
|
|
138
|
+
let m = Infinity;
|
|
139
|
+
for (let i = 0; i < count; i++) {
|
|
140
|
+
const v = data[i] ?? 0;
|
|
141
|
+
if (v < m) m = v;
|
|
142
|
+
}
|
|
143
|
+
return m;
|
|
144
|
+
}
|
|
145
|
+
max(key) {
|
|
146
|
+
const ring = this.rings.get(key);
|
|
147
|
+
if (!ring || ring.count === 0) return 0;
|
|
148
|
+
const { data, count } = ring;
|
|
149
|
+
let m = -Infinity;
|
|
150
|
+
for (let i = 0; i < count; i++) {
|
|
151
|
+
const v = data[i] ?? 0;
|
|
152
|
+
if (v > m) m = v;
|
|
153
|
+
}
|
|
154
|
+
return m;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// src/GraphicsPool.ts
|
|
159
|
+
import { Graphics } from "pixi.js";
|
|
160
|
+
var GraphicsPool = class {
|
|
161
|
+
static {
|
|
162
|
+
__name(this, "GraphicsPool");
|
|
163
|
+
}
|
|
164
|
+
pool = null;
|
|
165
|
+
index = 0;
|
|
166
|
+
container;
|
|
167
|
+
maxSize;
|
|
168
|
+
constructor(container, maxSize = 256) {
|
|
169
|
+
this.container = container;
|
|
170
|
+
this.maxSize = maxSize;
|
|
171
|
+
}
|
|
172
|
+
/** Lazily create Graphics objects on first use (ensures PixiJS is fully ready). */
|
|
173
|
+
ensure() {
|
|
174
|
+
if (this.pool) return this.pool;
|
|
175
|
+
this.pool = [];
|
|
176
|
+
for (let i = 0; i < this.maxSize; i++) {
|
|
177
|
+
const g = new Graphics();
|
|
178
|
+
g.visible = false;
|
|
179
|
+
g.eventMode = "none";
|
|
180
|
+
this.container.addChild(g);
|
|
181
|
+
this.pool.push(g);
|
|
182
|
+
}
|
|
183
|
+
return this.pool;
|
|
184
|
+
}
|
|
185
|
+
/** Return the next available Graphics, or undefined if the pool is exhausted. */
|
|
186
|
+
acquire() {
|
|
187
|
+
const pool = this.ensure();
|
|
188
|
+
if (this.index >= pool.length) return void 0;
|
|
189
|
+
const g = pool[this.index];
|
|
190
|
+
g.visible = true;
|
|
191
|
+
this.index++;
|
|
192
|
+
return g;
|
|
193
|
+
}
|
|
194
|
+
/** Clear and hide all previously acquired graphics, reset index. */
|
|
195
|
+
resetFrame() {
|
|
196
|
+
if (!this.pool) return;
|
|
197
|
+
for (let i = 0; i < this.index; i++) {
|
|
198
|
+
const g = this.pool[i];
|
|
199
|
+
g.clear();
|
|
200
|
+
g.visible = false;
|
|
201
|
+
g.position.set(0, 0);
|
|
202
|
+
g.rotation = 0;
|
|
203
|
+
g.scale.set(1, 1);
|
|
204
|
+
}
|
|
205
|
+
this.index = 0;
|
|
206
|
+
}
|
|
207
|
+
destroy() {
|
|
208
|
+
if (!this.pool) return;
|
|
209
|
+
for (const g of this.pool) {
|
|
210
|
+
g.destroy();
|
|
211
|
+
}
|
|
212
|
+
this.pool.length = 0;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// src/TextPool.ts
|
|
217
|
+
import { Text } from "pixi.js";
|
|
218
|
+
var LINE_HEIGHT = 16;
|
|
219
|
+
var FONT_SIZE = 14;
|
|
220
|
+
var PADDING = 4;
|
|
221
|
+
var TextPool = class {
|
|
222
|
+
static {
|
|
223
|
+
__name(this, "TextPool");
|
|
224
|
+
}
|
|
225
|
+
pool = null;
|
|
226
|
+
index = 0;
|
|
227
|
+
container;
|
|
228
|
+
maxLines;
|
|
229
|
+
constructor(container, maxLines = 32) {
|
|
230
|
+
this.container = container;
|
|
231
|
+
this.maxLines = maxLines;
|
|
232
|
+
}
|
|
233
|
+
/** Lazily create Text objects on first use (ensures PixiJS is fully ready). */
|
|
234
|
+
ensure() {
|
|
235
|
+
if (this.pool) return this.pool;
|
|
236
|
+
this.pool = [];
|
|
237
|
+
for (let i = 0; i < this.maxLines; i++) {
|
|
238
|
+
const t = new Text({
|
|
239
|
+
text: "",
|
|
240
|
+
style: {
|
|
241
|
+
fontFamily: "monospace",
|
|
242
|
+
fontSize: FONT_SIZE,
|
|
243
|
+
fill: 16777215
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
t.visible = false;
|
|
247
|
+
t.eventMode = "none";
|
|
248
|
+
this.container.addChild(t);
|
|
249
|
+
this.pool.push(t);
|
|
250
|
+
}
|
|
251
|
+
return this.pool;
|
|
252
|
+
}
|
|
253
|
+
/** Show a text line at the next available slot. */
|
|
254
|
+
addLine(text) {
|
|
255
|
+
const pool = this.ensure();
|
|
256
|
+
if (this.index >= pool.length) return;
|
|
257
|
+
const t = pool[this.index];
|
|
258
|
+
t.text = text;
|
|
259
|
+
t.visible = true;
|
|
260
|
+
t.position.set(PADDING, PADDING + this.index * LINE_HEIGHT);
|
|
261
|
+
this.index++;
|
|
262
|
+
}
|
|
263
|
+
/** Hide all lines and reset for the next frame. */
|
|
264
|
+
resetFrame() {
|
|
265
|
+
if (!this.pool) return;
|
|
266
|
+
for (let i = 0; i < this.index; i++) {
|
|
267
|
+
this.pool[i].visible = false;
|
|
268
|
+
}
|
|
269
|
+
this.index = 0;
|
|
270
|
+
}
|
|
271
|
+
destroy() {
|
|
272
|
+
if (!this.pool) return;
|
|
273
|
+
for (const t of this.pool) {
|
|
274
|
+
t.destroy();
|
|
275
|
+
}
|
|
276
|
+
this.pool.length = 0;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// src/WorldDebugApiImpl.ts
|
|
281
|
+
var WorldDebugApiImpl = class {
|
|
282
|
+
constructor(pool, registry, _camera) {
|
|
283
|
+
this.pool = pool;
|
|
284
|
+
this.registry = registry;
|
|
285
|
+
this._camera = _camera;
|
|
286
|
+
}
|
|
287
|
+
pool;
|
|
288
|
+
registry;
|
|
289
|
+
_camera;
|
|
290
|
+
static {
|
|
291
|
+
__name(this, "WorldDebugApiImpl");
|
|
292
|
+
}
|
|
293
|
+
_contributorName = "";
|
|
294
|
+
/** Set the current contributor name (called before each contributor's drawWorld). */
|
|
295
|
+
setContributor(name) {
|
|
296
|
+
this._contributorName = name;
|
|
297
|
+
}
|
|
298
|
+
acquireGraphics() {
|
|
299
|
+
return this.pool.acquire();
|
|
300
|
+
}
|
|
301
|
+
isFlagEnabled(flag) {
|
|
302
|
+
return this.registry.isFlagEnabled(this._contributorName, flag);
|
|
303
|
+
}
|
|
304
|
+
get cameraZoom() {
|
|
305
|
+
return this._camera.zoom;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// src/HudDebugApiImpl.ts
|
|
310
|
+
var HudDebugApiImpl = class {
|
|
311
|
+
constructor(textPool, registry, screenWidth, screenHeight) {
|
|
312
|
+
this.textPool = textPool;
|
|
313
|
+
this.registry = registry;
|
|
314
|
+
this.screenWidth = screenWidth;
|
|
315
|
+
this.screenHeight = screenHeight;
|
|
316
|
+
}
|
|
317
|
+
textPool;
|
|
318
|
+
registry;
|
|
319
|
+
screenWidth;
|
|
320
|
+
screenHeight;
|
|
321
|
+
static {
|
|
322
|
+
__name(this, "HudDebugApiImpl");
|
|
323
|
+
}
|
|
324
|
+
_contributorName = "";
|
|
325
|
+
/** Set the current contributor name (called before each contributor's drawHud). */
|
|
326
|
+
setContributor(name) {
|
|
327
|
+
this._contributorName = name;
|
|
328
|
+
}
|
|
329
|
+
addLine(text) {
|
|
330
|
+
this.textPool.addLine(text);
|
|
331
|
+
}
|
|
332
|
+
isFlagEnabled(flag) {
|
|
333
|
+
return this.registry.isFlagEnabled(this._contributorName, flag);
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// src/DebugRenderSystem.ts
|
|
338
|
+
import { System, Phase } from "@yagejs/core";
|
|
339
|
+
var DebugRenderSystem = class extends System {
|
|
340
|
+
constructor(registry, graphicsPool, textPool, worldApi, hudApi, stats, worldContainer, hudContainer) {
|
|
341
|
+
super();
|
|
342
|
+
this.registry = registry;
|
|
343
|
+
this.graphicsPool = graphicsPool;
|
|
344
|
+
this.textPool = textPool;
|
|
345
|
+
this.worldApi = worldApi;
|
|
346
|
+
this.hudApi = hudApi;
|
|
347
|
+
this.stats = stats;
|
|
348
|
+
this.worldContainer = worldContainer;
|
|
349
|
+
this.hudContainer = hudContainer;
|
|
350
|
+
}
|
|
351
|
+
registry;
|
|
352
|
+
graphicsPool;
|
|
353
|
+
textPool;
|
|
354
|
+
worldApi;
|
|
355
|
+
hudApi;
|
|
356
|
+
stats;
|
|
357
|
+
worldContainer;
|
|
358
|
+
hudContainer;
|
|
359
|
+
static {
|
|
360
|
+
__name(this, "DebugRenderSystem");
|
|
361
|
+
}
|
|
362
|
+
phase = Phase.Render;
|
|
363
|
+
priority = 9999;
|
|
364
|
+
update(dt) {
|
|
365
|
+
if (!this.registry.enabled) {
|
|
366
|
+
this.worldContainer.visible = false;
|
|
367
|
+
this.hudContainer.visible = false;
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
this.worldContainer.visible = true;
|
|
371
|
+
this.hudContainer.visible = true;
|
|
372
|
+
this.graphicsPool.resetFrame();
|
|
373
|
+
this.textPool.resetFrame();
|
|
374
|
+
for (const [name, contributor] of this.registry.contributors) {
|
|
375
|
+
contributor.sample?.(this.stats, dt);
|
|
376
|
+
if (contributor.drawWorld) {
|
|
377
|
+
this.worldApi.setContributor(name);
|
|
378
|
+
contributor.drawWorld(this.worldApi);
|
|
379
|
+
}
|
|
380
|
+
if (contributor.drawHud) {
|
|
381
|
+
this.hudApi.setContributor(name);
|
|
382
|
+
contributor.drawHud(this.hudApi);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// src/contributors/FpsContributor.ts
|
|
389
|
+
var FpsContributor = class {
|
|
390
|
+
static {
|
|
391
|
+
__name(this, "FpsContributor");
|
|
392
|
+
}
|
|
393
|
+
name = "fps";
|
|
394
|
+
flags = [];
|
|
395
|
+
stats = null;
|
|
396
|
+
sample(stats, dt) {
|
|
397
|
+
this.stats = stats;
|
|
398
|
+
if (dt > 0) stats.push("fps", 1e3 / dt);
|
|
399
|
+
}
|
|
400
|
+
drawHud(api) {
|
|
401
|
+
const avg = this.stats?.average("fps") ?? 0;
|
|
402
|
+
api.addLine(`FPS: ${Math.round(avg)}`);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// src/contributors/EntityCountContributor.ts
|
|
407
|
+
var EntityCountContributor = class {
|
|
408
|
+
constructor(inspector) {
|
|
409
|
+
this.inspector = inspector;
|
|
410
|
+
}
|
|
411
|
+
inspector;
|
|
412
|
+
static {
|
|
413
|
+
__name(this, "EntityCountContributor");
|
|
414
|
+
}
|
|
415
|
+
name = "entities";
|
|
416
|
+
flags = [];
|
|
417
|
+
drawHud(api) {
|
|
418
|
+
const count = this.inspector.snapshot().entityCount;
|
|
419
|
+
api.addLine(`Entities: ${count}`);
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
// src/contributors/SystemTimingContributor.ts
|
|
424
|
+
var SystemTimingContributor = class {
|
|
425
|
+
constructor(timings) {
|
|
426
|
+
this.timings = timings;
|
|
427
|
+
}
|
|
428
|
+
timings;
|
|
429
|
+
static {
|
|
430
|
+
__name(this, "SystemTimingContributor");
|
|
431
|
+
}
|
|
432
|
+
name = "timing";
|
|
433
|
+
flags = ["breakdown"];
|
|
434
|
+
stats = null;
|
|
435
|
+
sample(stats) {
|
|
436
|
+
this.stats = stats;
|
|
437
|
+
for (const [name, ms] of this.timings) {
|
|
438
|
+
stats.push(`system.${name}`, ms);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
drawHud(api) {
|
|
442
|
+
if (!this.stats) return;
|
|
443
|
+
let total = 0;
|
|
444
|
+
const entries = [];
|
|
445
|
+
for (const name of this.timings.keys()) {
|
|
446
|
+
const avg = this.stats.average(`system.${name}`);
|
|
447
|
+
total += avg;
|
|
448
|
+
entries.push([name, avg]);
|
|
449
|
+
}
|
|
450
|
+
api.addLine(`Systems: ${total.toFixed(2)}ms`);
|
|
451
|
+
if (api.isFlagEnabled("breakdown")) {
|
|
452
|
+
entries.sort((a, b) => b[1] - a[1]);
|
|
453
|
+
for (const [name, avg] of entries) {
|
|
454
|
+
api.addLine(` ${name}: ${avg.toFixed(2)}ms`);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// src/DebugPlugin.ts
|
|
461
|
+
var DebugPlugin = class {
|
|
462
|
+
static {
|
|
463
|
+
__name(this, "DebugPlugin");
|
|
464
|
+
}
|
|
465
|
+
name = "debug";
|
|
466
|
+
version = "2.0.0";
|
|
467
|
+
dependencies = ["renderer"];
|
|
468
|
+
config;
|
|
469
|
+
registry;
|
|
470
|
+
stats;
|
|
471
|
+
graphicsPool;
|
|
472
|
+
textPool;
|
|
473
|
+
worldContainer;
|
|
474
|
+
hudContainer;
|
|
475
|
+
worldApi;
|
|
476
|
+
hudApi;
|
|
477
|
+
systemTimings = /* @__PURE__ */ new Map();
|
|
478
|
+
originalUpdates = /* @__PURE__ */ new Map();
|
|
479
|
+
keyListener = null;
|
|
480
|
+
context;
|
|
481
|
+
renderer;
|
|
482
|
+
clock = null;
|
|
483
|
+
constructor(config) {
|
|
484
|
+
this.config = config ?? {};
|
|
485
|
+
}
|
|
486
|
+
install(context) {
|
|
487
|
+
this.context = context;
|
|
488
|
+
this.renderer = context.resolve(RendererKey);
|
|
489
|
+
const camera = context.resolve(CameraKey);
|
|
490
|
+
const worldLayers = context.resolve(RenderLayerManagerKey);
|
|
491
|
+
const debugLayer = worldLayers.getOrCreate("debug", 999999);
|
|
492
|
+
this.worldContainer = debugLayer.container;
|
|
493
|
+
this.worldContainer.eventMode = "none";
|
|
494
|
+
const hudLayers = this.renderer.createScreenContainer("debug-hud");
|
|
495
|
+
this.hudContainer = hudLayers.defaultLayer.container;
|
|
496
|
+
this.hudContainer.eventMode = "none";
|
|
497
|
+
this.graphicsPool = new GraphicsPool(
|
|
498
|
+
this.worldContainer,
|
|
499
|
+
this.config.maxGraphics
|
|
500
|
+
);
|
|
501
|
+
this.textPool = new TextPool(this.hudContainer, this.config.maxHudLines);
|
|
502
|
+
this.registry = new DebugRegistryImpl();
|
|
503
|
+
this.registry.enabled = this.config.startEnabled ?? false;
|
|
504
|
+
if (this.config.flags) {
|
|
505
|
+
for (const [key, value] of Object.entries(this.config.flags)) {
|
|
506
|
+
const dot = key.indexOf(".");
|
|
507
|
+
if (dot > 0) {
|
|
508
|
+
this.registry.setFlag(key.slice(0, dot), key.slice(dot + 1), value);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
this.stats = new StatsStore();
|
|
513
|
+
this.worldApi = new WorldDebugApiImpl(
|
|
514
|
+
this.graphicsPool,
|
|
515
|
+
this.registry,
|
|
516
|
+
camera
|
|
517
|
+
);
|
|
518
|
+
this.hudApi = new HudDebugApiImpl(
|
|
519
|
+
this.textPool,
|
|
520
|
+
this.registry,
|
|
521
|
+
camera.viewportWidth,
|
|
522
|
+
camera.viewportHeight
|
|
523
|
+
);
|
|
524
|
+
context.register(DebugRegistryKey, this.registry);
|
|
525
|
+
}
|
|
526
|
+
registerSystems(scheduler) {
|
|
527
|
+
scheduler.add(
|
|
528
|
+
new DebugRenderSystem(
|
|
529
|
+
this.registry,
|
|
530
|
+
this.graphicsPool,
|
|
531
|
+
this.textPool,
|
|
532
|
+
this.worldApi,
|
|
533
|
+
this.hudApi,
|
|
534
|
+
this.stats,
|
|
535
|
+
this.worldContainer,
|
|
536
|
+
this.hudContainer
|
|
537
|
+
)
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
onStart() {
|
|
541
|
+
const toggleKey = this.config.toggleKey ?? "Backquote";
|
|
542
|
+
const stepKey = this.config.stepKey ?? "Period";
|
|
543
|
+
this.keyListener = (e) => {
|
|
544
|
+
if (e.code === toggleKey) {
|
|
545
|
+
this.registry.toggle();
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
if (e.code === stepKey && this.clock?.isManual) {
|
|
549
|
+
e.preventDefault();
|
|
550
|
+
this.clock.step();
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
if (typeof window !== "undefined") {
|
|
554
|
+
window.addEventListener("keydown", this.keyListener);
|
|
555
|
+
}
|
|
556
|
+
const scheduler = this.context.resolve(SystemSchedulerKey);
|
|
557
|
+
for (const system of scheduler.getAllSystems()) {
|
|
558
|
+
if (system instanceof DebugRenderSystem) continue;
|
|
559
|
+
const name = system.constructor.name;
|
|
560
|
+
const original = system.update.bind(system);
|
|
561
|
+
this.originalUpdates.set(system, original);
|
|
562
|
+
system.update = (dt) => {
|
|
563
|
+
const t0 = performance.now();
|
|
564
|
+
original(dt);
|
|
565
|
+
this.systemTimings.set(name, performance.now() - t0);
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
const inspector = this.context.resolve(InspectorKey);
|
|
569
|
+
this.registry.register(new FpsContributor());
|
|
570
|
+
this.registry.register(new EntityCountContributor(inspector));
|
|
571
|
+
this.registry.register(new SystemTimingContributor(this.systemTimings));
|
|
572
|
+
const gameLoop = this.context.resolve(GameLoopKey);
|
|
573
|
+
const app = this.renderer.application;
|
|
574
|
+
this.clock = new DebugClock(
|
|
575
|
+
gameLoop,
|
|
576
|
+
() => app.stop(),
|
|
577
|
+
() => app.start(),
|
|
578
|
+
() => app.render()
|
|
579
|
+
);
|
|
580
|
+
if (this.config.manualClock) {
|
|
581
|
+
this.clock.setManual(true);
|
|
582
|
+
}
|
|
583
|
+
this.attachToGlobal(this.clock);
|
|
584
|
+
}
|
|
585
|
+
onDestroy() {
|
|
586
|
+
for (const [system, original] of this.originalUpdates) {
|
|
587
|
+
system.update = original;
|
|
588
|
+
}
|
|
589
|
+
this.originalUpdates.clear();
|
|
590
|
+
if (this.keyListener) {
|
|
591
|
+
if (typeof window !== "undefined") {
|
|
592
|
+
window.removeEventListener("keydown", this.keyListener);
|
|
593
|
+
}
|
|
594
|
+
this.keyListener = null;
|
|
595
|
+
}
|
|
596
|
+
this.detachFromGlobal();
|
|
597
|
+
this.clock = null;
|
|
598
|
+
for (const contributor of this.registry.contributors.values()) {
|
|
599
|
+
contributor.dispose?.();
|
|
600
|
+
}
|
|
601
|
+
this.registry.contributors.clear();
|
|
602
|
+
this.graphicsPool.destroy();
|
|
603
|
+
this.textPool.destroy();
|
|
604
|
+
this.renderer.destroyScreenContainer("debug-hud");
|
|
605
|
+
}
|
|
606
|
+
attachToGlobal(clock) {
|
|
607
|
+
const g = globalThis["__yage__"];
|
|
608
|
+
if (g && typeof g === "object") {
|
|
609
|
+
g["clock"] = clock;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
detachFromGlobal() {
|
|
613
|
+
const g = globalThis["__yage__"];
|
|
614
|
+
if (g && typeof g === "object" && g["clock"] === this.clock) {
|
|
615
|
+
delete g["clock"];
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
export {
|
|
620
|
+
DebugPlugin,
|
|
621
|
+
DebugRegistryImpl,
|
|
622
|
+
StatsStore
|
|
623
|
+
};
|
|
624
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/DebugPlugin.ts","../src/DebugClock.ts","../src/DebugRegistryImpl.ts","../src/StatsStore.ts","../src/GraphicsPool.ts","../src/TextPool.ts","../src/WorldDebugApiImpl.ts","../src/HudDebugApiImpl.ts","../src/DebugRenderSystem.ts","../src/contributors/FpsContributor.ts","../src/contributors/EntityCountContributor.ts","../src/contributors/SystemTimingContributor.ts"],"sourcesContent":["import { SystemSchedulerKey, InspectorKey, GameLoopKey } from \"@yagejs/core\";\nimport type {\n EngineContext,\n Plugin,\n SystemScheduler,\n System,\n} from \"@yagejs/core\";\nimport { DebugRegistryKey } from \"./types.js\";\nimport { RendererKey, RenderLayerManagerKey, CameraKey } from \"@yagejs/renderer\";\nimport type { RendererPlugin } from \"@yagejs/renderer\";\nimport { Container } from \"pixi.js\";\nimport { DebugClock } from \"./DebugClock.js\";\nimport type { IDebugClock } from \"./DebugClock.js\";\nimport { DebugRegistryImpl } from \"./DebugRegistryImpl.js\";\nimport { StatsStore } from \"./StatsStore.js\";\nimport { GraphicsPool } from \"./GraphicsPool.js\";\nimport { TextPool } from \"./TextPool.js\";\nimport { WorldDebugApiImpl } from \"./WorldDebugApiImpl.js\";\nimport { HudDebugApiImpl } from \"./HudDebugApiImpl.js\";\nimport { DebugRenderSystem } from \"./DebugRenderSystem.js\";\nimport { FpsContributor } from \"./contributors/FpsContributor.js\";\nimport { EntityCountContributor } from \"./contributors/EntityCountContributor.js\";\nimport { SystemTimingContributor } from \"./contributors/SystemTimingContributor.js\";\n\n/** Configuration for the DebugPlugin. */\nexport interface DebugConfig {\n /** Key code to toggle debug overlay. Default: \"Backquote\" */\n toggleKey?: string;\n /** When true, stop the renderer ticker and advance simulation manually via `window.__yage__.clock`. */\n manualClock?: boolean;\n /** Key code to advance one fixed-timestep frame while manual clock mode is active. Default: \"Period\" */\n stepKey?: string;\n /** Max pooled Graphics objects. Default: 256 */\n maxGraphics?: number;\n /** Max HUD text lines. Default: 32 */\n maxHudLines?: number;\n /** Whether the overlay starts enabled. Default: false */\n startEnabled?: boolean;\n /** Initial flag overrides, keyed by \"contributorName.flagName\". */\n flags?: Record<string, boolean>;\n}\n\n/** Debug overlay plugin. Depends on the renderer plugin. */\nexport class DebugPlugin implements Plugin {\n readonly name = \"debug\";\n readonly version = \"2.0.0\";\n readonly dependencies = [\"renderer\"] as const;\n\n private readonly config: DebugConfig;\n private registry!: DebugRegistryImpl;\n private stats!: StatsStore;\n private graphicsPool!: GraphicsPool;\n private textPool!: TextPool;\n private worldContainer!: Container;\n private hudContainer!: Container;\n private worldApi!: WorldDebugApiImpl;\n private hudApi!: HudDebugApiImpl;\n private systemTimings = new Map<string, number>();\n private originalUpdates = new Map<System, (dt: number) => void>();\n private keyListener: ((e: KeyboardEvent) => void) | null = null;\n private context!: EngineContext;\n private renderer!: RendererPlugin;\n private clock: DebugClock | null = null;\n\n constructor(config?: DebugConfig) {\n this.config = config ?? {};\n }\n\n install(context: EngineContext): void {\n this.context = context;\n\n this.renderer = context.resolve(RendererKey);\n const camera = context.resolve(CameraKey);\n\n // World-space debug layer (child of world container, drawn on top)\n const worldLayers = context.resolve(RenderLayerManagerKey);\n const debugLayer = worldLayers.getOrCreate(\"debug\", 999999);\n this.worldContainer = debugLayer.container;\n this.worldContainer.eventMode = \"none\";\n\n // Screen-space HUD container (sibling of world container, unaffected by camera)\n const hudLayers = this.renderer.createScreenContainer(\"debug-hud\");\n this.hudContainer = hudLayers.defaultLayer.container;\n this.hudContainer.eventMode = \"none\";\n\n this.graphicsPool = new GraphicsPool(\n this.worldContainer,\n this.config.maxGraphics,\n );\n this.textPool = new TextPool(this.hudContainer, this.config.maxHudLines);\n\n this.registry = new DebugRegistryImpl();\n this.registry.enabled = this.config.startEnabled ?? false;\n\n if (this.config.flags) {\n for (const [key, value] of Object.entries(this.config.flags)) {\n const dot = key.indexOf(\".\");\n if (dot > 0) {\n this.registry.setFlag(key.slice(0, dot), key.slice(dot + 1), value);\n }\n }\n }\n\n this.stats = new StatsStore();\n\n this.worldApi = new WorldDebugApiImpl(\n this.graphicsPool,\n this.registry,\n camera,\n );\n this.hudApi = new HudDebugApiImpl(\n this.textPool,\n this.registry,\n camera.viewportWidth,\n camera.viewportHeight,\n );\n\n context.register(DebugRegistryKey, this.registry);\n }\n\n registerSystems(scheduler: SystemScheduler): void {\n scheduler.add(\n new DebugRenderSystem(\n this.registry,\n this.graphicsPool,\n this.textPool,\n this.worldApi,\n this.hudApi,\n this.stats,\n this.worldContainer,\n this.hudContainer,\n ),\n );\n }\n\n onStart(): void {\n // Toggle / step key listener\n const toggleKey = this.config.toggleKey ?? \"Backquote\";\n const stepKey = this.config.stepKey ?? \"Period\";\n this.keyListener = (e: KeyboardEvent) => {\n if (e.code === toggleKey) {\n this.registry.toggle();\n return;\n }\n if (e.code === stepKey && this.clock?.isManual) {\n e.preventDefault();\n this.clock.step();\n }\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"keydown\", this.keyListener);\n }\n\n // Instrument system timings\n const scheduler = this.context.resolve(SystemSchedulerKey);\n for (const system of scheduler.getAllSystems()) {\n if (system instanceof DebugRenderSystem) continue;\n const name = system.constructor.name;\n const original = system.update.bind(system);\n this.originalUpdates.set(system, original);\n system.update = (dt: number) => {\n const t0 = performance.now();\n original(dt);\n this.systemTimings.set(name, performance.now() - t0);\n };\n }\n\n // Built-in contributors\n const inspector = this.context.resolve(InspectorKey);\n this.registry.register(new FpsContributor());\n this.registry.register(new EntityCountContributor(inspector));\n this.registry.register(new SystemTimingContributor(this.systemTimings));\n\n // Manual clock for deterministic stepping\n const gameLoop = this.context.resolve(GameLoopKey);\n const app = this.renderer.application;\n\n this.clock = new DebugClock(\n gameLoop,\n () => app.stop(),\n () => app.start(),\n () => app.render(),\n );\n\n if (this.config.manualClock) {\n this.clock.setManual(true);\n }\n\n this.attachToGlobal(this.clock);\n }\n\n onDestroy(): void {\n // Restore original system.update methods\n for (const [system, original] of this.originalUpdates) {\n system.update = original;\n }\n this.originalUpdates.clear();\n\n if (this.keyListener) {\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"keydown\", this.keyListener);\n }\n this.keyListener = null;\n }\n\n this.detachFromGlobal();\n this.clock = null;\n\n for (const contributor of this.registry.contributors.values()) {\n contributor.dispose?.();\n }\n this.registry.contributors.clear();\n\n this.graphicsPool.destroy();\n this.textPool.destroy();\n // worldContainer is owned by the world RenderLayerManager — don't destroy it\n this.renderer.destroyScreenContainer(\"debug-hud\");\n }\n\n private attachToGlobal(clock: IDebugClock): void {\n const g = (globalThis as Record<string, unknown>)[\"__yage__\"];\n if (g && typeof g === \"object\") {\n (g as Record<string, unknown>)[\"clock\"] = clock;\n }\n }\n\n private detachFromGlobal(): void {\n const g = (globalThis as Record<string, unknown>)[\"__yage__\"];\n if (\n g &&\n typeof g === \"object\" &&\n (g as Record<string, unknown>)[\"clock\"] === this.clock\n ) {\n delete (g as Record<string, unknown>)[\"clock\"];\n }\n }\n}\n","/** Public interface for the manual debug clock, accessible via `window.__yage__.clock`. */\nexport interface IDebugClock {\n readonly isManual: boolean;\n startAuto(): void;\n stopAuto(): void;\n step(dtMs?: number): void;\n stepFrames(count: number, dtMs?: number): void;\n}\n\n/** Minimal view of a game loop needed by the debug clock. */\ninterface GameLoopLike {\n tick(dtMs: number): void;\n readonly fixedTimestep: number;\n}\n\n/**\n * Controls engine time-stepping for deterministic E2E tests.\n *\n * When manual mode is active the renderer ticker is paused and frames\n * advance only via explicit `step()` / `stepFrames()` calls.\n */\nexport class DebugClock implements IDebugClock {\n private _isManual = false;\n\n constructor(\n private readonly gameLoop: GameLoopLike,\n private readonly stopTicker: () => void,\n private readonly startTicker: () => void,\n private readonly render: () => void,\n ) {}\n\n get isManual(): boolean {\n return this._isManual;\n }\n\n startAuto(): void {\n if (!this._isManual) return;\n this.startTicker();\n this._isManual = false;\n }\n\n stopAuto(): void {\n if (this._isManual) return;\n this.stopTicker();\n this._isManual = true;\n }\n\n step(dtMs?: number): void {\n if (!this._isManual) {\n throw new Error(\n \"Manual clock is not active. Call clock.stopAuto() first.\",\n );\n }\n const dt = dtMs ?? this.gameLoop.fixedTimestep;\n this.gameLoop.tick(dt);\n this.render();\n }\n\n stepFrames(count: number, dtMs?: number): void {\n if (!Number.isInteger(count) || count < 0) {\n throw new Error(\n \"stepFrames(count) requires a non-negative integer count.\",\n );\n }\n for (let i = 0; i < count; i++) {\n this.step(dtMs);\n }\n }\n\n /** Enter or exit manual mode. Used by DebugPlugin for config-driven init. */\n setManual(enabled: boolean): void {\n if (enabled === this._isManual) return;\n if (enabled) {\n this.stopTicker();\n } else {\n this.startTicker();\n }\n this._isManual = enabled;\n }\n}\n","import type { DebugContributor, DebugRegistry } from \"./types.js\";\n\n/** Concrete implementation of the DebugRegistry interface. */\nexport class DebugRegistryImpl implements DebugRegistry {\n readonly contributors = new Map<string, DebugContributor>();\n enabled = false;\n private flags = new Map<string, boolean>();\n\n register(contributor: DebugContributor): void {\n if (this.contributors.has(contributor.name)) return;\n this.contributors.set(contributor.name, contributor);\n for (const flag of contributor.flags) {\n this.flags.set(`${contributor.name}.${flag}`, true);\n }\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n isFlagEnabled(contributorName: string, flag: string): boolean {\n return this.flags.get(`${contributorName}.${flag}`) ?? true;\n }\n\n toggle(): void {\n this.enabled = !this.enabled;\n }\n\n toggleFlag(contributorName: string, flag: string): void {\n const key = `${contributorName}.${flag}`;\n this.flags.set(key, !(this.flags.get(key) ?? true));\n }\n\n setFlag(contributorName: string, flag: string, value: boolean): void {\n this.flags.set(`${contributorName}.${flag}`, value);\n }\n}\n","import type { StatsApi } from \"./types.js\";\n\nconst WINDOW_SIZE = 120;\n\ninterface RingBuffer {\n data: Float64Array;\n count: number;\n index: number;\n}\n\n/** Rolling-window statistics store backed by Float64Array ring buffers. */\nexport class StatsStore implements StatsApi {\n private rings = new Map<string, RingBuffer>();\n\n push(key: string, value: number): void {\n let ring = this.rings.get(key);\n if (!ring) {\n ring = { data: new Float64Array(WINDOW_SIZE), count: 0, index: 0 };\n this.rings.set(key, ring);\n }\n ring.data[ring.index] = value;\n ring.index = (ring.index + 1) % WINDOW_SIZE;\n if (ring.count < WINDOW_SIZE) ring.count++;\n }\n\n average(key: string): number {\n const ring = this.rings.get(key);\n if (!ring || ring.count === 0) return 0;\n const { data, count } = ring;\n let sum = 0;\n for (let i = 0; i < count; i++) sum += data[i] ?? 0;\n return sum / count;\n }\n\n latest(key: string): number {\n const ring = this.rings.get(key);\n if (!ring || ring.count === 0) return 0;\n return ring.data[(ring.index - 1 + WINDOW_SIZE) % WINDOW_SIZE] ?? 0;\n }\n\n min(key: string): number {\n const ring = this.rings.get(key);\n if (!ring || ring.count === 0) return 0;\n const { data, count } = ring;\n let m = Infinity;\n for (let i = 0; i < count; i++) {\n const v = data[i] ?? 0;\n if (v < m) m = v;\n }\n return m;\n }\n\n max(key: string): number {\n const ring = this.rings.get(key);\n if (!ring || ring.count === 0) return 0;\n const { data, count } = ring;\n let m = -Infinity;\n for (let i = 0; i < count; i++) {\n const v = data[i] ?? 0;\n if (v > m) m = v;\n }\n return m;\n }\n}\n","import { Graphics, Container } from \"pixi.js\";\n\n/** Allocation-free pool of PixiJS Graphics objects for debug drawing. */\nexport class GraphicsPool {\n private pool: Graphics[] | null = null;\n private index = 0;\n private readonly container: Container;\n private readonly maxSize: number;\n\n constructor(container: Container, maxSize = 256) {\n this.container = container;\n this.maxSize = maxSize;\n }\n\n /** Lazily create Graphics objects on first use (ensures PixiJS is fully ready). */\n private ensure(): Graphics[] {\n if (this.pool) return this.pool;\n this.pool = [];\n for (let i = 0; i < this.maxSize; i++) {\n const g = new Graphics();\n g.visible = false;\n g.eventMode = \"none\";\n this.container.addChild(g);\n this.pool.push(g);\n }\n return this.pool;\n }\n\n /** Return the next available Graphics, or undefined if the pool is exhausted. */\n acquire(): Graphics | undefined {\n const pool = this.ensure();\n if (this.index >= pool.length) return undefined;\n const g = pool[this.index]!;\n g.visible = true;\n this.index++;\n return g;\n }\n\n /** Clear and hide all previously acquired graphics, reset index. */\n resetFrame(): void {\n if (!this.pool) return;\n for (let i = 0; i < this.index; i++) {\n const g = this.pool[i]!;\n g.clear();\n g.visible = false;\n g.position.set(0, 0);\n g.rotation = 0;\n g.scale.set(1, 1);\n }\n this.index = 0;\n }\n\n destroy(): void {\n if (!this.pool) return;\n for (const g of this.pool) {\n g.destroy();\n }\n this.pool.length = 0;\n }\n}\n","import { Text, Container } from \"pixi.js\";\n\nconst LINE_HEIGHT = 16;\nconst FONT_SIZE = 14;\nconst PADDING = 4;\n\n/** Allocation-free pool of PixiJS Text objects for HUD debug lines. */\nexport class TextPool {\n private pool: Text[] | null = null;\n private index = 0;\n private readonly container: Container;\n private readonly maxLines: number;\n\n constructor(container: Container, maxLines = 32) {\n this.container = container;\n this.maxLines = maxLines;\n }\n\n /** Lazily create Text objects on first use (ensures PixiJS is fully ready). */\n private ensure(): Text[] {\n if (this.pool) return this.pool;\n this.pool = [];\n for (let i = 0; i < this.maxLines; i++) {\n const t = new Text({\n text: \"\",\n style: {\n fontFamily: \"monospace\",\n fontSize: FONT_SIZE,\n fill: 0xffffff,\n },\n });\n t.visible = false;\n t.eventMode = \"none\";\n this.container.addChild(t);\n this.pool.push(t);\n }\n return this.pool;\n }\n\n /** Show a text line at the next available slot. */\n addLine(text: string): void {\n const pool = this.ensure();\n if (this.index >= pool.length) return;\n const t = pool[this.index]!;\n t.text = text;\n t.visible = true;\n t.position.set(PADDING, PADDING + this.index * LINE_HEIGHT);\n this.index++;\n }\n\n /** Hide all lines and reset for the next frame. */\n resetFrame(): void {\n if (!this.pool) return;\n for (let i = 0; i < this.index; i++) {\n this.pool[i]!.visible = false;\n }\n this.index = 0;\n }\n\n destroy(): void {\n if (!this.pool) return;\n for (const t of this.pool) {\n t.destroy();\n }\n this.pool.length = 0;\n }\n}\n","import type { WorldDebugApi, DebugGraphics } from \"./types.js\";\nimport type { GraphicsPool } from \"./GraphicsPool.js\";\nimport type { DebugRegistryImpl } from \"./DebugRegistryImpl.js\";\n\n/** WorldDebugApi backed by a GraphicsPool. Contributor name is swapped per iteration. */\nexport class WorldDebugApiImpl implements WorldDebugApi {\n private _contributorName = \"\";\n\n constructor(\n private readonly pool: GraphicsPool,\n private readonly registry: DebugRegistryImpl,\n private readonly _camera: { zoom: number },\n ) {}\n\n /** Set the current contributor name (called before each contributor's drawWorld). */\n setContributor(name: string): void {\n this._contributorName = name;\n }\n\n acquireGraphics(): DebugGraphics | undefined {\n return this.pool.acquire() as unknown as DebugGraphics | undefined;\n }\n\n isFlagEnabled(flag: string): boolean {\n return this.registry.isFlagEnabled(this._contributorName, flag);\n }\n\n get cameraZoom(): number {\n return this._camera.zoom;\n }\n}\n","import type { HudDebugApi } from \"./types.js\";\nimport type { TextPool } from \"./TextPool.js\";\nimport type { DebugRegistryImpl } from \"./DebugRegistryImpl.js\";\n\n/** HudDebugApi backed by a TextPool. Contributor name is swapped per iteration. */\nexport class HudDebugApiImpl implements HudDebugApi {\n private _contributorName = \"\";\n\n constructor(\n private readonly textPool: TextPool,\n private readonly registry: DebugRegistryImpl,\n public readonly screenWidth: number,\n public readonly screenHeight: number,\n ) {}\n\n /** Set the current contributor name (called before each contributor's drawHud). */\n setContributor(name: string): void {\n this._contributorName = name;\n }\n\n addLine(text: string): void {\n this.textPool.addLine(text);\n }\n\n isFlagEnabled(flag: string): boolean {\n return this.registry.isFlagEnabled(this._contributorName, flag);\n }\n}\n","import { System, Phase } from \"@yagejs/core\";\nimport type { Container } from \"pixi.js\";\nimport type { DebugRegistryImpl } from \"./DebugRegistryImpl.js\";\nimport type { GraphicsPool } from \"./GraphicsPool.js\";\nimport type { TextPool } from \"./TextPool.js\";\nimport type { WorldDebugApiImpl } from \"./WorldDebugApiImpl.js\";\nimport type { HudDebugApiImpl } from \"./HudDebugApiImpl.js\";\nimport type { StatsStore } from \"./StatsStore.js\";\n\n/** Renders all debug contributors. Runs after DisplaySystem in the Render phase. */\nexport class DebugRenderSystem extends System {\n readonly phase = Phase.Render;\n readonly priority = 9999;\n\n constructor(\n private readonly registry: DebugRegistryImpl,\n private readonly graphicsPool: GraphicsPool,\n private readonly textPool: TextPool,\n private readonly worldApi: WorldDebugApiImpl,\n private readonly hudApi: HudDebugApiImpl,\n private readonly stats: StatsStore,\n private readonly worldContainer: Container,\n private readonly hudContainer: Container,\n ) {\n super();\n }\n\n update(dt: number): void {\n if (!this.registry.enabled) {\n this.worldContainer.visible = false;\n this.hudContainer.visible = false;\n return;\n }\n\n this.worldContainer.visible = true;\n this.hudContainer.visible = true;\n this.graphicsPool.resetFrame();\n this.textPool.resetFrame();\n\n for (const [name, contributor] of this.registry.contributors) {\n contributor.sample?.(this.stats, dt);\n\n if (contributor.drawWorld) {\n this.worldApi.setContributor(name);\n contributor.drawWorld(this.worldApi);\n }\n\n if (contributor.drawHud) {\n this.hudApi.setContributor(name);\n contributor.drawHud(this.hudApi);\n }\n }\n }\n}\n","import type { DebugContributor, StatsApi, HudDebugApi } from \"../types.js\";\n\nexport class FpsContributor implements DebugContributor {\n readonly name = \"fps\";\n readonly flags: readonly string[] = [];\n private stats: StatsApi | null = null;\n\n sample(stats: StatsApi, dt: number): void {\n this.stats = stats;\n if (dt > 0) stats.push(\"fps\", 1000 / dt);\n }\n\n drawHud(api: HudDebugApi): void {\n const avg = this.stats?.average(\"fps\") ?? 0;\n api.addLine(`FPS: ${Math.round(avg)}`);\n }\n}\n","import type { DebugContributor, HudDebugApi } from \"../types.js\";\nimport type { Inspector } from \"@yagejs/core\";\n\nexport class EntityCountContributor implements DebugContributor {\n readonly name = \"entities\";\n readonly flags: readonly string[] = [];\n\n constructor(private readonly inspector: Inspector) {}\n\n drawHud(api: HudDebugApi): void {\n const count = this.inspector.snapshot().entityCount;\n api.addLine(`Entities: ${count}`);\n }\n}\n","import type { DebugContributor, StatsApi, HudDebugApi } from \"../types.js\";\n\nexport class SystemTimingContributor implements DebugContributor {\n readonly name = \"timing\";\n readonly flags = [\"breakdown\"] as const;\n private stats: StatsApi | null = null;\n\n constructor(private readonly timings: Map<string, number>) {}\n\n sample(stats: StatsApi): void {\n this.stats = stats;\n for (const [name, ms] of this.timings) {\n stats.push(`system.${name}`, ms);\n }\n }\n\n drawHud(api: HudDebugApi): void {\n if (!this.stats) return;\n\n let total = 0;\n const entries: Array<[string, number]> = [];\n for (const name of this.timings.keys()) {\n const avg = this.stats.average(`system.${name}`);\n total += avg;\n entries.push([name, avg]);\n }\n\n api.addLine(`Systems: ${total.toFixed(2)}ms`);\n\n if (api.isFlagEnabled(\"breakdown\")) {\n entries.sort((a, b) => b[1] - a[1]);\n for (const [name, avg] of entries) {\n api.addLine(` ${name}: ${avg.toFixed(2)}ms`);\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
|