@vworlds/vecs 1.0.10 → 1.0.11

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.
Files changed (43) hide show
  1. package/README.md +218 -229
  2. package/dist/command.d.ts +1 -46
  3. package/dist/component.d.ts +51 -59
  4. package/dist/component.js +31 -25
  5. package/dist/component.js.map +1 -1
  6. package/dist/dsl.d.ts +34 -26
  7. package/dist/dsl.js +46 -20
  8. package/dist/dsl.js.map +1 -1
  9. package/dist/entity.d.ts +96 -106
  10. package/dist/entity.js +261 -190
  11. package/dist/entity.js.map +1 -1
  12. package/dist/filter.d.ts +31 -23
  13. package/dist/filter.js +24 -17
  14. package/dist/filter.js.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/package.json +3 -1
  17. package/dist/phase.d.ts +5 -28
  18. package/dist/phase.js +11 -10
  19. package/dist/phase.js.map +1 -1
  20. package/dist/query.d.ts +107 -144
  21. package/dist/query.js +200 -169
  22. package/dist/query.js.map +1 -1
  23. package/dist/system.d.ts +59 -87
  24. package/dist/system.js +114 -114
  25. package/dist/system.js.map +1 -1
  26. package/dist/util/array_map.d.ts +4 -55
  27. package/dist/util/array_map.js +35 -37
  28. package/dist/util/array_map.js.map +1 -1
  29. package/dist/util/bitset.d.ts +40 -50
  30. package/dist/util/bitset.js +76 -62
  31. package/dist/util/bitset.js.map +1 -1
  32. package/dist/util/events.d.ts +14 -18
  33. package/dist/util/events.js +24 -3
  34. package/dist/util/events.js.map +1 -1
  35. package/dist/util/ordered_set.d.ts +1 -17
  36. package/dist/util/ordered_set.js +74 -25
  37. package/dist/util/ordered_set.js.map +1 -1
  38. package/dist/world.d.ts +212 -224
  39. package/dist/world.js +368 -330
  40. package/dist/world.js.map +1 -1
  41. package/eslint-rules/internal-underscore.js +60 -0
  42. package/eslint.config.js +5 -0
  43. package/package.json +3 -1
package/dist/system.d.ts CHANGED
@@ -2,14 +2,14 @@ import { Component } from "./component.js";
2
2
  import { Query } from "./query.js";
3
3
  import { type QueryDSL, type MaybeRequired } from "./dsl.js";
4
4
  import type { Entity } from "./entity.js";
5
- import { Phase, type IPhase } from "./phase.js";
5
+ import { type IPhase } from "./phase.js";
6
6
  import { type World } from "./world.js";
7
7
  export type { QueryDSL as SystemQuery, EntityTestFunc } from "./dsl.js";
8
8
  type RunCallback = (now: number, delta: number) => void;
9
9
  /**
10
- * A reactive processor that operates on a filtered subset of world entities.
10
+ * A reactive processor running over a filtered subset of world entities.
11
11
  *
12
- * Systems are created and registered through {@link World.system}:
12
+ * Systems are created and configured through {@link World.system}:
13
13
  *
14
14
  * ```ts
15
15
  * world.system("Move")
@@ -20,9 +20,9 @@ type RunCallback = (now: number, delta: number) => void;
20
20
  * .exit((e) => { console.log("entity left", e.eid); });
21
21
  * ```
22
22
  *
23
- * All builder methods return `this` for chaining. Call {@link World.start}
24
- * once all systems are registered; after that, drive the loop with
25
- * {@link World.runPhase}.
23
+ * Every builder method returns `this` for chaining. After registering systems
24
+ * call {@link World.start} once, then drive the loop with
25
+ * {@link World.runPhase} or {@link World.progress}.
26
26
  *
27
27
  * Internally each system holds a single ordered **inbox** of routed events
28
28
  * (`enter`, `exit`, `update`). The world appends to it during command-queue
@@ -31,83 +31,66 @@ type RunCallback = (now: number, delta: number) => void;
31
31
  *
32
32
  * ### Component injection and type inference
33
33
  *
34
- * `enter`, `exit`, `update`, `each`, and `sort` all accept an array of
35
- * component classes that are resolved from the entity and passed as a typed
36
- * tuple to the callback. Use `{ parent: SomeComponent }` to resolve from the
37
- * entity's parent instead of the entity itself.
34
+ * `enter`, `exit`, `update`, `each`, and `sort` accept an array of component
35
+ * classes resolved from the entity and passed as a typed tuple to the
36
+ * callback. Use `{ parent: SomeComponent }` to resolve from the entity's
37
+ * parent instead of the entity itself.
38
38
  *
39
- * Components declared via {@link requires} (or the second argument of
40
- * {@link query}) are tracked as a type parameter `R` on the system. In
41
- * `sort`, `each`, and `update` inject callbacks, those components appear as
42
- * non-nullable; any component not in `R` remains `Type | undefined`.
39
+ * Components declared via {@link requires} (or the `_guaranteed` argument of
40
+ * {@link query}) are tracked as the type parameter `R`. Inside `sort`,
41
+ * `each`, and `update` injection callbacks they are non-nullable; any other
42
+ * component remains `Type | undefined`.
43
+ *
44
+ * @typeParam R - Component classes guaranteed present on every matched entity.
43
45
  */
