archetype-ecs-lib 0.5.0 → 0.6.1
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 +1 -1
- package/lib/ecs/Archetype.js +1 -1
- package/lib/ecs/EntityManager.d.ts +3 -1
- package/lib/ecs/EntityManager.js +89 -0
- package/lib/ecs/Schedule.d.ts +128 -5
- package/lib/ecs/Schedule.js +390 -32
- package/lib/ecs/Types.d.ts +140 -3
- package/lib/ecs/World.d.ts +71 -6
- package/lib/ecs/World.js +562 -82
- package/lib/ecs/WorldSnapshotStore.d.ts +30 -0
- package/lib/ecs/WorldSnapshotStore.js +339 -0
- package/lib/ecs/stats/StatsOverlay.d.ts +72 -0
- package/lib/ecs/stats/StatsOverlay.js +548 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/package.json +8 -4
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Archetype } from "./Archetype";
|
|
2
|
+
import { Commands } from "./Commands";
|
|
3
|
+
import { EntityManager } from "./EntityManager";
|
|
4
|
+
import { EventChannel } from "./Events";
|
|
5
|
+
import type { ComponentCtor, Signature, SnapshotCodec, WorldSnapshot } from "./Types";
|
|
6
|
+
export type WorldSnapshotRuntime = Readonly<{
|
|
7
|
+
ensureNotIterating(op: string): void;
|
|
8
|
+
formatCtor(ctor: ComponentCtor<any>): string;
|
|
9
|
+
flush(): void;
|
|
10
|
+
resetArchetypes(): void;
|
|
11
|
+
getOrCreateArchetype(sig: Signature): Archetype;
|
|
12
|
+
commands: Commands;
|
|
13
|
+
entities: EntityManager;
|
|
14
|
+
archetypes: Archetype[];
|
|
15
|
+
resources: Map<ComponentCtor<any>, any>;
|
|
16
|
+
eventChannels: Map<ComponentCtor<any>, EventChannel<any>>;
|
|
17
|
+
}>;
|
|
18
|
+
export declare class WorldSnapshotStore {
|
|
19
|
+
private readonly componentSnapshotByCtor;
|
|
20
|
+
private readonly componentSnapshotCtorByKey;
|
|
21
|
+
private readonly resourceSnapshotByCtor;
|
|
22
|
+
private readonly resourceSnapshotCtorByKey;
|
|
23
|
+
registerComponentSnapshot<T, D = unknown>(runtime: Pick<WorldSnapshotRuntime, "formatCtor">, key: ComponentCtor<T>, codec: SnapshotCodec<T, D>): void;
|
|
24
|
+
unregisterComponentSnapshot<T>(key: ComponentCtor<T>): boolean;
|
|
25
|
+
registerResourceSnapshot<T, D = unknown>(runtime: Pick<WorldSnapshotRuntime, "formatCtor">, key: ComponentCtor<T>, codec: SnapshotCodec<T, D>): void;
|
|
26
|
+
unregisterResourceSnapshot<T>(key: ComponentCtor<T>): boolean;
|
|
27
|
+
snapshot(runtime: Pick<WorldSnapshotRuntime, "ensureNotIterating" | "flush" | "commands" | "archetypes" | "entities" | "resources">): WorldSnapshot;
|
|
28
|
+
restore(runtime: Pick<WorldSnapshotRuntime, "ensureNotIterating" | "commands" | "eventChannels" | "resources" | "entities" | "resetArchetypes" | "getOrCreateArchetype">, snapshot: WorldSnapshot): void;
|
|
29
|
+
private _normalizeSnapshotKey;
|
|
30
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __values = (this && this.__values) || function(o) {
|
|
3
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
4
|
+
if (m) return m.call(o);
|
|
5
|
+
if (o && typeof o.length === "number") return {
|
|
6
|
+
next: function () {
|
|
7
|
+
if (o && i >= o.length) o = void 0;
|
|
8
|
+
return { value: o && o[i++], done: !o };
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
12
|
+
};
|
|
13
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
14
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
15
|
+
if (!m) return o;
|
|
16
|
+
var i = m.call(o), r, ar = [], e;
|
|
17
|
+
try {
|
|
18
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
19
|
+
}
|
|
20
|
+
catch (error) { e = { error: error }; }
|
|
21
|
+
finally {
|
|
22
|
+
try {
|
|
23
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
24
|
+
}
|
|
25
|
+
finally { if (e) throw e.error; }
|
|
26
|
+
}
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.WorldSnapshotStore = void 0;
|
|
31
|
+
var TypeRegistry_1 = require("./TypeRegistry");
|
|
32
|
+
var WORLD_SNAPSHOT_FORMAT = "archetype-ecs/world-snapshot@1";
|
|
33
|
+
var WorldSnapshotStore = /** @class */ (function () {
|
|
34
|
+
function WorldSnapshotStore() {
|
|
35
|
+
this.componentSnapshotByCtor = new Map();
|
|
36
|
+
this.componentSnapshotCtorByKey = new Map();
|
|
37
|
+
this.resourceSnapshotByCtor = new Map();
|
|
38
|
+
this.resourceSnapshotCtorByKey = new Map();
|
|
39
|
+
}
|
|
40
|
+
WorldSnapshotStore.prototype.registerComponentSnapshot = function (runtime, key, codec) {
|
|
41
|
+
var snapshotKey = this._normalizeSnapshotKey(codec.key, "component");
|
|
42
|
+
var existingCtor = this.componentSnapshotCtorByKey.get(snapshotKey);
|
|
43
|
+
if (existingCtor && existingCtor !== key) {
|
|
44
|
+
throw new Error("registerComponentSnapshot(".concat(snapshotKey, ") failed: key already used by ").concat(runtime.formatCtor(existingCtor)));
|
|
45
|
+
}
|
|
46
|
+
var prev = this.componentSnapshotByCtor.get(key);
|
|
47
|
+
if (prev && prev.key !== snapshotKey)
|
|
48
|
+
this.componentSnapshotCtorByKey.delete(prev.key);
|
|
49
|
+
this.componentSnapshotByCtor.set(key, {
|
|
50
|
+
key: snapshotKey,
|
|
51
|
+
tid: (0, TypeRegistry_1.typeId)(key),
|
|
52
|
+
serialize: function (value) { return codec.serialize(value); },
|
|
53
|
+
deserialize: function (data) { return codec.deserialize(data); }
|
|
54
|
+
});
|
|
55
|
+
this.componentSnapshotCtorByKey.set(snapshotKey, key);
|
|
56
|
+
};
|
|
57
|
+
WorldSnapshotStore.prototype.unregisterComponentSnapshot = function (key) {
|
|
58
|
+
var prev = this.componentSnapshotByCtor.get(key);
|
|
59
|
+
if (!prev)
|
|
60
|
+
return false;
|
|
61
|
+
this.componentSnapshotByCtor.delete(key);
|
|
62
|
+
this.componentSnapshotCtorByKey.delete(prev.key);
|
|
63
|
+
return true;
|
|
64
|
+
};
|
|
65
|
+
WorldSnapshotStore.prototype.registerResourceSnapshot = function (runtime, key, codec) {
|
|
66
|
+
var snapshotKey = this._normalizeSnapshotKey(codec.key, "resource");
|
|
67
|
+
var existingCtor = this.resourceSnapshotCtorByKey.get(snapshotKey);
|
|
68
|
+
if (existingCtor && existingCtor !== key) {
|
|
69
|
+
throw new Error("registerResourceSnapshot(".concat(snapshotKey, ") failed: key already used by ").concat(runtime.formatCtor(existingCtor)));
|
|
70
|
+
}
|
|
71
|
+
var prev = this.resourceSnapshotByCtor.get(key);
|
|
72
|
+
if (prev && prev.key !== snapshotKey)
|
|
73
|
+
this.resourceSnapshotCtorByKey.delete(prev.key);
|
|
74
|
+
this.resourceSnapshotByCtor.set(key, {
|
|
75
|
+
key: snapshotKey,
|
|
76
|
+
serialize: function (value) { return codec.serialize(value); },
|
|
77
|
+
deserialize: function (data) { return codec.deserialize(data); }
|
|
78
|
+
});
|
|
79
|
+
this.resourceSnapshotCtorByKey.set(snapshotKey, key);
|
|
80
|
+
};
|
|
81
|
+
WorldSnapshotStore.prototype.unregisterResourceSnapshot = function (key) {
|
|
82
|
+
var prev = this.resourceSnapshotByCtor.get(key);
|
|
83
|
+
if (!prev)
|
|
84
|
+
return false;
|
|
85
|
+
this.resourceSnapshotByCtor.delete(key);
|
|
86
|
+
this.resourceSnapshotCtorByKey.delete(prev.key);
|
|
87
|
+
return true;
|
|
88
|
+
};
|
|
89
|
+
WorldSnapshotStore.prototype.snapshot = function (runtime) {
|
|
90
|
+
var e_1, _a, e_2, _b, e_3, _c, e_4, _d, e_5, _e;
|
|
91
|
+
var _f;
|
|
92
|
+
runtime.ensureNotIterating("snapshot");
|
|
93
|
+
if (runtime.commands.hasPending())
|
|
94
|
+
runtime.flush();
|
|
95
|
+
var componentRegs = [];
|
|
96
|
+
try {
|
|
97
|
+
for (var _g = __values(this.componentSnapshotByCtor), _h = _g.next(); !_h.done; _h = _g.next()) {
|
|
98
|
+
var _j = __read(_h.value, 2), reg = _j[1];
|
|
99
|
+
componentRegs.push(reg);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
103
|
+
finally {
|
|
104
|
+
try {
|
|
105
|
+
if (_h && !_h.done && (_a = _g.return)) _a.call(_g);
|
|
106
|
+
}
|
|
107
|
+
finally { if (e_1) throw e_1.error; }
|
|
108
|
+
}
|
|
109
|
+
componentRegs.sort(function (a, b) { return a.key.localeCompare(b.key); });
|
|
110
|
+
var serializedColumnsByArch = new Map();
|
|
111
|
+
try {
|
|
112
|
+
for (var _k = __values(runtime.archetypes), _l = _k.next(); !_l.done; _l = _k.next()) {
|
|
113
|
+
var a = _l.value;
|
|
114
|
+
if (!a)
|
|
115
|
+
continue;
|
|
116
|
+
var cols = [];
|
|
117
|
+
try {
|
|
118
|
+
for (var componentRegs_1 = (e_3 = void 0, __values(componentRegs)), componentRegs_1_1 = componentRegs_1.next(); !componentRegs_1_1.done; componentRegs_1_1 = componentRegs_1.next()) {
|
|
119
|
+
var reg = componentRegs_1_1.value;
|
|
120
|
+
if (!a.has(reg.tid))
|
|
121
|
+
continue;
|
|
122
|
+
cols.push({
|
|
123
|
+
type: reg.key,
|
|
124
|
+
column: a.column(reg.tid),
|
|
125
|
+
serialize: reg.serialize
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
130
|
+
finally {
|
|
131
|
+
try {
|
|
132
|
+
if (componentRegs_1_1 && !componentRegs_1_1.done && (_c = componentRegs_1.return)) _c.call(componentRegs_1);
|
|
133
|
+
}
|
|
134
|
+
finally { if (e_3) throw e_3.error; }
|
|
135
|
+
}
|
|
136
|
+
serializedColumnsByArch.set(a.id, cols);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
140
|
+
finally {
|
|
141
|
+
try {
|
|
142
|
+
if (_l && !_l.done && (_b = _k.return)) _b.call(_k);
|
|
143
|
+
}
|
|
144
|
+
finally { if (e_2) throw e_2.error; }
|
|
145
|
+
}
|
|
146
|
+
var entities = [];
|
|
147
|
+
for (var id = 1; id < runtime.entities.meta.length; id++) {
|
|
148
|
+
var m = runtime.entities.meta[id];
|
|
149
|
+
if (!m || !m.alive)
|
|
150
|
+
continue;
|
|
151
|
+
var cols = (_f = serializedColumnsByArch.get(m.arch)) !== null && _f !== void 0 ? _f : [];
|
|
152
|
+
var components = new Array(cols.length);
|
|
153
|
+
for (var i = 0; i < cols.length; i++) {
|
|
154
|
+
var c = cols[i];
|
|
155
|
+
components[i] = {
|
|
156
|
+
type: c.type,
|
|
157
|
+
data: c.serialize(c.column[m.row])
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
entities.push({ id: id, gen: m.gen, components: components });
|
|
161
|
+
}
|
|
162
|
+
var resourceRegs = [];
|
|
163
|
+
try {
|
|
164
|
+
for (var _m = __values(this.resourceSnapshotByCtor), _o = _m.next(); !_o.done; _o = _m.next()) {
|
|
165
|
+
var _p = __read(_o.value, 2), ctor = _p[0], reg = _p[1];
|
|
166
|
+
resourceRegs.push({ ctor: ctor, reg: reg });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
170
|
+
finally {
|
|
171
|
+
try {
|
|
172
|
+
if (_o && !_o.done && (_d = _m.return)) _d.call(_m);
|
|
173
|
+
}
|
|
174
|
+
finally { if (e_4) throw e_4.error; }
|
|
175
|
+
}
|
|
176
|
+
resourceRegs.sort(function (a, b) { return a.reg.key.localeCompare(b.reg.key); });
|
|
177
|
+
var resources = [];
|
|
178
|
+
try {
|
|
179
|
+
for (var resourceRegs_1 = __values(resourceRegs), resourceRegs_1_1 = resourceRegs_1.next(); !resourceRegs_1_1.done; resourceRegs_1_1 = resourceRegs_1.next()) {
|
|
180
|
+
var entry = resourceRegs_1_1.value;
|
|
181
|
+
if (!runtime.resources.has(entry.ctor))
|
|
182
|
+
continue;
|
|
183
|
+
resources.push({
|
|
184
|
+
type: entry.reg.key,
|
|
185
|
+
data: entry.reg.serialize(runtime.resources.get(entry.ctor))
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
190
|
+
finally {
|
|
191
|
+
try {
|
|
192
|
+
if (resourceRegs_1_1 && !resourceRegs_1_1.done && (_e = resourceRegs_1.return)) _e.call(resourceRegs_1);
|
|
193
|
+
}
|
|
194
|
+
finally { if (e_5) throw e_5.error; }
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
format: WORLD_SNAPSHOT_FORMAT,
|
|
198
|
+
allocator: runtime.entities.snapshotAllocator(),
|
|
199
|
+
entities: entities,
|
|
200
|
+
resources: resources
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
WorldSnapshotStore.prototype.restore = function (runtime, snapshot) {
|
|
204
|
+
var e_6, _a, e_7, _b, e_8, _c, e_9, _d, e_10, _e;
|
|
205
|
+
runtime.ensureNotIterating("restore");
|
|
206
|
+
if (snapshot.format !== WORLD_SNAPSHOT_FORMAT) {
|
|
207
|
+
throw new Error("Unsupported world snapshot format \"".concat(snapshot.format, "\". ") +
|
|
208
|
+
"Expected \"".concat(WORLD_SNAPSHOT_FORMAT, "\"."));
|
|
209
|
+
}
|
|
210
|
+
runtime.commands.drain();
|
|
211
|
+
try {
|
|
212
|
+
for (var _f = __values(runtime.eventChannels.values()), _g = _f.next(); !_g.done; _g = _f.next()) {
|
|
213
|
+
var ch = _g.value;
|
|
214
|
+
ch.clearAll();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
218
|
+
finally {
|
|
219
|
+
try {
|
|
220
|
+
if (_g && !_g.done && (_a = _f.return)) _a.call(_f);
|
|
221
|
+
}
|
|
222
|
+
finally { if (e_6) throw e_6.error; }
|
|
223
|
+
}
|
|
224
|
+
runtime.resources.clear();
|
|
225
|
+
runtime.entities.restoreAllocator(snapshot.allocator);
|
|
226
|
+
runtime.resetArchetypes();
|
|
227
|
+
var seenResourceTypes = new Set();
|
|
228
|
+
try {
|
|
229
|
+
for (var _h = __values(snapshot.resources), _j = _h.next(); !_j.done; _j = _h.next()) {
|
|
230
|
+
var resource = _j.value;
|
|
231
|
+
if (seenResourceTypes.has(resource.type)) {
|
|
232
|
+
throw new Error("Duplicate snapshot resource type \"".concat(resource.type, "\""));
|
|
233
|
+
}
|
|
234
|
+
seenResourceTypes.add(resource.type);
|
|
235
|
+
var ctor = this.resourceSnapshotCtorByKey.get(resource.type);
|
|
236
|
+
if (!ctor) {
|
|
237
|
+
throw new Error("Missing resource snapshot codec for \"".concat(resource.type, "\". Register it before restore()."));
|
|
238
|
+
}
|
|
239
|
+
var reg = this.resourceSnapshotByCtor.get(ctor);
|
|
240
|
+
runtime.resources.set(ctor, reg.deserialize(resource.data));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
244
|
+
finally {
|
|
245
|
+
try {
|
|
246
|
+
if (_j && !_j.done && (_b = _h.return)) _b.call(_h);
|
|
247
|
+
}
|
|
248
|
+
finally { if (e_7) throw e_7.error; }
|
|
249
|
+
}
|
|
250
|
+
var freeSet = new Set(snapshot.allocator.free);
|
|
251
|
+
var seenEntityIds = new Set();
|
|
252
|
+
try {
|
|
253
|
+
for (var _k = __values(snapshot.entities), _l = _k.next(); !_l.done; _l = _k.next()) {
|
|
254
|
+
var entity = _l.value;
|
|
255
|
+
if (!Number.isInteger(entity.id) || entity.id <= 0) {
|
|
256
|
+
throw new Error("Invalid snapshot entity id: ".concat(entity.id));
|
|
257
|
+
}
|
|
258
|
+
if (!Number.isInteger(entity.gen) || entity.gen <= 0) {
|
|
259
|
+
throw new Error("Invalid snapshot entity generation for id ".concat(entity.id, ": ").concat(entity.gen));
|
|
260
|
+
}
|
|
261
|
+
if (seenEntityIds.has(entity.id)) {
|
|
262
|
+
throw new Error("Duplicate snapshot entity id ".concat(entity.id));
|
|
263
|
+
}
|
|
264
|
+
seenEntityIds.add(entity.id);
|
|
265
|
+
if (freeSet.has(entity.id)) {
|
|
266
|
+
throw new Error("Invalid snapshot: entity id ".concat(entity.id, " is both alive and free"));
|
|
267
|
+
}
|
|
268
|
+
var meta = runtime.entities.meta[entity.id];
|
|
269
|
+
if (!meta) {
|
|
270
|
+
throw new Error("Invalid snapshot: missing allocator generation entry for entity id ".concat(entity.id, ". ") +
|
|
271
|
+
"Ensure snapshot.allocator.generations includes all alive ids.");
|
|
272
|
+
}
|
|
273
|
+
if (meta.gen !== entity.gen) {
|
|
274
|
+
throw new Error("Invalid snapshot: allocator generation mismatch for entity id ".concat(entity.id, ". ") +
|
|
275
|
+
"Expected gen ".concat(meta.gen, ", got ").concat(entity.gen, "."));
|
|
276
|
+
}
|
|
277
|
+
var componentValues = new Map();
|
|
278
|
+
var seenComponentTypes = new Set();
|
|
279
|
+
try {
|
|
280
|
+
for (var _m = (e_9 = void 0, __values(entity.components)), _o = _m.next(); !_o.done; _o = _m.next()) {
|
|
281
|
+
var component = _o.value;
|
|
282
|
+
if (seenComponentTypes.has(component.type)) {
|
|
283
|
+
throw new Error("Duplicate component type \"".concat(component.type, "\" on entity ").concat(entity.id));
|
|
284
|
+
}
|
|
285
|
+
seenComponentTypes.add(component.type);
|
|
286
|
+
var ctor = this.componentSnapshotCtorByKey.get(component.type);
|
|
287
|
+
if (!ctor) {
|
|
288
|
+
throw new Error("Missing component snapshot codec for \"".concat(component.type, "\". Register it before restore()."));
|
|
289
|
+
}
|
|
290
|
+
var reg = this.componentSnapshotByCtor.get(ctor);
|
|
291
|
+
componentValues.set(reg.tid, reg.deserialize(component.data));
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch (e_9_1) { e_9 = { error: e_9_1 }; }
|
|
295
|
+
finally {
|
|
296
|
+
try {
|
|
297
|
+
if (_o && !_o.done && (_d = _m.return)) _d.call(_m);
|
|
298
|
+
}
|
|
299
|
+
finally { if (e_9) throw e_9.error; }
|
|
300
|
+
}
|
|
301
|
+
var sig = Array.from(componentValues.keys()).sort(function (a, b) { return a - b; });
|
|
302
|
+
var a = runtime.getOrCreateArchetype(sig);
|
|
303
|
+
var row = a.addRow({ id: entity.id, gen: entity.gen });
|
|
304
|
+
try {
|
|
305
|
+
for (var sig_1 = (e_10 = void 0, __values(sig)), sig_1_1 = sig_1.next(); !sig_1_1.done; sig_1_1 = sig_1.next()) {
|
|
306
|
+
var t = sig_1_1.value;
|
|
307
|
+
a.column(t).push(componentValues.get(t));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
catch (e_10_1) { e_10 = { error: e_10_1 }; }
|
|
311
|
+
finally {
|
|
312
|
+
try {
|
|
313
|
+
if (sig_1_1 && !sig_1_1.done && (_e = sig_1.return)) _e.call(sig_1);
|
|
314
|
+
}
|
|
315
|
+
finally { if (e_10) throw e_10.error; }
|
|
316
|
+
}
|
|
317
|
+
meta.alive = true;
|
|
318
|
+
meta.arch = a.id;
|
|
319
|
+
meta.row = row;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
323
|
+
finally {
|
|
324
|
+
try {
|
|
325
|
+
if (_l && !_l.done && (_c = _k.return)) _c.call(_k);
|
|
326
|
+
}
|
|
327
|
+
finally { if (e_8) throw e_8.error; }
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
WorldSnapshotStore.prototype._normalizeSnapshotKey = function (key, kind) {
|
|
331
|
+
var normalized = key.trim();
|
|
332
|
+
if (normalized.length === 0) {
|
|
333
|
+
throw new Error("register".concat(kind === "component" ? "Component" : "Resource", "Snapshot() failed: codec.key must be a non-empty string"));
|
|
334
|
+
}
|
|
335
|
+
return normalized;
|
|
336
|
+
};
|
|
337
|
+
return WorldSnapshotStore;
|
|
338
|
+
}());
|
|
339
|
+
exports.WorldSnapshotStore = WorldSnapshotStore;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { WorldStats, WorldStatsHistory } from "../Types";
|
|
2
|
+
export type StatsOverlayOptions = Readonly<{
|
|
3
|
+
/** Parent element to attach the overlay to. Defaults to document.body */
|
|
4
|
+
parent?: HTMLElement;
|
|
5
|
+
/** Fixed positioning offsets */
|
|
6
|
+
left?: number;
|
|
7
|
+
top?: number;
|
|
8
|
+
/** Canvas size */
|
|
9
|
+
width?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
/** Target frame timeline (ms). Defaults to 16.67 (60fps). */
|
|
12
|
+
targetFrameMs?: number;
|
|
13
|
+
/** Threshold where bars become "slow" (ms). Defaults to 20. */
|
|
14
|
+
slowFrameMs?: number;
|
|
15
|
+
/** How many history samples to render (uses world history capacity). */
|
|
16
|
+
maxSamples?: number;
|
|
17
|
+
}>;
|
|
18
|
+
export declare class StatsOverlay {
|
|
19
|
+
private root;
|
|
20
|
+
private header;
|
|
21
|
+
private toggleButton;
|
|
22
|
+
private debugToggleButton;
|
|
23
|
+
private content;
|
|
24
|
+
private text;
|
|
25
|
+
private canvas;
|
|
26
|
+
private ctx;
|
|
27
|
+
private opts;
|
|
28
|
+
private resizeObserver;
|
|
29
|
+
private isExpanded;
|
|
30
|
+
private debugLoggingEnabled;
|
|
31
|
+
private isInitialized;
|
|
32
|
+
private debugingEnabled;
|
|
33
|
+
protected _profilingEnabled: boolean;
|
|
34
|
+
protected _frameCounter: number;
|
|
35
|
+
protected _lastDt: number;
|
|
36
|
+
protected _lastFrameMs: number;
|
|
37
|
+
protected readonly _phaseMs: Map<string, number>;
|
|
38
|
+
protected readonly _systemMs: Map<string, number>;
|
|
39
|
+
protected _historyCapacity: number;
|
|
40
|
+
protected readonly _histDt: number[];
|
|
41
|
+
protected readonly _histFrameMs: number[];
|
|
42
|
+
protected readonly _histPhaseMs: Map<string, number[]>;
|
|
43
|
+
protected readonly _histSystemMs: Map<string, number[]>;
|
|
44
|
+
private isDragging;
|
|
45
|
+
private dragOffsetX;
|
|
46
|
+
private dragOffsetY;
|
|
47
|
+
constructor(options?: StatsOverlayOptions);
|
|
48
|
+
private initializeDom;
|
|
49
|
+
setDebugging(enabled: boolean): void;
|
|
50
|
+
setProfilingEnabled(enabled: boolean): void;
|
|
51
|
+
setProfilingHistorySize(frames: number): void;
|
|
52
|
+
protected _trimHistoryToCapacity(): void;
|
|
53
|
+
protected _pushSeriesFrame(series: Map<string, number[]>, current: Map<string, number>): void;
|
|
54
|
+
/** @internal Called by Schedule/World.update to start a new profiling frame */
|
|
55
|
+
_profBeginFrame(dt: number): number;
|
|
56
|
+
/** @internal Called by Schedule/World.update to end a new profiling frame */
|
|
57
|
+
_profEndFrame(frameStartMs: number): void;
|
|
58
|
+
/** @internal */
|
|
59
|
+
_profAddPhase(phase: string, ms: number): void;
|
|
60
|
+
/** @internal */
|
|
61
|
+
_profAddSystem(name: string, ms: number): void;
|
|
62
|
+
private createDebugToggleButton;
|
|
63
|
+
private toggleDebugLogging;
|
|
64
|
+
private setupDrag;
|
|
65
|
+
private resizeCanvas;
|
|
66
|
+
private toggle;
|
|
67
|
+
destroyOverlay(): void;
|
|
68
|
+
/** Convenience: call each frame */
|
|
69
|
+
updateOverlay(stats: WorldStats, statsHistory: WorldStatsHistory): void;
|
|
70
|
+
private render;
|
|
71
|
+
private drawFrameGraph;
|
|
72
|
+
}
|