@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.
- package/README.md +218 -229
- 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 +1 -1
- package/dist/package.json +3 -1
- package/dist/phase.d.ts +5 -28
- 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 +59 -87
- package/dist/system.js +114 -114
- package/dist/system.js.map +1 -1
- 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 +212 -224
- package/dist/world.js +368 -330
- 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/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 {
|
|
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
|
|
10
|
+
* A reactive processor running over a filtered subset of world entities.
|
|
11
11
|
*
|
|
12
|
-
* Systems are created and
|
|
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
|
-
*
|
|
24
|
-
*
|
|
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`
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
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
|
|
40
|
-
* {@link query}) are tracked as
|
|
41
|
-
* `
|
|
42
|
-
*
|
|
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
|
-
*
|
|
55
|
-
* {@link
|
|
56
|
-
*
|
|
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
|
|
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
|
|
78
|
-
*
|
|
62
|
+
* Register a per-tick callback fired every time this system's phase runs,
|
|
63
|
+
* regardless of entity membership.
|
|
79
64
|
*
|
|
80
|
-
* Use
|
|
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
|
|
85
|
-
* @returns
|
|
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
|
|
90
|
-
*
|
|
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
|
|
95
|
-
*
|
|
96
|
-
*
|
|
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
|
|
104
|
-
*
|
|
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
|
|
109
|
-
* @returns
|
|
110
|
-
* @throws
|
|
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
|
-
*
|
|
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-
|
|
137
|
-
* `update`
|
|
112
|
+
* previous `requires` call. After calling `query`, watchlist auto-expansion
|
|
113
|
+
* via `update` is disabled.
|
|
138
114
|
*
|
|
139
|
-
* The optional `
|
|
140
|
-
*
|
|
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 -
|
|
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
|
|
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])` —
|
|
161
|
-
*
|
|
125
|
+
* Shorthand for `query([...components])` — tracks entities that have **all**
|
|
126
|
+
* of the listed component types.
|
|
162
127
|
*
|
|
163
|
-
* Equivalent to `query({ HAS: components })`.
|
|
164
|
-
*
|
|
165
|
-
* {@link
|
|
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 -
|
|
169
|
-
* @returns
|
|
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
|
|
4
|
+
* A reactive processor running over a filtered subset of world entities.
|
|
5
5
|
*
|
|
6
|
-
* Systems are created and
|
|
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
|
-
*
|
|
18
|
-
*
|
|
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`
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
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
|
|
34
|
-
* {@link query}) are tracked as
|
|
35
|
-
* `
|
|
36
|
-
*
|
|
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
|
-
|
|
43
|
+
/** @internal Single inbox replayed in arrival order on every `_run`. */
|
|
44
|
+
this._inbox = [];
|
|
42
45
|
}
|
|
43
46
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
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.
|
|
56
|
+
this._inbox.push({ kind: 0 /* InboxCommand.Enter */, entity: e });
|
|
72
57
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
/**
|
|
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.
|
|
84
|
+
this._inbox.push({ kind: 1 /* InboxCommand.Exit */, entity: e, snapshot });
|
|
100
85
|
}
|
|
101
86
|
}
|
|
102
|
-
/**
|
|
103
|
-
|
|
104
|
-
|
|
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.
|
|
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
|
-
* `
|
|
112
|
-
*
|
|
113
|
-
*
|
|
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.
|
|
118
|
-
const event = this.
|
|
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.
|
|
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.
|
|
123
|
+
this._inbox.length = 0;
|
|
135
124
|
if (this._runCallback) {
|
|
136
125
|
this._runCallback(now, delta);
|
|
137
126
|
}
|
|
138
|
-
if (this.
|
|
139
|
-
const cb = this.
|
|
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
|
-
*
|
|
146
|
-
*
|
|
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
|
-
*
|
|
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
|
|
153
|
-
* @returns
|
|
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
|
|
161
|
-
*
|
|
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
|
|
166
|
-
*
|
|
167
|
-
*
|
|
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
|
|
175
|
-
*
|
|
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
|
|
180
|
-
* @returns
|
|
181
|
-
* @throws
|
|
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.
|
|
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.
|
|
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
|
-
*
|
|
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-
|
|
219
|
-
* `update`
|
|
220
|
+
* previous `requires` call. After calling `query`, watchlist auto-expansion
|
|
221
|
+
* via `update` is disabled.
|
|
220
222
|
*
|
|
221
|
-
* The optional `
|
|
222
|
-
*
|
|
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 -
|
|
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
|
|
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])` —
|
|
246
|
-
*
|
|
236
|
+
* Shorthand for `query([...components])` — tracks entities that have **all**
|
|
237
|
+
* of the listed component types.
|
|
247
238
|
*
|
|
248
|
-
* Equivalent to `query({ HAS: components })`.
|
|
249
|
-
*
|
|
250
|
-
* {@link
|
|
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 -
|
|
254
|
-
* @returns
|
|
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
|
package/dist/system.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","sourceRoot":"","sources":["../src/system.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,KAAK,EAAe,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../src/system.ts"],"names":[],"mappings":"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"}
|