44
46
  export declare class System<R extends (typeof Component)[] = []> extends Query<R> {
45
- protected eachCallback: ((e: Entity) => void) | undefined;
46
- private _runCallback;
47
- private readonly inbox;
48
- /** @internal */
49
- _phase: string | Phase | undefined;
50
47
  constructor(name: string, world: World);
51
48
  /**
52
49
  * Assign this system to a pipeline phase.
53
50
  *
54
- * The phase can be specified by name (the world will resolve it at
55
- * {@link World.start | start} time) or by an {@link IPhase} reference
56
- * returned from {@link World.addPhase}. Systems without an explicit phase
57
- * are placed in the built-in `"update"` phase.
51
+ * Pass either a phase name (resolved at {@link World.start}) or an
52
+ * {@link IPhase} reference returned from {@link World.addPhase}. Systems
53
+ * with no explicit phase fall into the built-in `"update"` phase.
58
54
  *
59
55
  * @param p - Phase name or `IPhase` reference.
60
- * @returns `this` for chaining.
56
+ * @returns This system, for chaining.
57
+ * @throws When the phase reference is not a `Phase`, or belongs to a
58
+ * different world.
61
59
  */
62
60
  phase(p: string | IPhase): this;
63
- /** @internal Routing entry: register membership and enqueue an enter event. */
64
- _enter(e: Entity): void;
65
- /** @internal Routing entry: deregister membership and enqueue an exit event. */
66
- _exit(e: Entity): void;
67
- /** @internal Routing entry: enqueue an update event if the watchlist matches. */
68
- notifyModified(c: Component): void;
69
- /**
70
- * @internal Execute one tick: drain the inbox in arrival order, then run
71
- * `runCallback` and `eachCallback`. The whole body runs in a deferred
72
- * scope; any mutations made by callbacks land in the world queue and are
73
- * processed by the world after `_run` returns.
74
- */
75
- _run(now: number, delta: number): void;
76
61
  /**
77
- * Register a per-tick callback that runs every time this system's phase
78
- * executes, regardless of entity membership.
62
+ * Register a per-tick callback fired every time this system's phase runs,
63
+ * regardless of entity membership.
79
64
  *
80
- * Use this for logic that is not driven by component updates — polling,
65
+ * Use it for logic that is not driven by component changes — polling,
81
66
  * network flushing, global timers, etc.
82
67
  *
83
68
  * @param callback - Receives `now` (absolute timestamp in ms) and `delta`
84
- * (ms since the last tick).
85
- * @returns `this` for chaining.
69
+ * (ms since the previous tick).
70
+ * @returns This system, for chaining.
86
71
  */
87
72
  run(callback: RunCallback): this;
88
73
  /**
89
- * Register a callback that fires **every tick** for every entity currently
90
- * tracked by this system, with the listed components resolved from each
91
- * entity.
74
+ * Register a callback fired **every tick** for **every tracked entity**,
75
+ * unconditionally, with the listed components resolved from each entity.
92
76
  *
93
77
  * Unlike {@link update} (which only fires when `component.modified()` is
94
- * called), `each` fires unconditionally on every tick the system runs,
95
- * once per tracked entity. Components declared via {@link requires} are
96
- * guaranteed non-null in the resolved tuple; any other component class
97
- * may be `undefined` if the entity lacks it.
78
+ * called), `each` fires every tick the system runs, once per tracked entity.
79
+ * Components declared via {@link requires} are non-nullable in the resolved
80
+ * tuple; any other component class may be `undefined` if the entity lacks it.
98
81
  *
99
82
  * `each` does **not** modify the system's query — define membership with
100
83
  * {@link requires} or {@link query} as usual. It does, however, implicitly
101
84
  * enable {@link track}, so matched entities are exposed via {@link entities}.
102
85
  *
103
- * Only a single `each` callback may be registered per system; calling
104
- * `each` a second time throws.
86
+ * Only one `each` callback may be registered per system; calling `each` a
87
+ * second time throws.
105
88
  *
106
89
  * @param components - Component classes to resolve from each entity.
107
90
  * @param callback - Receives the entity and a tuple of resolved component
108
- * instances (`undefined` for components not covered by {@link requires}).
109
- * @returns `this` for chaining.
110
- * @throws If `each` has already been registered on this system.
91
+ * instances (`undefined` for any not covered by {@link requires}).
92
+ * @returns This system, for chaining.
93
+ * @throws When `each` has already been registered on this system.
111
94
  *
112
95
  * @example
113
96
  * ```ts
@@ -123,50 +106,39 @@ export declare class System<R extends (typeof Component)[] = []> extends Query<R
123
106
  [K in keyof J]: MaybeRequired<J[K], R>;
124
107
  }) => void): this;
125
108
  /**
126
- * Not supported on `System`. Throws unconditionally.
127
- *
128
- * Systems are owned by the world for the duration of the session. If you
129
- * need a temporary reactive set, use a standalone {@link Query} instead.
130
- */
131
- destroy(): never;
132
- /**
133
- * Set the entity membership predicate using the {@link QueryDSL} DSL.
109
+ * Set the entity-membership predicate using a {@link QueryDSL} expression.
134
110
  *
135
111
  * Replaces any implicit query derived from `update` watchlists and any
136
- * previous `requires` call. After calling `query`, auto-expanding of
137
- * `update` watchlists is disabled.
112
+ * previous `requires` call. After calling `query`, watchlist auto-expansion
113
+ * via `update` is disabled.
138
114
  *
139
- * The optional `guaranteed` tuple is a pure type-level hint: it tells
140
- * `sort`, `each`, and `update` callbacks which components are guaranteed
141
- * to be present on every matched entity, eliminating `| undefined` from
142
- * those positions. It has no effect at runtime.
115
+ * The optional `_guaranteed` tuple is a pure type-level hint see
116
+ * {@link Query.query} for details.
143
117
  *
144
- * @param q - A {@link QueryDSL} expression.
118
+ * @param q - Query expression.
145
119
  * @param _guaranteed - Component classes guaranteed present on every matched
146
120
  * entity (type hint only — not validated at runtime).
147
- * @returns `this` for chaining.
148
- *
149
- * @example
150
- * ```ts
151
- * world.system("Move")
152
- * .query({ AND: [{ HAS: Position }, { HAS: Velocity }] }, [Position, Velocity])
153
- * .each([Position, Velocity], (e, [pos, vel]) => {
154
- * pos.x += vel.vx; // no ! needed
155
- * });
156
- * ```
121
+ * @returns This system, retyped with the guaranteed tuple as its `R`.
157
122
  */
158
123
  query<T extends (typeof Component)[] = []>(q: QueryDSL, _guaranteed?: readonly [...T]): System<T>;
159
124
  /**
160
- * Shorthand for `query([...components])` — the system tracks entities that
161
- * have **all** of the listed component types.
125
+ * Shorthand for `query([...components])` — tracks entities that have **all**
126
+ * of the listed component types.
162
127
  *
163
- * Equivalent to `query({ HAS: components })`. Unlike `query`, passing
164
- * component classes here also informs the types of {@link sort} and
165
- * {@link each} callbacks: listed components will be non-nullable in those
166
- * tuples.
128
+ * Equivalent to `query({ HAS: components })`. The listed components are also
129
+ * recorded in the type parameter `R`, so {@link sort}, {@link each}, and
130
+ * {@link update} callbacks treat them as non-nullable.
167
131
  *
168
- * @param components - One or more component classes.
169
- * @returns `this` for chaining.
132
+ * @param components - Component classes to require.
133
+ * @returns This system, retyped with the required tuple as its `R`.
170
134
  */
171
135
  requires<T extends (typeof Component)[]>(...components: [...T]): System<T>;
136
+ /**
137
+ * Not supported on `System`. Throws unconditionally.
138
+ *
139
+ * Systems are owned by the world for the duration of the session; if you
140
+ * need a temporary reactive set use a standalone {@link Query} via
141
+ * {@link World.query}.
142
+ */
143
+ destroy(): never;
172
144
  }
