@aura3d/core 1.0.6
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 +51 -0
- package/dist/Diagnostics.d.ts +25 -0
- package/dist/Diagnostics.d.ts.map +1 -0
- package/dist/Diagnostics.js +60 -0
- package/dist/Diagnostics.js.map +1 -0
- package/dist/Disposable.d.ts +12 -0
- package/dist/Disposable.d.ts.map +1 -0
- package/dist/Disposable.js +37 -0
- package/dist/Disposable.js.map +1 -0
- package/dist/Engine.d.ts +46 -0
- package/dist/Engine.d.ts.map +1 -0
- package/dist/Engine.js +130 -0
- package/dist/Engine.js.map +1 -0
- package/dist/EngineConfig.d.ts +18 -0
- package/dist/EngineConfig.d.ts.map +1 -0
- package/dist/EngineConfig.js +23 -0
- package/dist/EngineConfig.js.map +1 -0
- package/dist/EngineLoop.d.ts +33 -0
- package/dist/EngineLoop.d.ts.map +1 -0
- package/dist/EngineLoop.js +63 -0
- package/dist/EngineLoop.js.map +1 -0
- package/dist/Errors.d.ts +14 -0
- package/dist/Errors.d.ts.map +1 -0
- package/dist/Errors.js +24 -0
- package/dist/Errors.js.map +1 -0
- package/dist/EventBus.d.ts +18 -0
- package/dist/EventBus.d.ts.map +1 -0
- package/dist/EventBus.js +45 -0
- package/dist/EventBus.js.map +1 -0
- package/dist/FixedStepAccumulator.d.ts +15 -0
- package/dist/FixedStepAccumulator.d.ts.map +1 -0
- package/dist/FixedStepAccumulator.js +34 -0
- package/dist/FixedStepAccumulator.js.map +1 -0
- package/dist/Logger.d.ts +23 -0
- package/dist/Logger.d.ts.map +1 -0
- package/dist/Logger.js +53 -0
- package/dist/Logger.js.map +1 -0
- package/dist/ResourceScope.d.ts +18 -0
- package/dist/ResourceScope.d.ts.map +1 -0
- package/dist/ResourceScope.js +53 -0
- package/dist/ResourceScope.js.map +1 -0
- package/dist/Scheduler.d.ts +31 -0
- package/dist/Scheduler.d.ts.map +1 -0
- package/dist/Scheduler.js +77 -0
- package/dist/Scheduler.js.map +1 -0
- package/dist/TaskQueue.d.ts +13 -0
- package/dist/TaskQueue.d.ts.map +1 -0
- package/dist/TaskQueue.js +42 -0
- package/dist/TaskQueue.js.map +1 -0
- package/dist/Time.d.ts +24 -0
- package/dist/Time.d.ts.map +1 -0
- package/dist/Time.js +45 -0
- package/dist/Time.js.map +1 -0
- package/dist/VersionedSerialization.d.ts +96 -0
- package/dist/VersionedSerialization.d.ts.map +1 -0
- package/dist/VersionedSerialization.js +278 -0
- package/dist/VersionedSerialization.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/package.json +16 -0
- package/src/Diagnostics.ts +80 -0
- package/src/Disposable.ts +41 -0
- package/src/Engine.ts +140 -0
- package/src/EngineConfig.ts +38 -0
- package/src/EngineLoop.ts +83 -0
- package/src/Errors.ts +28 -0
- package/src/EventBus.ts +52 -0
- package/src/FixedStepAccumulator.ts +39 -0
- package/src/Logger.ts +67 -0
- package/src/ResourceScope.ts +55 -0
- package/src/Scheduler.ts +94 -0
- package/src/TaskQueue.ts +50 -0
- package/src/Time.ts +54 -0
- package/src/VersionedSerialization.ts +351 -0
- package/src/index.ts +14 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VersionedSerialization.d.ts","sourceRoot":"","sources":["../../../../packages/core/src/VersionedSerialization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { ValidationError } from "./Errors.js";
|
|
2
|
+
export class VersionedSchema {
|
|
3
|
+
name;
|
|
4
|
+
version;
|
|
5
|
+
fields = new Map();
|
|
6
|
+
constructor(name, version) {
|
|
7
|
+
this.name = name;
|
|
8
|
+
this.version = version;
|
|
9
|
+
if (!name.trim())
|
|
10
|
+
throw new ValidationError("SCHEMA_NAME", "VersionedSchema requires a non-empty name.");
|
|
11
|
+
if (!Number.isSafeInteger(version) || version < 0)
|
|
12
|
+
throw new ValidationError("SCHEMA_VERSION", "VersionedSchema version must be a non-negative integer.");
|
|
13
|
+
}
|
|
14
|
+
addField(field) {
|
|
15
|
+
if (!field.name.trim())
|
|
16
|
+
throw new ValidationError("SCHEMA_FIELD", "Schema field requires a non-empty name.");
|
|
17
|
+
if (this.fields.has(field.name))
|
|
18
|
+
throw new ValidationError("SCHEMA_FIELD_DUPLICATE", `Duplicate schema field: ${field.name}`);
|
|
19
|
+
if (field.kind === "array" && !field.elementKind)
|
|
20
|
+
throw new ValidationError("SCHEMA_ARRAY_ELEMENT", `Array field ${field.name} requires elementKind.`);
|
|
21
|
+
this.fields.set(field.name, field);
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
getField(name) {
|
|
25
|
+
return this.fields.get(name);
|
|
26
|
+
}
|
|
27
|
+
getFields() {
|
|
28
|
+
return [...this.fields.values()];
|
|
29
|
+
}
|
|
30
|
+
validate(data) {
|
|
31
|
+
const issues = [];
|
|
32
|
+
if (!isRecord(data)) {
|
|
33
|
+
return { ok: false, issues: [`${this.name} must be an object.`] };
|
|
34
|
+
}
|
|
35
|
+
for (const field of this.fields.values()) {
|
|
36
|
+
const value = data[field.name];
|
|
37
|
+
if (value === undefined) {
|
|
38
|
+
if (field.required && field.defaultValue === undefined)
|
|
39
|
+
issues.push(`${field.name} is required.`);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
collectTypeIssues(value, field, field.name, issues);
|
|
43
|
+
}
|
|
44
|
+
return { ok: issues.length === 0, issues };
|
|
45
|
+
}
|
|
46
|
+
serialize(data) {
|
|
47
|
+
const validation = this.validate(data);
|
|
48
|
+
if (!validation.ok)
|
|
49
|
+
throw new ValidationError("SCHEMA_VALIDATE", validation.issues.join(" "));
|
|
50
|
+
const record = data;
|
|
51
|
+
const result = {};
|
|
52
|
+
for (const field of this.fields.values()) {
|
|
53
|
+
const value = record[field.name];
|
|
54
|
+
if (value !== undefined) {
|
|
55
|
+
result[field.name] = value;
|
|
56
|
+
}
|
|
57
|
+
else if (field.defaultValue !== undefined) {
|
|
58
|
+
result[field.name] = cloneValue(field.defaultValue);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
deserialize(data) {
|
|
64
|
+
return this.serialize(data);
|
|
65
|
+
}
|
|
66
|
+
static builder(name, version) {
|
|
67
|
+
return new VersionedSchemaBuilder(name, version);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export class VersionedSchemaBuilder {
|
|
71
|
+
schema;
|
|
72
|
+
constructor(name, version) {
|
|
73
|
+
this.schema = new VersionedSchema(name, version);
|
|
74
|
+
}
|
|
75
|
+
boolean(name, options = {}) {
|
|
76
|
+
return this.field({ name, kind: "boolean", ...options });
|
|
77
|
+
}
|
|
78
|
+
int32(name, options = {}) {
|
|
79
|
+
return this.field({ name, kind: "int32", ...options });
|
|
80
|
+
}
|
|
81
|
+
uint32(name, options = {}) {
|
|
82
|
+
return this.field({ name, kind: "uint32", ...options });
|
|
83
|
+
}
|
|
84
|
+
float32(name, options = {}) {
|
|
85
|
+
return this.field({ name, kind: "float32", ...options });
|
|
86
|
+
}
|
|
87
|
+
string(name, options = {}) {
|
|
88
|
+
return this.field({ name, kind: "string", ...options });
|
|
89
|
+
}
|
|
90
|
+
array(name, elementKind, options = {}) {
|
|
91
|
+
return this.field({ name, kind: "array", elementKind, ...options });
|
|
92
|
+
}
|
|
93
|
+
object(name, schema, options = {}) {
|
|
94
|
+
return this.field({ name, kind: "object", schema, ...options });
|
|
95
|
+
}
|
|
96
|
+
field(field) {
|
|
97
|
+
this.schema.addField(field);
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
build() {
|
|
101
|
+
return this.schema;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export class MigrationRegistry {
|
|
105
|
+
migrations = new Map();
|
|
106
|
+
register(migration) {
|
|
107
|
+
if (!Number.isSafeInteger(migration.from) || !Number.isSafeInteger(migration.to) || migration.to <= migration.from) {
|
|
108
|
+
throw new ValidationError("MIGRATION_VERSION", "Migration must move from a lower integer version to a higher integer version.");
|
|
109
|
+
}
|
|
110
|
+
const list = this.migrations.get(migration.from) ?? [];
|
|
111
|
+
if (list.some((entry) => entry.to === migration.to)) {
|
|
112
|
+
throw new ValidationError("MIGRATION_DUPLICATE", `Duplicate migration path: ${migration.from} -> ${migration.to}`);
|
|
113
|
+
}
|
|
114
|
+
list.push(migration);
|
|
115
|
+
list.sort((left, right) => left.to - right.to);
|
|
116
|
+
this.migrations.set(migration.from, list);
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
canMigrate(from, to) {
|
|
120
|
+
try {
|
|
121
|
+
this.plan(from, to);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
migrate(data, from, to) {
|
|
129
|
+
let current = data;
|
|
130
|
+
for (const migration of this.plan(from, to)) {
|
|
131
|
+
current = migration.migrate(current);
|
|
132
|
+
}
|
|
133
|
+
return current;
|
|
134
|
+
}
|
|
135
|
+
list() {
|
|
136
|
+
return [...this.migrations.values()].flat().sort((left, right) => left.from - right.from || left.to - right.to);
|
|
137
|
+
}
|
|
138
|
+
plan(from, to) {
|
|
139
|
+
if (from === to)
|
|
140
|
+
return [];
|
|
141
|
+
if (!Number.isSafeInteger(from) || !Number.isSafeInteger(to) || from > to) {
|
|
142
|
+
throw new ValidationError("MIGRATION_TARGET", "Migration target must be an integer version greater than or equal to the source.");
|
|
143
|
+
}
|
|
144
|
+
const plan = [];
|
|
145
|
+
let current = from;
|
|
146
|
+
while (current < to) {
|
|
147
|
+
const next = (this.migrations.get(current) ?? []).find((migration) => migration.to <= to);
|
|
148
|
+
if (!next)
|
|
149
|
+
throw new ValidationError("MIGRATION_PATH", `No migration path from version ${current} to ${to}.`);
|
|
150
|
+
plan.push(next);
|
|
151
|
+
current = next.to;
|
|
152
|
+
}
|
|
153
|
+
return plan;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export class SaveSlot {
|
|
157
|
+
id;
|
|
158
|
+
data = null;
|
|
159
|
+
format = "json";
|
|
160
|
+
timestamp;
|
|
161
|
+
metadata = {};
|
|
162
|
+
compressed = false;
|
|
163
|
+
constructor(id, timestamp = Date.now()) {
|
|
164
|
+
this.id = id;
|
|
165
|
+
if (!id.trim())
|
|
166
|
+
throw new ValidationError("SAVE_SLOT_ID", "SaveSlot requires a non-empty id.");
|
|
167
|
+
this.timestamp = timestamp;
|
|
168
|
+
}
|
|
169
|
+
setData(data, format, options = {}) {
|
|
170
|
+
this.data = typeof data === "string" ? data : new Uint8Array(data);
|
|
171
|
+
this.format = format;
|
|
172
|
+
this.compressed = options.compressed ?? false;
|
|
173
|
+
this.timestamp = Date.now();
|
|
174
|
+
}
|
|
175
|
+
getData() {
|
|
176
|
+
return typeof this.data === "string" || this.data === null ? this.data : new Uint8Array(this.data);
|
|
177
|
+
}
|
|
178
|
+
getFormat() {
|
|
179
|
+
return this.format;
|
|
180
|
+
}
|
|
181
|
+
getTimestamp() {
|
|
182
|
+
return this.timestamp;
|
|
183
|
+
}
|
|
184
|
+
getMetadata() {
|
|
185
|
+
return { ...this.metadata };
|
|
186
|
+
}
|
|
187
|
+
setMetadata(metadata) {
|
|
188
|
+
this.metadata = { ...this.metadata, ...metadata };
|
|
189
|
+
}
|
|
190
|
+
isCompressed() {
|
|
191
|
+
return this.compressed;
|
|
192
|
+
}
|
|
193
|
+
getSize() {
|
|
194
|
+
if (this.data === null)
|
|
195
|
+
return 0;
|
|
196
|
+
return typeof this.data === "string" ? new TextEncoder().encode(this.data).byteLength : this.data.byteLength;
|
|
197
|
+
}
|
|
198
|
+
toJSON() {
|
|
199
|
+
return {
|
|
200
|
+
id: this.id,
|
|
201
|
+
format: this.format,
|
|
202
|
+
timestamp: this.timestamp,
|
|
203
|
+
metadata: { ...this.metadata },
|
|
204
|
+
compressed: this.compressed,
|
|
205
|
+
data: this.data instanceof Uint8Array ? bytesToBase64(this.data) : this.data ?? ""
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
static fromJSON(serialized) {
|
|
209
|
+
const slot = new SaveSlot(serialized.id, serialized.timestamp);
|
|
210
|
+
slot.format = serialized.format;
|
|
211
|
+
slot.metadata = { ...serialized.metadata };
|
|
212
|
+
slot.compressed = serialized.compressed;
|
|
213
|
+
slot.data = serialized.format === "binary" ? base64ToBytes(serialized.data) : serialized.data;
|
|
214
|
+
return slot;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function collectTypeIssues(value, field, path, issues) {
|
|
218
|
+
if (!matchesKind(value, field.kind)) {
|
|
219
|
+
issues.push(`${path} expected ${field.kind}.`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (field.kind === "array" && field.elementKind && Array.isArray(value)) {
|
|
223
|
+
value.forEach((entry, index) => {
|
|
224
|
+
if (!matchesKind(entry, field.elementKind))
|
|
225
|
+
issues.push(`${path}[${index}] expected ${field.elementKind}.`);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
if (field.kind === "object" && field.schema) {
|
|
229
|
+
const nested = field.schema.validate(value);
|
|
230
|
+
for (const issue of nested.issues)
|
|
231
|
+
issues.push(`${path}.${issue}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function matchesKind(value, kind) {
|
|
235
|
+
switch (kind) {
|
|
236
|
+
case "boolean":
|
|
237
|
+
return typeof value === "boolean";
|
|
238
|
+
case "int32":
|
|
239
|
+
return Number.isInteger(value) && Number(value) >= -2147483648 && Number(value) <= 2147483647;
|
|
240
|
+
case "uint32":
|
|
241
|
+
return Number.isInteger(value) && Number(value) >= 0 && Number(value) <= 4294967295;
|
|
242
|
+
case "float32":
|
|
243
|
+
case "float64":
|
|
244
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
245
|
+
case "string":
|
|
246
|
+
return typeof value === "string";
|
|
247
|
+
case "array":
|
|
248
|
+
return Array.isArray(value);
|
|
249
|
+
case "object":
|
|
250
|
+
return isRecord(value);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function cloneValue(value) {
|
|
254
|
+
if (typeof structuredClone === "function")
|
|
255
|
+
return structuredClone(value);
|
|
256
|
+
return JSON.parse(JSON.stringify(value));
|
|
257
|
+
}
|
|
258
|
+
function isRecord(value) {
|
|
259
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
260
|
+
}
|
|
261
|
+
function bytesToBase64(bytes) {
|
|
262
|
+
if (typeof Buffer !== "undefined")
|
|
263
|
+
return Buffer.from(bytes).toString("base64");
|
|
264
|
+
let binary = "";
|
|
265
|
+
for (const byte of bytes)
|
|
266
|
+
binary += String.fromCharCode(byte);
|
|
267
|
+
return btoa(binary);
|
|
268
|
+
}
|
|
269
|
+
function base64ToBytes(base64) {
|
|
270
|
+
if (typeof Buffer !== "undefined")
|
|
271
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
272
|
+
const binary = atob(base64);
|
|
273
|
+
const bytes = new Uint8Array(binary.length);
|
|
274
|
+
for (let index = 0; index < binary.length; index += 1)
|
|
275
|
+
bytes[index] = binary.charCodeAt(index);
|
|
276
|
+
return bytes;
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=VersionedSerialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VersionedSerialization.js","sourceRoot":"","sources":["../../../../packages/core/src/VersionedSerialization.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./Engine.js";
|
|
2
|
+
export * from "./EngineConfig.js";
|
|
3
|
+
export * from "./EngineLoop.js";
|
|
4
|
+
export * from "./Time.js";
|
|
5
|
+
export * from "./FixedStepAccumulator.js";
|
|
6
|
+
export * from "./EventBus.js";
|
|
7
|
+
export * from "./Scheduler.js";
|
|
8
|
+
export * from "./TaskQueue.js";
|
|
9
|
+
export * from "./Logger.js";
|
|
10
|
+
export * from "./Diagnostics.js";
|
|
11
|
+
export * from "./Errors.js";
|
|
12
|
+
export * from "./Disposable.js";
|
|
13
|
+
export * from "./ResourceScope.js";
|
|
14
|
+
export * from "./VersionedSerialization.js";
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./Engine.js";
|
|
2
|
+
export * from "./EngineConfig.js";
|
|
3
|
+
export * from "./EngineLoop.js";
|
|
4
|
+
export * from "./Time.js";
|
|
5
|
+
export * from "./FixedStepAccumulator.js";
|
|
6
|
+
export * from "./EventBus.js";
|
|
7
|
+
export * from "./Scheduler.js";
|
|
8
|
+
export * from "./TaskQueue.js";
|
|
9
|
+
export * from "./Logger.js";
|
|
10
|
+
export * from "./Diagnostics.js";
|
|
11
|
+
export * from "./Errors.js";
|
|
12
|
+
export * from "./Disposable.js";
|
|
13
|
+
export * from "./ResourceScope.js";
|
|
14
|
+
export * from "./VersionedSerialization.js";
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aura3d/core",
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@aura3d/math": "1.0.6"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export type MetricKind = "counter" | "gauge" | "timing";
|
|
2
|
+
|
|
3
|
+
export interface MetricSnapshot {
|
|
4
|
+
readonly kind: MetricKind;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly value: number;
|
|
7
|
+
readonly samples: readonly number[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DiagnosticsSnapshot {
|
|
11
|
+
readonly metrics: readonly MetricSnapshot[];
|
|
12
|
+
readonly timestamp: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface MutableMetric {
|
|
16
|
+
kind: MetricKind;
|
|
17
|
+
value: number;
|
|
18
|
+
samples: number[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class Diagnostics {
|
|
22
|
+
private readonly metrics = new Map<string, MutableMetric>();
|
|
23
|
+
private readonly activeTimers = new Map<string, number>();
|
|
24
|
+
|
|
25
|
+
constructor(private readonly maxHistory = 120) {}
|
|
26
|
+
|
|
27
|
+
increment(name: string, amount = 1): void {
|
|
28
|
+
const metric = this.ensure(name, "counter");
|
|
29
|
+
metric.value += amount;
|
|
30
|
+
this.recordSample(metric, metric.value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
gauge(name: string, value: number): void {
|
|
34
|
+
const metric = this.ensure(name, "gauge");
|
|
35
|
+
metric.value = value;
|
|
36
|
+
this.recordSample(metric, value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
begin(name: string): void {
|
|
40
|
+
if (this.activeTimers.has(name)) throw new Error(`Timer ${name} already started.`);
|
|
41
|
+
this.activeTimers.set(name, performance.now());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
end(name: string): number {
|
|
45
|
+
const start = this.activeTimers.get(name);
|
|
46
|
+
if (start === undefined) throw new Error(`Timer ${name} was not started.`);
|
|
47
|
+
this.activeTimers.delete(name);
|
|
48
|
+
const duration = performance.now() - start;
|
|
49
|
+
const metric = this.ensure(name, "timing");
|
|
50
|
+
metric.value = duration;
|
|
51
|
+
this.recordSample(metric, duration);
|
|
52
|
+
return duration;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
snapshot(): DiagnosticsSnapshot {
|
|
56
|
+
const metrics = [...this.metrics.entries()].map(([name, metric]) => Object.freeze({
|
|
57
|
+
kind: metric.kind,
|
|
58
|
+
name,
|
|
59
|
+
value: metric.value,
|
|
60
|
+
samples: Object.freeze([...metric.samples])
|
|
61
|
+
}));
|
|
62
|
+
return Object.freeze({ metrics: Object.freeze(metrics), timestamp: Date.now() });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private ensure(name: string, kind: MetricKind): MutableMetric {
|
|
66
|
+
const existing = this.metrics.get(name);
|
|
67
|
+
if (existing) {
|
|
68
|
+
if (existing.kind !== kind) throw new Error(`Metric ${name} already exists as ${existing.kind}.`);
|
|
69
|
+
return existing;
|
|
70
|
+
}
|
|
71
|
+
const metric: MutableMetric = { kind, value: 0, samples: [] };
|
|
72
|
+
this.metrics.set(name, metric);
|
|
73
|
+
return metric;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private recordSample(metric: MutableMetric, value: number): void {
|
|
77
|
+
metric.samples.push(value);
|
|
78
|
+
if (metric.samples.length > this.maxHistory) metric.samples.shift();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface Disposable {
|
|
2
|
+
dispose(): void | Promise<void>;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function isDisposable(value: unknown): value is Disposable {
|
|
6
|
+
return typeof value === "object" && value !== null && "dispose" in value && typeof (value as Disposable).dispose === "function";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class DisposableStack implements Disposable {
|
|
10
|
+
private readonly entries: Disposable[] = [];
|
|
11
|
+
private disposed = false;
|
|
12
|
+
|
|
13
|
+
use<T extends Disposable>(resource: T): T {
|
|
14
|
+
if (this.disposed) {
|
|
15
|
+
throw new Error("Cannot add a disposable to an already disposed stack.");
|
|
16
|
+
}
|
|
17
|
+
this.entries.push(resource);
|
|
18
|
+
return resource;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get size(): number {
|
|
22
|
+
return this.entries.length;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async dispose(): Promise<void> {
|
|
26
|
+
if (this.disposed) return;
|
|
27
|
+
this.disposed = true;
|
|
28
|
+
|
|
29
|
+
const errors: unknown[] = [];
|
|
30
|
+
while (this.entries.length > 0) {
|
|
31
|
+
const entry = this.entries.pop();
|
|
32
|
+
if (!entry) continue;
|
|
33
|
+
try {
|
|
34
|
+
await entry.dispose();
|
|
35
|
+
} catch (error) {
|
|
36
|
+
errors.push(error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (errors.length > 0) throw new AggregateError(errors, "One or more disposables failed.");
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/Engine.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { DisposableStack } from "./Disposable.js";
|
|
2
|
+
import { EngineLoop, type FrameContext } from "./EngineLoop.js";
|
|
3
|
+
import { resolveEngineConfig, type EngineConfig, type ResolvedEngineConfig } from "./EngineConfig.js";
|
|
4
|
+
import { LifecycleError } from "./Errors.js";
|
|
5
|
+
import { EventBus } from "./EventBus.js";
|
|
6
|
+
import { Diagnostics } from "./Diagnostics.js";
|
|
7
|
+
import { Logger } from "./Logger.js";
|
|
8
|
+
import { ResourceScope } from "./ResourceScope.js";
|
|
9
|
+
import { Scheduler, SystemPhase } from "./Scheduler.js";
|
|
10
|
+
import { TaskQueue } from "./TaskQueue.js";
|
|
11
|
+
|
|
12
|
+
export type EngineState = "created" | "initializing" | "initialized" | "running" | "stopped" | "disposed" | "failed";
|
|
13
|
+
|
|
14
|
+
export interface EngineEvents {
|
|
15
|
+
stateChanged: { readonly previous: EngineState; readonly current: EngineState };
|
|
16
|
+
frame: FrameContext;
|
|
17
|
+
error: unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface EnginePlugin {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
init?(engine: Engine): void | Promise<void>;
|
|
23
|
+
dispose?(): void | Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class Engine {
|
|
27
|
+
readonly config: ResolvedEngineConfig;
|
|
28
|
+
readonly events = new EventBus<EngineEvents>((error) => this.events.emit("error", error));
|
|
29
|
+
readonly diagnostics = new Diagnostics();
|
|
30
|
+
readonly logger = new Logger();
|
|
31
|
+
readonly scheduler = new Scheduler();
|
|
32
|
+
readonly tasks = new TaskQueue();
|
|
33
|
+
readonly resources = new ResourceScope("engine");
|
|
34
|
+
|
|
35
|
+
private readonly plugins: EnginePlugin[] = [];
|
|
36
|
+
private readonly pluginDisposables = new DisposableStack();
|
|
37
|
+
private readonly loop: EngineLoop;
|
|
38
|
+
private stateValue: EngineState = "created";
|
|
39
|
+
|
|
40
|
+
constructor(config: EngineConfig = {}) {
|
|
41
|
+
this.config = resolveEngineConfig(config);
|
|
42
|
+
this.loop = new EngineLoop({
|
|
43
|
+
mode: "manual",
|
|
44
|
+
fixedDelta: this.config.fixedDelta,
|
|
45
|
+
maxDelta: this.config.maxDelta,
|
|
46
|
+
maxFixedSteps: this.config.maxFixedSteps,
|
|
47
|
+
timeScale: this.config.timeScale
|
|
48
|
+
}, (context) => this.runFrame(context));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get state(): EngineState {
|
|
52
|
+
return this.stateValue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
use(plugin: EnginePlugin): this {
|
|
56
|
+
if (this.stateValue !== "created") throw new LifecycleError("PLUGIN_AFTER_INIT", "Plugins must be registered before init.");
|
|
57
|
+
if (this.plugins.some((existing) => existing.id === plugin.id)) throw new LifecycleError("DUPLICATE_PLUGIN", `Plugin ${plugin.id} already registered.`);
|
|
58
|
+
this.plugins.push(plugin);
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async init(): Promise<void> {
|
|
63
|
+
if (this.stateValue === "initialized" || this.stateValue === "running" || this.stateValue === "stopped") return;
|
|
64
|
+
if (this.stateValue !== "created") throw new LifecycleError("INVALID_INIT", `Cannot init engine from ${this.stateValue}.`);
|
|
65
|
+
this.setState("initializing");
|
|
66
|
+
try {
|
|
67
|
+
for (const plugin of this.plugins) {
|
|
68
|
+
await plugin.init?.(this);
|
|
69
|
+
if (plugin.dispose) this.pluginDisposables.use({ dispose: () => plugin.dispose?.() });
|
|
70
|
+
}
|
|
71
|
+
this.setState("initialized");
|
|
72
|
+
if (this.config.autoStart) this.start();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
this.setState("failed");
|
|
75
|
+
await this.pluginDisposables.dispose();
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
start(): void {
|
|
81
|
+
if (this.stateValue !== "initialized" && this.stateValue !== "stopped") throw new LifecycleError("START_BEFORE_INIT", "Engine must be initialized before start.");
|
|
82
|
+
this.loop.start();
|
|
83
|
+
this.setState("running");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
stop(): void {
|
|
87
|
+
if (this.stateValue !== "running") return;
|
|
88
|
+
this.loop.stop();
|
|
89
|
+
this.setState("stopped");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async step(delta: number): Promise<FrameContext> {
|
|
93
|
+
if (this.stateValue === "created") await this.init();
|
|
94
|
+
if (this.stateValue !== "initialized" && this.stateValue !== "running" && this.stateValue !== "stopped") {
|
|
95
|
+
throw new LifecycleError("STEP_INVALID_STATE", `Cannot step engine from ${this.stateValue}.`);
|
|
96
|
+
}
|
|
97
|
+
return this.loop.step(delta);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async dispose(): Promise<void> {
|
|
101
|
+
if (this.stateValue === "disposed") return;
|
|
102
|
+
if (this.stateValue === "running") this.stop();
|
|
103
|
+
const errors: unknown[] = [];
|
|
104
|
+
try {
|
|
105
|
+
await this.pluginDisposables.dispose();
|
|
106
|
+
} catch (error) {
|
|
107
|
+
errors.push(error);
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
await this.resources.dispose();
|
|
111
|
+
} catch (error) {
|
|
112
|
+
errors.push(error);
|
|
113
|
+
}
|
|
114
|
+
this.events.clear();
|
|
115
|
+
this.setState("disposed");
|
|
116
|
+
if (errors.length > 0) throw new AggregateError(errors, "Engine disposal failed.");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private async runFrame(context: FrameContext): Promise<void> {
|
|
120
|
+
this.diagnostics.increment("frames");
|
|
121
|
+
await this.scheduler.runPhase(SystemPhase.Platform);
|
|
122
|
+
await this.scheduler.runPhase(SystemPhase.Tasks);
|
|
123
|
+
await this.tasks.flush();
|
|
124
|
+
for (let step = 0; step < context.fixedSteps; step++) {
|
|
125
|
+
await this.scheduler.runPhase(SystemPhase.Fixed, step);
|
|
126
|
+
}
|
|
127
|
+
await this.scheduler.runPhase(SystemPhase.Update);
|
|
128
|
+
await this.scheduler.runPhase(SystemPhase.Scene);
|
|
129
|
+
await this.scheduler.runPhase(SystemPhase.Render);
|
|
130
|
+
await this.scheduler.runPhase(SystemPhase.Present);
|
|
131
|
+
await this.scheduler.runPhase(SystemPhase.Cleanup);
|
|
132
|
+
this.events.emit("frame", context);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private setState(next: EngineState): void {
|
|
136
|
+
const previous = this.stateValue;
|
|
137
|
+
this.stateValue = next;
|
|
138
|
+
this.events.emit("stateChanged", Object.freeze({ previous, current: next }));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ValidationError } from "./Errors.js";
|
|
2
|
+
|
|
3
|
+
export interface EngineConfig {
|
|
4
|
+
targetFPS?: number;
|
|
5
|
+
fixedDelta?: number;
|
|
6
|
+
maxDelta?: number;
|
|
7
|
+
maxFixedSteps?: number;
|
|
8
|
+
timeScale?: number;
|
|
9
|
+
autoStart?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ResolvedEngineConfig {
|
|
13
|
+
readonly targetFPS: number;
|
|
14
|
+
readonly fixedDelta: number;
|
|
15
|
+
readonly maxDelta: number;
|
|
16
|
+
readonly maxFixedSteps: number;
|
|
17
|
+
readonly timeScale: number;
|
|
18
|
+
readonly autoStart: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function resolveEngineConfig(config: EngineConfig = {}): ResolvedEngineConfig {
|
|
22
|
+
const resolved = {
|
|
23
|
+
targetFPS: config.targetFPS ?? 60,
|
|
24
|
+
fixedDelta: config.fixedDelta ?? 1 / 60,
|
|
25
|
+
maxDelta: config.maxDelta ?? 0.25,
|
|
26
|
+
maxFixedSteps: config.maxFixedSteps ?? 5,
|
|
27
|
+
timeScale: config.timeScale ?? 1,
|
|
28
|
+
autoStart: config.autoStart ?? false
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
if (!Number.isFinite(resolved.targetFPS) || resolved.targetFPS <= 0) throw new ValidationError("INVALID_TARGET_FPS", "targetFPS must be positive.");
|
|
32
|
+
if (!Number.isFinite(resolved.fixedDelta) || resolved.fixedDelta <= 0) throw new ValidationError("INVALID_FIXED_DELTA", "fixedDelta must be positive.");
|
|
33
|
+
if (!Number.isFinite(resolved.maxDelta) || resolved.maxDelta <= 0) throw new ValidationError("INVALID_MAX_DELTA", "maxDelta must be positive.");
|
|
34
|
+
if (!Number.isInteger(resolved.maxFixedSteps) || resolved.maxFixedSteps <= 0) throw new ValidationError("INVALID_MAX_FIXED_STEPS", "maxFixedSteps must be a positive integer.");
|
|
35
|
+
if (!Number.isFinite(resolved.timeScale) || resolved.timeScale < 0) throw new ValidationError("INVALID_TIME_SCALE", "timeScale must be finite and non-negative.");
|
|
36
|
+
|
|
37
|
+
return Object.freeze(resolved);
|
|
38
|
+
}
|