@vworlds/vecs 1.0.10 → 1.0.12
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/.husky/pre-commit +1 -0
- package/README.md +299 -228
- package/dist/command.d.ts +1 -46
- package/dist/component.d.ts +51 -59
- package/dist/component.js +31 -25
- package/dist/component.js.map +1 -1
- package/dist/dsl.d.ts +34 -26
- package/dist/dsl.js +46 -20
- package/dist/dsl.js.map +1 -1
- package/dist/entity.d.ts +96 -106
- package/dist/entity.js +261 -190
- package/dist/entity.js.map +1 -1
- package/dist/filter.d.ts +31 -23
- package/dist/filter.js +24 -17
- package/dist/filter.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/package.json +3 -1
- package/dist/phase.d.ts +12 -30
- package/dist/phase.js +11 -10
- package/dist/phase.js.map +1 -1
- package/dist/query.d.ts +107 -144
- package/dist/query.js +200 -169
- package/dist/query.js.map +1 -1
- package/dist/system.d.ts +170 -86
- package/dist/system.js +253 -114
- package/dist/system.js.map +1 -1
- package/dist/timer.d.ts +50 -0
- package/dist/timer.js +154 -0
- package/dist/timer.js.map +1 -0
- package/dist/util/array_map.d.ts +4 -55
- package/dist/util/array_map.js +35 -37
- package/dist/util/array_map.js.map +1 -1
- package/dist/util/bitset.d.ts +40 -50
- package/dist/util/bitset.js +76 -62
- package/dist/util/bitset.js.map +1 -1
- package/dist/util/events.d.ts +14 -18
- package/dist/util/events.js +24 -3
- package/dist/util/events.js.map +1 -1
- package/dist/util/ordered_set.d.ts +1 -17
- package/dist/util/ordered_set.js +74 -25
- package/dist/util/ordered_set.js.map +1 -1
- package/dist/world.d.ts +230 -218
- package/dist/world.js +422 -327
- package/dist/world.js.map +1 -1
- package/eslint-rules/internal-underscore.js +60 -0
- package/eslint.config.js +5 -0
- package/package.json +3 -1
package/dist/world.d.ts
CHANGED
|
@@ -4,21 +4,21 @@ import { Query } from "./query.js";
|
|
|
4
4
|
import { System } from "./system.js";
|
|
5
5
|
import { Filter } from "./filter.js";
|
|
6
6
|
import { type QueryDSL, type ExtractRequired } from "./dsl.js";
|
|
7
|
-
import { IPhase
|
|
8
|
-
import { type Command } from "./command.js";
|
|
7
|
+
import { IPhase } from "./phase.js";
|
|
9
8
|
/**
|
|
10
|
-
* The central ECS container.
|
|
9
|
+
* The central ECS container. One world per game session.
|
|
11
10
|
*
|
|
12
|
-
* A `World` owns
|
|
13
|
-
* pipeline.
|
|
11
|
+
* A `World` owns every entity, every registered component class, every
|
|
12
|
+
* registered query / system, and the update pipeline. The typical lifecycle:
|
|
14
13
|
*
|
|
15
|
-
* 1. **Register components** —
|
|
16
|
-
* {@link registerComponentType}) for every component class.
|
|
17
|
-
* 2. **
|
|
18
|
-
*
|
|
14
|
+
* 1. **Register components** — {@link registerComponent} (and optionally
|
|
15
|
+
* {@link registerComponentType}) for every component class you plan to use.
|
|
16
|
+
* 2. **Build the pipeline** — {@link addPhase} for every named phase, then
|
|
17
|
+
* {@link system} / {@link query} for each processor.
|
|
19
18
|
* 3. **Start** — call {@link start} to freeze component registration and
|
|
20
19
|
* distribute systems into their phases.
|
|
21
|
-
* 4. **Run loop** — call {@link runPhase}
|
|
20
|
+
* 4. **Run loop** — call {@link runPhase} per phase or {@link progress} for
|
|
21
|
+
* every phase, once per frame.
|
|
22
22
|
*
|
|
23
23
|
* ```ts
|
|
24
24
|
* const world = new World();
|
|
@@ -28,204 +28,234 @@ import { type Command } from "./command.js";
|
|
|
28
28
|
*
|
|
29
29
|
* world.system("Move")
|
|
30
30
|
* .requires(Position, Velocity)
|
|
31
|
-
* .
|
|
31
|
+
* .each([Position, Velocity], (e, [pos, vel]) => {
|
|
32
|
+
* pos.x += vel.vx;
|
|
33
|
+
* });
|
|
32
34
|
*
|
|
33
35
|
* world.start();
|
|
34
36
|
*
|
|
35
37
|
* // game loop:
|
|
36
|
-
* world.
|
|
38
|
+
* world.progress(now, delta);
|
|
37
39
|
* ```
|
|
40
|
+
*
|
|
41
|
+
* ## Deferred mode
|
|
42
|
+
*
|
|
43
|
+
* The world can be in **deferred mode**, in which case entity mutations
|
|
44
|
+
* (`add` / `set` / `remove` / `destroy` / `setParent` / `modified`) are
|
|
45
|
+
* queued instead of applied inline. Systems run inside an automatically
|
|
46
|
+
* deferred scope; user code can wrap arbitrary blocks with
|
|
47
|
+
* {@link beginDefer} / {@link endDefer} or {@link defer}. {@link flush}
|
|
48
|
+
* drains the queue at top level.
|
|
38
49
|
*/
|
|
39
50
|
export declare class World {
|
|
40
|
-
private _entities;
|
|
41
|
-
private componentNameTypeMap;
|
|
42
|
-
private _queries;
|
|
43
|
-
private Class2Meta;
|
|
44
|
-
private Type2Meta;
|
|
45
|
-
private localComponentCounter;
|
|
46
|
-
private componentRegistrationDisabled;
|
|
47
|
-
/** @internal Single ordered command queue used in deferred mode. */
|
|
48
|
-
private commandQueue;
|
|
49
|
-
/** @internal Nested `beginDefer` / `endDefer` count. */
|
|
50
|
-
private deferredDepth;
|
|
51
|
-
/** @internal True while `processCommandQueue` is iterating, to avoid re-entrant drains. */
|
|
52
|
-
private draining;
|
|
53
|
-
/** `true` when the world is in deferred mode — mutations are queued rather than applied immediately. */
|
|
54
|
-
get deferred(): boolean;
|
|
55
|
-
/** @internal */
|
|
56
|
-
_pipeline: Map<string, Phase>;
|
|
57
|
-
private eidCounter;
|
|
58
51
|
constructor();
|
|
59
|
-
/**
|
|
52
|
+
/** Read-only view of the live entities, keyed by entity id. */
|
|
60
53
|
get entities(): Omit<Map<number, Entity>, "set" | "delete" | "clear">;
|
|
61
|
-
/**
|
|
54
|
+
/** Read-only view of every registered query (includes systems). */
|
|
62
55
|
get queries(): ReadonlyArray<Query>;
|
|
63
56
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
57
|
+
* `true` while the world is in deferred mode — entity mutations are queued
|
|
58
|
+
* rather than applied inline. Equivalent to "the queue depth is non-zero or
|
|
59
|
+
* the world is currently draining".
|
|
60
|
+
*/
|
|
61
|
+
get deferred(): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Enter deferred mode. Mutations made until the matching {@link endDefer}
|
|
64
|
+
* are queued instead of executing inline.
|
|
67
65
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*
|
|
66
|
+
* Nested `beginDefer` / `endDefer` pairs are allowed; only the outermost
|
|
67
|
+
* `endDefer` triggers a queue drain.
|
|
68
|
+
*/
|
|
69
|
+
beginDefer(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Leave deferred mode. When the depth returns to zero the world drains the
|
|
72
|
+
* command queue (firing hooks and routing enter / exit / update events).
|
|
73
|
+
*/
|
|
74
|
+
endDefer(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Run `fn` inside a deferred scope. Equivalent to
|
|
77
|
+
* `beginDefer(); try { fn(); } finally { endDefer(); }`.
|
|
74
78
|
*
|
|
75
|
-
* @param
|
|
76
|
-
* @param onCreateCallback - Optional callback invoked only when a **new**
|
|
77
|
-
* entity is created, before it is returned. Use this to initialise
|
|
78
|
-
* bookkeeping (e.g. tracking it in a local set).
|
|
79
|
-
* @returns The existing or newly created entity.
|
|
79
|
+
* @param fn - Callback executed in deferred mode.
|
|
80
80
|
*/
|
|
81
|
-
|
|
81
|
+
defer(fn: () => void): void;
|
|
82
82
|
/**
|
|
83
|
-
*
|
|
83
|
+
* Drain any commands queued at the top level (depth 0).
|
|
84
84
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
85
|
+
* Call between phases or after batch-loading network snapshots to surface
|
|
86
|
+
* accumulated mutations (firing hooks and routing enter / exit / update)
|
|
87
|
+
* before the next read or system run.
|
|
87
88
|
*/
|
|
88
|
-
|
|
89
|
+
flush(): void;
|
|
89
90
|
/**
|
|
90
|
-
*
|
|
91
|
+
* Pre-register a `componentName → typeId` mapping without binding a class.
|
|
91
92
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
93
|
+
* Useful when network messages refer to components by type id and the
|
|
94
|
+
* corresponding class may be registered later. Call this **before**
|
|
95
|
+
* {@link registerComponent} so the class picks up the server-assigned id
|
|
96
|
+
* rather than a locally generated one.
|
|
97
|
+
*
|
|
98
|
+
* @param componentName - String name used in network payloads.
|
|
99
|
+
* @param type - Numeric type id assigned by the server.
|
|
94
100
|
*/
|
|
95
|
-
|
|
101
|
+
registerComponentType(componentName: string, type: number): void;
|
|
96
102
|
/**
|
|
97
|
-
*
|
|
103
|
+
* Register a component class with the world.
|
|
98
104
|
*
|
|
99
|
-
* Must be called
|
|
100
|
-
* {@link
|
|
101
|
-
*
|
|
102
|
-
* client entities can start at a high offset to avoid collisions with
|
|
103
|
-
* server-assigned ids.
|
|
105
|
+
* Must be called before any entity uses the component. Registration is
|
|
106
|
+
* disabled once {@link start} (or {@link disableComponentRegistration}) is
|
|
107
|
+
* called.
|
|
104
108
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
109
|
+
* **Overloads:**
|
|
110
|
+
* - `registerComponent(Class)` — type id auto-assigned from the
|
|
111
|
+
* {@link registerComponentType} map, falling back to a local counter
|
|
112
|
+
* (≥ 256) if the name is not yet mapped.
|
|
113
|
+
* - `registerComponent(Class, type)` — explicit numeric type id.
|
|
114
|
+
* - `registerComponent(Class, componentName)` — auto-assigned id, custom
|
|
115
|
+
* display name (useful when the class name differs from the network name).
|
|
116
|
+
* - `registerComponent(Class, type, componentName)` — explicit id + name.
|
|
117
|
+
*
|
|
118
|
+
* @param ComponentClass - Component class to register.
|
|
119
|
+
* @throws When the class has already been registered or registration is
|
|
120
|
+
* disabled.
|
|
107
121
|
*/
|
|
108
|
-
|
|
122
|
+
registerComponent(ComponentClass: typeof Component): void;
|
|
123
|
+
registerComponent(ComponentClass: typeof Component, type: number): void;
|
|
124
|
+
registerComponent(ComponentClass: typeof Component, componentName?: string): void;
|
|
125
|
+
registerComponent(ComponentClass: typeof Component, type: number, componentName: string): void;
|
|
109
126
|
/**
|
|
110
|
-
*
|
|
127
|
+
* Look up the {@link ComponentMeta} for a registered component.
|
|
111
128
|
*
|
|
112
|
-
* @param typeOrClass -
|
|
113
|
-
* @returns The corresponding
|
|
114
|
-
* @throws
|
|
129
|
+
* @param typeOrClass - Component class or numeric type id.
|
|
130
|
+
* @returns The corresponding meta record.
|
|
131
|
+
* @throws When no component with that class or type id has been registered.
|
|
115
132
|
*/
|
|
116
133
|
getComponentMeta(typeOrClass: ComponentClassOrType): ComponentMeta;
|
|
117
134
|
/**
|
|
118
135
|
* Resolve a component class or type id to its numeric type id.
|
|
119
136
|
*
|
|
120
|
-
* @param typeOrClass -
|
|
137
|
+
* @param typeOrClass - Component class or numeric type id.
|
|
121
138
|
* @returns The numeric type id.
|
|
122
139
|
*/
|
|
123
140
|
getComponentType(typeOrClass: ComponentClassOrType): number;
|
|
124
141
|
/**
|
|
125
|
-
*
|
|
126
|
-
* are queued instead of executing inline.
|
|
142
|
+
* Return the {@link Hook} for a component class.
|
|
127
143
|
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
144
|
+
* Hooks let you react to component lifecycle events (add / remove / set)
|
|
145
|
+
* without building a full {@link System}. The same hook is returned on every
|
|
146
|
+
* call — handlers stack on the underlying meta record.
|
|
130
147
|
*
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
*
|
|
135
|
-
*
|
|
148
|
+
* ```ts
|
|
149
|
+
* world.hook(Sprite)
|
|
150
|
+
* .onAdd(c => c.initialize(scene))
|
|
151
|
+
* .onRemove(c => c.destroy());
|
|
152
|
+
* ```
|
|
136
153
|
*
|
|
154
|
+
* @param C - Component class.
|
|
155
|
+
* @returns The hook bound to that component type.
|
|
137
156
|
*/
|
|
138
|
-
|
|
157
|
+
hook<T extends typeof Component>(C: T): Hook<InstanceType<T>>;
|
|
139
158
|
/**
|
|
159
|
+
* Declare a group of mutually exclusive components.
|
|
140
160
|
*
|
|
141
|
-
*
|
|
161
|
+
* Adding any component in the group to an entity that already has another
|
|
162
|
+
* member of the group automatically removes the previous member. Members
|
|
163
|
+
* not in the group are unaffected.
|
|
164
|
+
*
|
|
165
|
+
* ```ts
|
|
166
|
+
* world.setExclusiveComponents(Walking, Running, Idle);
|
|
167
|
+
* entity.add(Walking);
|
|
168
|
+
* entity.add(Running); // Walking is removed automatically
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* Each call defines one independent group. A component may belong to at
|
|
172
|
+
* most one group at a time; calling {@link setExclusiveComponents} with the
|
|
173
|
+
* same class again overwrites its group. Safe to call before or after
|
|
174
|
+
* {@link start}.
|
|
175
|
+
*
|
|
176
|
+
* @param components - Two or more component classes that cannot coexist.
|
|
177
|
+
* @throws When any class has not been registered.
|
|
142
178
|
*/
|
|
143
|
-
|
|
179
|
+
setExclusiveComponents(...components: (typeof Component)[]): void;
|
|
144
180
|
/**
|
|
145
|
-
*
|
|
181
|
+
* Set the starting value of the auto-incrementing entity id counter.
|
|
182
|
+
*
|
|
183
|
+
* Must be called **before** {@link start} (or
|
|
184
|
+
* {@link disableComponentRegistration}). Useful when the world runs
|
|
185
|
+
* alongside a server that owns a different id range — locally created
|
|
186
|
+
* client entities can start at a high offset to avoid collisions with
|
|
187
|
+
* server-assigned ids.
|
|
146
188
|
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* the next read or system run.
|
|
189
|
+
* @param min - First id assigned by {@link entity}.
|
|
190
|
+
* @throws When called after registration has been disabled.
|
|
150
191
|
*/
|
|
151
|
-
|
|
152
|
-
/** @internal Append a command to the queue. */
|
|
153
|
-
_enqueue(cmd: Command): void;
|
|
192
|
+
setEntityIdRange(min: number): void;
|
|
154
193
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
194
|
+
* Return the entity with id `eid`, creating it if it does not yet exist.
|
|
195
|
+
*
|
|
196
|
+
* Used by networking code to materialise server-assigned entities:
|
|
197
|
+
*
|
|
198
|
+
* ```ts
|
|
199
|
+
* const e = world.getOrCreateEntity(snapshot.eid, (e) => {
|
|
200
|
+
* networkEntities.add(e);
|
|
201
|
+
* });
|
|
202
|
+
* e.add(snapshot.type);
|
|
203
|
+
* ```
|
|
204
|
+
*
|
|
205
|
+
* @param eid - Entity id to look up or create.
|
|
206
|
+
* @param onCreateCallback - Optional callback invoked only when a new
|
|
207
|
+
* entity is created, before it is returned. Use it to initialise
|
|
208
|
+
* bookkeeping (e.g. tracking it in a local set).
|
|
209
|
+
* @returns The existing or newly created entity.
|
|
158
210
|
*/
|
|
159
|
-
|
|
211
|
+
getOrCreateEntity(eid: number, onCreateCallback?: (e: Entity) => void): Entity;
|
|
160
212
|
/**
|
|
161
|
-
*
|
|
162
|
-
*
|
|
213
|
+
* Create a new entity with an auto-assigned id.
|
|
214
|
+
*
|
|
215
|
+
* The id counter starts at `0` (or at the value set by
|
|
216
|
+
* {@link setEntityIdRange}) and increments by one for each call. In
|
|
217
|
+
* deferred mode the new entity is queued onto the command queue and is not
|
|
218
|
+
* visible in {@link entities} until the queue drains.
|
|
163
219
|
*/
|
|
164
|
-
|
|
165
|
-
/** @internal Remove an entity from the world's entity map. Called by Entity._destroy. */
|
|
166
|
-
_unregisterEntity(entity: Entity): void;
|
|
220
|
+
entity(): Entity;
|
|
167
221
|
/**
|
|
168
|
-
*
|
|
222
|
+
* Look up an existing entity by id.
|
|
169
223
|
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* **Overloads:**
|
|
174
|
-
* - `registerComponent(Class)` — type id auto-assigned from the name map, or
|
|
175
|
-
* from a local counter (≥ 256) if the name is not yet mapped.
|
|
176
|
-
* - `registerComponent(Class, type)` — explicit numeric type id.
|
|
177
|
-
* - `registerComponent(Class, componentName)` — auto-assigned id, custom
|
|
178
|
-
* display name (useful when the class name differs from the network name).
|
|
179
|
-
* - `registerComponent(Class, type, componentName)` — explicit id + name.
|
|
180
|
-
*
|
|
181
|
-
* @param ComponentClass - The component class to register.
|
|
182
|
-
* @throws If the class has already been registered, or if registration is
|
|
183
|
-
* disabled.
|
|
224
|
+
* @param id - Numeric entity id.
|
|
225
|
+
* @returns The entity, or `undefined` when no entity with that id exists.
|
|
184
226
|
*/
|
|
185
|
-
|
|
186
|
-
registerComponent(ComponentClass: typeof Component, type: number): void;
|
|
187
|
-
registerComponent(ComponentClass: typeof Component, componentName?: string): void;
|
|
188
|
-
registerComponent(ComponentClass: typeof Component, type: number, componentName: string): void;
|
|
227
|
+
entity(id: number): Entity | undefined;
|
|
189
228
|
/**
|
|
190
|
-
*
|
|
191
|
-
* class.
|
|
192
|
-
*
|
|
193
|
-
* Useful when network messages refer to components by type id and the
|
|
194
|
-
* corresponding class may be registered later. Call this before
|
|
195
|
-
* {@link registerComponent} to ensure the class picks up the server-assigned
|
|
196
|
-
* id rather than a locally generated one.
|
|
229
|
+
* Destroy every entity currently tracked by the world.
|
|
197
230
|
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
231
|
+
* Triggers all `onRemove` hooks and `exit` callbacks. Useful when
|
|
232
|
+
* transitioning between game sessions or resetting to a clean state.
|
|
200
233
|
*/
|
|
201
|
-
|
|
202
|
-
/** @internal Called by the {@link Query} constructor to register itself. */
|
|
203
|
-
_addQuery(q: Query): void;
|
|
204
|
-
/** @internal Called by {@link Query.destroy} to unregister a query and remove it from all entities. */
|
|
205
|
-
_removeQuery(q: Query): void;
|
|
234
|
+
clearAllEntities(): void;
|
|
206
235
|
/**
|
|
207
|
-
* Create a new {@link System},
|
|
236
|
+
* Create, register, and return a new {@link System}, ready for fluent
|
|
237
|
+
* configuration.
|
|
208
238
|
*
|
|
209
239
|
* ```ts
|
|
210
240
|
* world.system("Render")
|
|
211
241
|
* .phase("update")
|
|
212
242
|
* .requires(Position, Sprite)
|
|
213
243
|
* .enter([Sprite], (e, [sprite]) => sprite.initialize(scene))
|
|
214
|
-
* .
|
|
244
|
+
* .each([Position, Sprite], (e, [pos, sprite]) => sprite.draw(pos.x, pos.y));
|
|
215
245
|
* ```
|
|
216
246
|
*
|
|
217
|
-
* @param name -
|
|
218
|
-
* @returns The new
|
|
247
|
+
* @param name - Unique display name for the system.
|
|
248
|
+
* @returns The new system.
|
|
219
249
|
*/
|
|
220
|
-
system(name: string): System
|
|
250
|
+
system(name: string): System;
|
|
221
251
|
/**
|
|
222
|
-
* Create a standalone {@link Query},
|
|
252
|
+
* Create, register, and return a standalone {@link Query}, ready for fluent
|
|
223
253
|
* configuration.
|
|
224
254
|
*
|
|
225
255
|
* Unlike a {@link System}, a standalone query has no phase and no per-tick
|
|
226
|
-
* callbacks — it is a reactive
|
|
227
|
-
*
|
|
228
|
-
*
|
|
256
|
+
* callbacks — it is a reactive entity set that can be read at any time. It
|
|
257
|
+
* can also be created **after** {@link start}; existing matched entities
|
|
258
|
+
* are backfilled immediately.
|
|
229
259
|
*
|
|
230
260
|
* ```ts
|
|
231
261
|
* const enemies = world.query("Enemies")
|
|
@@ -236,135 +266,117 @@ export declare class World {
|
|
|
236
266
|
* // enemies.entities is kept up-to-date automatically
|
|
237
267
|
* ```
|
|
238
268
|
*
|
|
239
|
-
* @param name -
|
|
240
|
-
* @returns The new
|
|
269
|
+
* @param name - Unique display name for the query.
|
|
270
|
+
* @returns The new query.
|
|
241
271
|
*/
|
|
242
|
-
query(name: string): Query
|
|
272
|
+
query(name: string): Query;
|
|
243
273
|
/**
|
|
244
274
|
* Create a non-reactive {@link Filter} that matches entities satisfying `q`.
|
|
245
275
|
*
|
|
246
276
|
* Unlike {@link query}, the returned filter holds no tracked entity set and
|
|
247
|
-
* registers nothing
|
|
248
|
-
* all current world entities and invokes the callback
|
|
277
|
+
* registers nothing on the world. Each call to {@link Filter.forEach} walks
|
|
278
|
+
* all current world entities and invokes the callback on the matches.
|
|
249
279
|
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
* and `AND` of those forms). For
|
|
253
|
-
* (`OR`, `NOT`, `PARENT`, custom `EntityTestFunc`)
|
|
280
|
+
* The component classes guaranteed present on every matched entity are
|
|
281
|
+
* inferred from the DSL where possible (plain arrays, `HAS`, `HAS_ONLY`,
|
|
282
|
+
* and `AND` of those forms). For shapes the inferer cannot see through
|
|
283
|
+
* (`OR`, `NOT`, `PARENT`, custom `EntityTestFunc`) supply a `_guaranteed`
|
|
254
284
|
* tuple as a type-level override:
|
|
255
285
|
*
|
|
256
286
|
* ```ts
|
|
257
|
-
* // Auto-deduced
|
|
287
|
+
* // Auto-deduced: pos and vel are non-nullable.
|
|
258
288
|
* world.filter([Position, Velocity])
|
|
259
289
|
* .forEach([Position, Velocity], (e, [pos, vel]) => { ... });
|
|
260
290
|
*
|
|
261
|
-
* // Manual override for an opaque query
|
|
291
|
+
* // Manual override for an opaque query.
|
|
262
292
|
* world.filter(myTestFunc, [Position])
|
|
263
293
|
* .forEach([Position], (e, [pos]) => pos.x);
|
|
264
294
|
* ```
|
|
265
295
|
*
|
|
266
|
-
* @param q -
|
|
296
|
+
* @param q - Query expression.
|
|
267
297
|
* @param _guaranteed - Optional type hint declaring which components are
|
|
268
298
|
* guaranteed present (not validated at runtime).
|
|
269
299
|
*/
|
|
270
300
|
filter<Q extends QueryDSL>(q: Q): Filter<ExtractRequired<Q>>;
|
|
271
301
|
filter<T extends (typeof Component)[]>(q: QueryDSL, _guaranteed: readonly [...T]): Filter<T>;
|
|
302
|
+
/**
|
|
303
|
+
* Add a named phase to the update pipeline.
|
|
304
|
+
*
|
|
305
|
+
* Phases are executed in insertion order when {@link runPhase} or
|
|
306
|
+
* {@link progress} is called. Systems join a phase via {@link System.phase}.
|
|
307
|
+
*
|
|
308
|
+
* ```ts
|
|
309
|
+
* const preUpdate = world.addPhase("preupdate");
|
|
310
|
+
* const update = world.addPhase("update");
|
|
311
|
+
* const send = world.addPhase("send");
|
|
312
|
+
* ```
|
|
313
|
+
*
|
|
314
|
+
* @param name - Unique phase name. Systems can reference it by this string.
|
|
315
|
+
* @returns The new phase.
|
|
316
|
+
*/
|
|
317
|
+
addPhase(name: string): IPhase;
|
|
272
318
|
/**
|
|
273
319
|
* Prevent any further calls to {@link registerComponent}.
|
|
274
320
|
*
|
|
275
|
-
* Called automatically by {@link start}.
|
|
276
|
-
*
|
|
321
|
+
* Called automatically by {@link start}. Call directly if you want to lock
|
|
322
|
+
* registration before the rest of the systems are wired up.
|
|
277
323
|
*/
|
|
278
324
|
disableComponentRegistration(): void;
|
|
279
325
|
/**
|
|
280
326
|
* Freeze component registration and prepare the world for running.
|
|
281
327
|
*
|
|
282
|
-
* Distributes
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
328
|
+
* Distributes every system registered so far into its phase (defaulting to
|
|
329
|
+
* `"update"`) and logs the phase → system order to the console. Systems
|
|
330
|
+
* and queries can still be created after this call — standalone queries
|
|
331
|
+
* backfill existing matched entities immediately.
|
|
286
332
|
*
|
|
287
|
-
* Call
|
|
333
|
+
* Call once before the first {@link runPhase} / {@link progress}.
|
|
288
334
|
*/
|
|
289
335
|
start(): void;
|
|
290
|
-
private reindexSystems;
|
|
291
336
|
/**
|
|
292
|
-
*
|
|
337
|
+
* Open a new frame and evaluate every registered tick source once.
|
|
293
338
|
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
* component's {@link ComponentMeta} and the same object is returned on every
|
|
297
|
-
* call.
|
|
298
|
-
*
|
|
299
|
-
* ```ts
|
|
300
|
-
* world.hook(Sprite)
|
|
301
|
-
* .onAdd(c => c.initialize(scene))
|
|
302
|
-
* .onRemove(c => c.destroy());
|
|
303
|
-
* ```
|
|
339
|
+
* Call this before one or more {@link runPhase} calls when manually driving
|
|
340
|
+
* phases. {@link progress} wraps this automatically for the full pipeline.
|
|
304
341
|
*
|
|
305
|
-
* @param
|
|
306
|
-
* @
|
|
342
|
+
* @param delta - Milliseconds elapsed since the previous frame.
|
|
343
|
+
* @throws When a frame is already open.
|
|
307
344
|
*/
|
|
308
|
-
|
|
345
|
+
beginFrame(delta: number): void;
|
|
309
346
|
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* Phases are executed in insertion order when you call {@link runPhase} for
|
|
313
|
-
* each one. Systems are assigned to a phase via {@link System.phase}.
|
|
314
|
-
*
|
|
315
|
-
* ```ts
|
|
316
|
-
* const preUpdate = world.addPhase("preupdate");
|
|
317
|
-
* const update = world.addPhase("update");
|
|
318
|
-
* const send = world.addPhase("send");
|
|
319
|
-
* ```
|
|
347
|
+
* Close the current frame.
|
|
320
348
|
*
|
|
321
|
-
* @
|
|
322
|
-
* @returns The new {@link IPhase}.
|
|
349
|
+
* @throws When no frame is currently open.
|
|
323
350
|
*/
|
|
324
|
-
|
|
351
|
+
endFrame(): void;
|
|
325
352
|
/**
|
|
326
|
-
* Execute
|
|
353
|
+
* Execute every system in `phase` within the current frame.
|
|
327
354
|
*
|
|
328
|
-
* Pending top-level mutations are drained
|
|
329
|
-
*
|
|
330
|
-
* deferred scope; mutations made by callbacks
|
|
331
|
-
*
|
|
332
|
-
* next system runs.
|
|
355
|
+
* Pending top-level mutations are drained before the first system runs so
|
|
356
|
+
* each system observes a consistent world. Each system body executes in a
|
|
357
|
+
* deferred scope; mutations made by callbacks land in the world queue and
|
|
358
|
+
* are processed before the next system runs.
|
|
333
359
|
*
|
|
334
|
-
*
|
|
360
|
+
* `runPhase` is safe to call re-entrantly from a system body: it reuses the
|
|
361
|
+
* frame opened by {@link beginFrame} and does not advance `_frameCounter` or
|
|
362
|
+
* re-evaluate tick sources.
|
|
363
|
+
*
|
|
364
|
+
* @param phase - Phase reference returned from {@link addPhase}.
|
|
335
365
|
* @param now - Absolute timestamp in milliseconds (e.g. `Date.now()`).
|
|
336
366
|
* @param delta - Milliseconds elapsed since the previous tick.
|
|
367
|
+
* @throws When called outside an open frame.
|
|
337
368
|
*/
|
|
338
369
|
runPhase(phase: IPhase, now: number, delta: number): void;
|
|
339
370
|
/**
|
|
340
|
-
* Run every phase in the pipeline in
|
|
341
|
-
*
|
|
342
|
-
* {@link runPhase} for each
|
|
371
|
+
* Run every phase in the pipeline in registration order.
|
|
372
|
+
*
|
|
373
|
+
* Equivalent to `beginFrame(delta)`, calling {@link runPhase} for each
|
|
374
|
+
* phase, then {@link endFrame}. All registered tick sources are evaluated
|
|
375
|
+
* once up front for the whole frame, and the frame is closed in a `finally`
|
|
376
|
+
* block if a system throws.
|
|
343
377
|
*
|
|
344
378
|
* @param now - Absolute timestamp in milliseconds (e.g. `Date.now()`).
|
|
345
379
|
* @param delta - Milliseconds elapsed since the previous tick.
|
|
346
380
|
*/
|
|
347
381
|
progress(now: number, delta: number): void;
|
|
348
|
-
/**
|
|
349
|
-
* Declare a group of mutually exclusive components.
|
|
350
|
-
*
|
|
351
|
-
* After this call, adding any component in the group to an entity that
|
|
352
|
-
* already has another component from the same group will remove the other component
|
|
353
|
-
*
|
|
354
|
-
* ```ts
|
|
355
|
-
* world.setExclusiveComponents(Walking, Running, Idle);
|
|
356
|
-
* // entity.add(Running) throws if entity already has Walking or Idle
|
|
357
|
-
* ```
|
|
358
|
-
*
|
|
359
|
-
* @param components - Two or more component classes that cannot coexist.
|
|
360
|
-
* @throws If any class has not been registered.
|
|
361
|
-
*/
|
|
362
|
-
setExclusiveComponents(...components: (typeof Component)[]): void;
|
|
363
|
-
/**
|
|
364
|
-
* Destroy every entity currently tracked by the world.
|
|
365
|
-
*
|
|
366
|
-
* Triggers all `onRemove` hooks and `exit` callbacks. Useful when
|
|
367
|
-
* transitioning between game sessions or resetting to a clean state.
|
|
368
|
-
*/
|
|
369
|
-
clearAllEntities(): void;
|
|
370
382
|
}
|