package/dist/system.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { Query } from "./query.js";
2
2
  import { Phase } from "./phase.js";
3
3
  /**
4
- * A reactive processor that operates on a filtered subset of world entities.
4
+ * A reactive processor running over a filtered subset of world entities.
5
5
  *
6
- * Systems are created and registered through {@link World.system}:
6
+ * Systems are created and configured through {@link World.system}:
7
7
  *
8
8
  * ```ts
9
9
  * world.system("Move")
@@ -14,9 +14,9 @@ import { Phase } from "./phase.js";
14
14
  * .exit((e) => { console.log("entity left", e.eid); });
15
15
  * ```
16
16
  *
17
- * All builder methods return `this` for chaining. Call {@link World.start}
18
- * once all systems are registered; after that, drive the loop with
19
- * {@link World.runPhase}.
17
+ * Every builder method returns `this` for chaining. After registering systems
18
+ * call {@link World.start} once, then drive the loop with
19
+ * {@link World.runPhase} or {@link World.progress}.
20
20
  *
21
21
  * Internally each system holds a single ordered **inbox** of routed events
22
22
  * (`enter`, `exit`, `update`). The world appends to it during command-queue
@@ -25,67 +25,52 @@ import { Phase } from "./phase.js";
25
25
  *
26
26
  * ### Component injection and type inference
27
27
  *
28
- * `enter`, `exit`, `update`, `each`, and `sort` all accept an array of
29
- * component classes that are resolved from the entity and passed as a typed
30
- * tuple to the callback. Use `{ parent: SomeComponent }` to resolve from the
31
- * entity's parent instead of the entity itself.
28
+ * `enter`, `exit`, `update`, `each`, and `sort` accept an array of component
29
+ * classes resolved from the entity and passed as a typed tuple to the
30
+ * callback. Use `{ parent: SomeComponent }` to resolve from the entity's
31
+ * parent instead of the entity itself.
32
32
  *
33
- * Components declared via {@link requires} (or the second argument of
34
- * {@link query}) are tracked as a type parameter `R` on the system. In
35
- * `sort`, `each`, and `update` inject callbacks, those components appear as
36
- * non-nullable; any component not in `R` remains `Type | undefined`.
33
+ * Components declared via {@link requires} (or the `_guaranteed` argument of
34
+ * {@link query}) are tracked as the type parameter `R`. Inside `sort`,
35
+ * `each`, and `update` injection callbacks they are non-nullable; any other
36
+ * component remains `Type | undefined`.
37
+ *
38
+ * @typeParam R - Component classes guaranteed present on every matched entity.
37
39
  */
