@driftengine/entities 4.7.4 → 4.8.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 +9 -0
- package/dist/index.d.ts +1 -1
- package/dist/schedule.d.ts +17 -4
- package/dist/schedule.js +10 -5
- package/package.json +2 -2
- package/src/index.ts +1 -1
- package/src/schedule.ts +26 -5
package/README.md
CHANGED
|
@@ -45,6 +45,15 @@ runSchedule(world, schedule, tick);
|
|
|
45
45
|
**The declaration is enforced.** A system that writes something it did not declare is refused
|
|
46
46
|
naming both — a schedule derived from a lie is worse than no schedule. `writes` implies `reads`.
|
|
47
47
|
|
|
48
|
+
**A system that throws is skipped, and the others still run.** By default the failure is logged once
|
|
49
|
+
per system per world. Pass a reporter as the fourth argument to take every failure, every tick, with
|
|
50
|
+
the system's name, the tick and the error, and nothing is logged; throw from it to make a failure
|
|
51
|
+
fatal while developing:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
runSchedule(world, schedule, tick, ({ system, tick, error }) => overlay.add(system, tick, error));
|
|
55
|
+
```
|
|
56
|
+
|
|
48
57
|
Order is declaration order, adjusted only by `after`, which is topologically sorted with
|
|
49
58
|
declaration order as the tie-break. A cycle in `after` is refused naming the systems.
|
|
50
59
|
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type { WorldSnapshot } from './world.ts';
|
|
|
25
25
|
export { World, createWorldSnapshot } from './world.ts';
|
|
26
26
|
export type { SystemDefinition, SystemView } from './system.ts';
|
|
27
27
|
export { BoundSystem } from './system.ts';
|
|
28
|
-
export type { Schedule } from './schedule.ts';
|
|
28
|
+
export type { Schedule, SystemFailure, SystemFailureReporter } from './schedule.ts';
|
|
29
29
|
export { buildSchedule, runSchedule } from './schedule.ts';
|
|
30
30
|
export type { Prefab } from './prefab.ts';
|
|
31
31
|
export { definePrefab, instantiate } from './prefab.ts';
|
package/dist/schedule.d.ts
CHANGED
|
@@ -37,8 +37,21 @@ export declare function buildSchedule(systems: readonly SystemDefinition[]): Sch
|
|
|
37
37
|
* function no longer throws, which is what `AGENTS.md` requires of anything the frame loop calls.
|
|
38
38
|
*
|
|
39
39
|
* **What it gives up** is the stack reaching a debugger's uncaught-exception break, which is how
|
|
40
|
-
* somebody working on a system would rather meet it.
|
|
41
|
-
*
|
|
42
|
-
* a
|
|
40
|
+
* somebody working on a system would rather meet it. So `report` takes the decision back: given one,
|
|
41
|
+
* every failure goes to it, every tick it happens, with the system's name, the tick and the error as
|
|
42
|
+
* thrown, and nothing is logged. A game can count failures, show them in a debug overlay, send them
|
|
43
|
+
* to its own telemetry, or throw from it to make a failure fatal in development, which stops the
|
|
44
|
+
* schedule there. Without one, the failure is said once per system per world, as above.
|
|
43
45
|
*/
|
|
44
|
-
export declare function runSchedule(world: World, schedule: Schedule, tick: number): void;
|
|
46
|
+
export declare function runSchedule(world: World, schedule: Schedule, tick: number, report?: SystemFailureReporter): void;
|
|
47
|
+
/** One system's failure in one step, as `runSchedule` hands it to a reporter. */
|
|
48
|
+
export interface SystemFailure {
|
|
49
|
+
/** The failing system's name, as its definition gave it. */
|
|
50
|
+
readonly system: string;
|
|
51
|
+
/** The tick it failed on: the `tick` the schedule was run with. */
|
|
52
|
+
readonly tick: number;
|
|
53
|
+
/** What the system threw, unchanged. */
|
|
54
|
+
readonly error: unknown;
|
|
55
|
+
}
|
|
56
|
+
/** Called with every failure, every tick. Throwing from it stops the schedule at that system. */
|
|
57
|
+
export type SystemFailureReporter = (failure: SystemFailure) => void;
|
package/dist/schedule.js
CHANGED
|
@@ -117,11 +117,13 @@ const reported = new WeakMap();
|
|
|
117
117
|
* function no longer throws, which is what `AGENTS.md` requires of anything the frame loop calls.
|
|
118
118
|
*
|
|
119
119
|
* **What it gives up** is the stack reaching a debugger's uncaught-exception break, which is how
|
|
120
|
-
* somebody working on a system would rather meet it.
|
|
121
|
-
*
|
|
122
|
-
* a
|
|
120
|
+
* somebody working on a system would rather meet it. So `report` takes the decision back: given one,
|
|
121
|
+
* every failure goes to it, every tick it happens, with the system's name, the tick and the error as
|
|
122
|
+
* thrown, and nothing is logged. A game can count failures, show them in a debug overlay, send them
|
|
123
|
+
* to its own telemetry, or throw from it to make a failure fatal in development, which stops the
|
|
124
|
+
* schedule there. Without one, the failure is said once per system per world, as above.
|
|
123
125
|
*/
|
|
124
|
-
export function runSchedule(world, schedule, tick) {
|
|
126
|
+
export function runSchedule(world, schedule, tick, report) {
|
|
125
127
|
let forWorld = bound.get(world);
|
|
126
128
|
if (forWorld === undefined) {
|
|
127
129
|
forWorld = new Map();
|
|
@@ -140,7 +142,10 @@ export function runSchedule(world, schedule, tick) {
|
|
|
140
142
|
system.run();
|
|
141
143
|
}
|
|
142
144
|
catch (error) {
|
|
143
|
-
|
|
145
|
+
if (report === undefined)
|
|
146
|
+
announce(world, definition, error);
|
|
147
|
+
else
|
|
148
|
+
report({ system: definition.name, tick, error });
|
|
144
149
|
}
|
|
145
150
|
}
|
|
146
151
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@driftengine/entities",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.1",
|
|
4
4
|
"description": "Entities with generational identity, component storage, systems and scenes",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"sideEffects": false,
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"driftscript": "1.
|
|
30
|
+
"driftscript": "1.16.0"
|
|
31
31
|
},
|
|
32
32
|
"author": "Drift Technologies",
|
|
33
33
|
"repository": {
|
package/src/index.ts
CHANGED
|
@@ -35,7 +35,7 @@ export { World, createWorldSnapshot } from './world.ts';
|
|
|
35
35
|
export type { SystemDefinition, SystemView } from './system.ts';
|
|
36
36
|
export { BoundSystem } from './system.ts';
|
|
37
37
|
|
|
38
|
-
export type { Schedule } from './schedule.ts';
|
|
38
|
+
export type { Schedule, SystemFailure, SystemFailureReporter } from './schedule.ts';
|
|
39
39
|
export { buildSchedule, runSchedule } from './schedule.ts';
|
|
40
40
|
|
|
41
41
|
export type { Prefab } from './prefab.ts';
|
package/src/schedule.ts
CHANGED
|
@@ -158,11 +158,18 @@ const reported = new WeakMap<World, Set<SystemDefinition>>();
|
|
|
158
158
|
* function no longer throws, which is what `AGENTS.md` requires of anything the frame loop calls.
|
|
159
159
|
*
|
|
160
160
|
* **What it gives up** is the stack reaching a debugger's uncaught-exception break, which is how
|
|
161
|
-
* somebody working on a system would rather meet it.
|
|
162
|
-
*
|
|
163
|
-
* a
|
|
161
|
+
* somebody working on a system would rather meet it. So `report` takes the decision back: given one,
|
|
162
|
+
* every failure goes to it, every tick it happens, with the system's name, the tick and the error as
|
|
163
|
+
* thrown, and nothing is logged. A game can count failures, show them in a debug overlay, send them
|
|
164
|
+
* to its own telemetry, or throw from it to make a failure fatal in development, which stops the
|
|
165
|
+
* schedule there. Without one, the failure is said once per system per world, as above.
|
|
164
166
|
*/
|
|
165
|
-
export function runSchedule(
|
|
167
|
+
export function runSchedule(
|
|
168
|
+
world: World,
|
|
169
|
+
schedule: Schedule,
|
|
170
|
+
tick: number,
|
|
171
|
+
report?: SystemFailureReporter,
|
|
172
|
+
): void {
|
|
166
173
|
let forWorld = bound.get(world);
|
|
167
174
|
if (forWorld === undefined) {
|
|
168
175
|
forWorld = new Map();
|
|
@@ -181,11 +188,25 @@ export function runSchedule(world: World, schedule: Schedule, tick: number): voi
|
|
|
181
188
|
try {
|
|
182
189
|
system.run();
|
|
183
190
|
} catch (error) {
|
|
184
|
-
announce(world, definition, error);
|
|
191
|
+
if (report === undefined) announce(world, definition, error);
|
|
192
|
+
else report({ system: definition.name, tick, error });
|
|
185
193
|
}
|
|
186
194
|
}
|
|
187
195
|
}
|
|
188
196
|
|
|
197
|
+
/** One system's failure in one step, as `runSchedule` hands it to a reporter. */
|
|
198
|
+
export interface SystemFailure {
|
|
199
|
+
/** The failing system's name, as its definition gave it. */
|
|
200
|
+
readonly system: string;
|
|
201
|
+
/** The tick it failed on: the `tick` the schedule was run with. */
|
|
202
|
+
readonly tick: number;
|
|
203
|
+
/** What the system threw, unchanged. */
|
|
204
|
+
readonly error: unknown;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Called with every failure, every tick. Throwing from it stops the schedule at that system. */
|
|
208
|
+
export type SystemFailureReporter = (failure: SystemFailure) => void;
|
|
209
|
+
|
|
189
210
|
/** Say what failed, once per system per world. */
|
|
190
211
|
function announce(world: World, definition: SystemDefinition, error: unknown): void {
|
|
191
212
|
let seen = reported.get(world);
|