38
40
  export class System extends Query {
39
41
  constructor(name, world) {
40
42
  super(name, world, false);
41
- this.inbox = [];
43
+ /** @internal Single inbox replayed in arrival order on every `_run`. */
44
+ this._inbox = [];
42
45
  }
43
46
  /**
44
- * Assign this system to a pipeline phase.
45
- *
46
- * The phase can be specified by name (the world will resolve it at
47
- * {@link World.start | start} time) or by an {@link IPhase} reference
48
- * returned from {@link World.addPhase}. Systems without an explicit phase
49
- * are placed in the built-in `"update"` phase.
50
- *
51
- * @param p - Phase name or `IPhase` reference.
52
- * @returns `this` for chaining.
47
+ * @internal Routing entry: register query membership for `e`, push an
48
+ * inbox `enter` event when an `enter` callback is registered, and bridge
49
+ * watched components through {@link _notifyModified} to surface them as
50
+ * inbox `update` events on entry.
53
51
  */
54
- phase(p) {
55
- if (typeof p !== "string") {
56
- if (!(p instanceof Phase)) {
57
- throw "Invalid Phase object";
58
- }
59
- if (p.world !== this.world) {
60
- throw "Phase does not belong to this system's world";
61
- }
62
- }
63
- this._phase = p;
64
- return this;
65
- }
66
- /** @internal Routing entry: register membership and enqueue an enter event. */
67
52
  _enter(e) {
68
53
  this._entities?.add(e);
69
54
  e._addQueryMembership(this);
70
55
  if (this._enterCallback !== undefined) {
71
- this.inbox.push({ kind: 0 /* InboxCommand.Enter */, entity: e });
56
+ this._inbox.push({ kind: 0 /* InboxCommand.Enter */, entity: e });
72
57
  }
73
- // Bridge: surface watched components on entry through `notifyModified`,
74
- // which on System pushes inbox `update` events.
75
- e.forEachComponent((c) => {
76
- if (this.watchlistBitmask.hasBit(c.bitPtr)) {
77
- this.notifyModified(c);
58
+ e.components.forEach((c) => {
59
+ if (this._watchlistBitmask.hasBit(c.bitPtr)) {
60
+ this._notifyModified(c);
78
61
  }
79
62
  });
80
63
  }
81
- /** @internal Routing entry: deregister membership and enqueue an exit event. */
64
+ /**
65
+ * @internal Routing entry: deregister query membership for `e` and push an
66
+ * inbox `exit` event when an `exit` callback is registered, capturing a
67
+ * snapshot of the components the callback wants to inject so they remain
68
+ * resolvable after the underlying components are removed.
69
+ */
82
70
  _exit(e) {
83
71
  this._entities?.delete(e);
84
72
  e._removeQueryMembership(this);
85
73
  if (this._exitCallback !== undefined) {
86
- // Only snapshot the types the callback injects, and only direct (non-parent)
87
- // ones — resolved at registration time. Parent refs are read from e.parent
88
- // at callback time. Undefined when the callback takes no injection.
89
74
  let snapshot;
90
75
  if (this._exitSnapshotTypes && this._exitSnapshotTypes.length > 0) {
91
76
  snapshot = new Map();
@@ -96,26 +81,30 @@ export class System extends Query {
96
81
  }
97
82
  }
98
83
  }
99
- this.inbox.push({ kind: 1 /* InboxCommand.Exit */, entity: e, snapshot });
84
+ this._inbox.push({ kind: 1 /* InboxCommand.Exit */, entity: e, snapshot });
100
85
  }
101
86
  }
102
- /** @internal Routing entry: enqueue an update event if the watchlist matches. */
103
- notifyModified(c) {
104
- if (!this.watchlistBitmask.hasBit(c.bitPtr)) {
87
+ /**
88
+ * @internal Routing entry: push an inbox `update` event when the modified
89
+ * component matches the watchlist.
90
+ */
91
+ _notifyModified(c) {
92
+ if (!this._watchlistBitmask.hasBit(c.bitPtr)) {
105
93
  return;
106
94
  }
107
- this.inbox.push({ kind: 2 /* InboxCommand.Update */, component: c });
95
+ this._inbox.push({ kind: 2 /* InboxCommand.Update */, component: c });
108
96
  }
109
97
  /**
110
98
  * @internal Execute one tick: drain the inbox in arrival order, then run
111
- * `runCallback` and `eachCallback`. The whole body runs in a deferred
112
- * scope; any mutations made by callbacks land in the world queue and are
113
- * processed by the world after `_run` returns.
99
+ * the `run` callback, then the `each` callback for every tracked entity.
100
+ *
101
+ * The whole body executes inside a `World.defer` scope; mutations made by
102
+ * callbacks land in the world queue and are processed when `_run` returns.
114
103
  */
115
104
  _run(now, delta) {
116
105
  this.world.defer(() => {
117
- for (let i = 0; i < this.inbox.length; i++) {
118
- const event = this.inbox[i];
106
+ for (let i = 0; i < this._inbox.length; i++) {
107
+ const event = this._inbox[i];
119
108
  switch (event.kind) {
120
109
  case 0 /* InboxCommand.Enter */:
121
110
  this._enterCallback(event.entity);
@@ -124,61 +113,83 @@ export class System extends Query {
124
113
  this._exitCallback(event.entity, event.snapshot);
125
114
  break;
126
115
  case 2 /* InboxCommand.Update */:
127
- const callback = this.componentUpdateCallbacks.get(event.component.type);
116
+ const callback = this._componentUpdateCallbacks.get(event.component.type);
128
117
  if (callback) {
129
118
  callback(event.component);
130
119
  }
131
120
  break;
132
121
  }
133
122
  }
134
- this.inbox.length = 0;
123
+ this._inbox.length = 0;
135
124
  if (this._runCallback) {
136
125
  this._runCallback(now, delta);
137
126
  }
138
- if (this.eachCallback) {
139
- const cb = this.eachCallback;
127
+ if (this._eachCallback) {
128
+ const cb = this._eachCallback;
140
129
  this.forEach((e) => cb(e));
141
130
  }
142
131
  });
143
132
  }
144
133
  /**
145
- * Register a per-tick callback that runs every time this system's phase
146
- * executes, regardless of entity membership.
134
+ * Assign this system to a pipeline phase.
135
+ *
136
+ * Pass either a phase name (resolved at {@link World.start}) or an
137
+ * {@link IPhase} reference returned from {@link World.addPhase}. Systems
138
+ * with no explicit phase fall into the built-in `"update"` phase.
147
139
  *
148
- * Use this for logic that is not driven by component updates — polling,
140
+ * @param p - Phase name or `IPhase` reference.
141
+ * @returns This system, for chaining.
142
+ * @throws When the phase reference is not a `Phase`, or belongs to a
143
+ * different world.
144
+ */
145
+ phase(p) {
146
+ if (typeof p !== "string") {
147
+ if (!(p instanceof Phase)) {
148
+ throw "Invalid Phase object";
149
+ }
150
+ if (p.world !== this.world) {
151
+ throw "Phase does not belong to this system's world";
152
+ }
153
+ }
154
+ this._phase = p;
155
+ return this;
156
+ }
157
+ /**
158
+ * Register a per-tick callback fired every time this system's phase runs,
159
+ * regardless of entity membership.
160
+ *
161
+ * Use it for logic that is not driven by component changes — polling,
149
162
  * network flushing, global timers, etc.
150
163
  *
151
164
  * @param callback - Receives `now` (absolute timestamp in ms) and `delta`
152
- * (ms since the last tick).
153
- * @returns `this` for chaining.
165
+ * (ms since the previous tick).
166
+ * @returns This system, for chaining.
154
167
  */
155
168
  run(callback) {
156
169
  this._runCallback = callback;
157
170
  return this;
158
171
  }
159
172
  /**
160
- * Register a callback that fires **every tick** for every entity currently
161
- * tracked by this system, with the listed components resolved from each
162
- * entity.
173
+ * Register a callback fired **every tick** for **every tracked entity**,
174
+ * unconditionally, with the listed components resolved from each entity.
163
175
  *
164
176
  * Unlike {@link update} (which only fires when `component.modified()` is
165
- * called), `each` fires unconditionally on every tick the system runs,
166
- * once per tracked entity. Components declared via {@link requires} are
167
- * guaranteed non-null in the resolved tuple; any other component class
168
- * may be `undefined` if the entity lacks it.
177
+ * called), `each` fires every tick the system runs, once per tracked entity.
178
+ * Components declared via {@link requires} are non-nullable in the resolved
179
+ * tuple; any other component class may be `undefined` if the entity lacks it.
169
180
  *
170
181
  * `each` does **not** modify the system's query — define membership with
171
182
  * {@link requires} or {@link query} as usual. It does, however, implicitly
172
183
  * enable {@link track}, so matched entities are exposed via {@link entities}.
173
184
  *
174
- * Only a single `each` callback may be registered per system; calling
175
- * `each` a second time throws.
185
+ * Only one `each` callback may be registered per system; calling `each` a
186
+ * second time throws.
176
187
  *
177
188
  * @param components - Component classes to resolve from each entity.
178
189
  * @param callback - Receives the entity and a tuple of resolved component
179
- * instances (`undefined` for components not covered by {@link requires}).
180
- * @returns `this` for chaining.
181
- * @throws If `each` has already been registered on this system.
190
+ * instances (`undefined` for any not covered by {@link requires}).
191
+ * @returns This system, for chaining.
192
+ * @throws When `each` has already been registered on this system.
182
193
  *
183
194
  * @example
184
195
  * ```ts
@@ -191,71 +202,60 @@ export class System extends Query {
191
202
  * ```
192
203
  */
193
204
  each(components, callback) {
194
- if (this.eachCallback) {
205
+ if (this._eachCallback) {
195
206
  throw `each already registered for system '${this.name}'`;
196
207
  }
197
208
  this.track();
198
209
  const types = components.map((C) => this.world.getComponentType(C));
199
- this.eachCallback = (e) => {
210
+ this._eachCallback = (e) => {
200
211
  const resolved = types.map((t) => e.get(t));
201
212
  callback(e, resolved);
202
213
  };
203
214
  return this;
204
215
  }
205
216
  /**
206
- * Not supported on `System`. Throws unconditionally.
207
- *
208
- * Systems are owned by the world for the duration of the session. If you
209
- * need a temporary reactive set, use a standalone {@link Query} instead.
210
- */
211
- destroy() {
212
- throw `destroy() is not supported on System '${this.name}'`;
213
- }
214
- /**
215
- * Set the entity membership predicate using the {@link QueryDSL} DSL.
217
+ * Set the entity-membership predicate using a {@link QueryDSL} expression.
216
218
  *
217
219
  * Replaces any implicit query derived from `update` watchlists and any
218
- * previous `requires` call. After calling `query`, auto-expanding of
219
- * `update` watchlists is disabled.
220
+ * previous `requires` call. After calling `query`, watchlist auto-expansion
221
+ * via `update` is disabled.
220
222
  *
221
- * The optional `guaranteed` tuple is a pure type-level hint: it tells
222
- * `sort`, `each`, and `update` callbacks which components are guaranteed
223
- * to be present on every matched entity, eliminating `| undefined` from
224
- * those positions. It has no effect at runtime.
223
+ * The optional `_guaranteed` tuple is a pure type-level hint see
224
+ * {@link Query.query} for details.
225
225
  *
226
- * @param q - A {@link QueryDSL} expression.
226
+ * @param q - Query expression.
227
227
  * @param _guaranteed - Component classes guaranteed present on every matched
228
228
  * entity (type hint only — not validated at runtime).
229
- * @returns `this` for chaining.
230
- *
231
- * @example
232
- * ```ts
233
- * world.system("Move")
234
- * .query({ AND: [{ HAS: Position }, { HAS: Velocity }] }, [Position, Velocity])
235
- * .each([Position, Velocity], (e, [pos, vel]) => {
236
- * pos.x += vel.vx; // no ! needed
237
- * });
238
- * ```
229
+ * @returns This system, retyped with the guaranteed tuple as its `R`.
239
230
  */
240
231
  query(q, _guaranteed) {
241
232
  super.query(q, _guaranteed);
242
233
  return this;
243
234
  }
244
235
  /**
245
- * Shorthand for `query([...components])` — the system tracks entities that
246
- * have **all** of the listed component types.
236
+ * Shorthand for `query([...components])` — tracks entities that have **all**
237
+ * of the listed component types.
247
238
  *
248
- * Equivalent to `query({ HAS: components })`. Unlike `query`, passing
249
- * component classes here also informs the types of {@link sort} and
250
- * {@link each} callbacks: listed components will be non-nullable in those
251
- * tuples.
239
+ * Equivalent to `query({ HAS: components })`. The listed components are also
240
+ * recorded in the type parameter `R`, so {@link sort}, {@link each}, and
241
+ * {@link update} callbacks treat them as non-nullable.
252
242
  *
253
- * @param components - One or more component classes.
254
- * @returns `this` for chaining.
243
+ * @param components - Component classes to require.
244
+ * @returns This system, retyped with the required tuple as its `R`.
255
245
  */
256
246
  requires(...components) {
257
247
  super.requires(...components);
258
248
  return this;
259
249
  }
250
+ /**
251
+ * Not supported on `System`. Throws unconditionally.
252
+ *
253
+ * Systems are owned by the world for the duration of the session; if you
254
+ * need a temporary reactive set use a standalone {@link Query} via
255
+ * {@link World.query}.
256
+ */
257
+ destroy() {
258
+ throw `destroy() is not supported on System '${this.name}'`;
259
+ }
260
260
  }
261
261
  //# sourceMappingURL=system.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"system.js","sourceRoot":"","sources":["../src/system.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"system.js","sourceRoot":"","sources":["../src/system.ts"],"names":[],"mappings":"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"}