@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/system.d.ts
CHANGED
|
@@ -2,14 +2,15 @@ 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
|
+
import { type ITickSource } from "./timer.js";
|
|
7
8
|
export type { QueryDSL as SystemQuery, EntityTestFunc } from "./dsl.js";
|
|
8
9
|
type RunCallback = (now: number, delta: number) => void;
|
|
9
10
|
/**
|
|
10
|
-
* A reactive processor
|
|
11
|
+
* A reactive processor running over a filtered subset of world entities.
|
|
11
12
|
*
|
|
12
|
-
* Systems are created and
|
|
13
|
+
* Systems are created and configured through {@link World.system}:
|
|
13
14
|
*
|
|
14
15
|
* ```ts
|
|
15
16
|
* world.system("Move")
|
|
@@ -20,9 +21,9 @@ type RunCallback = (now: number, delta: number) => void;
|
|
|
20
21
|
* .exit((e) => { console.log("entity left", e.eid); });
|
|
21
22
|
* ```
|
|
22
23
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* {@link World.runPhase}.
|
|
24
|
+
* Every builder method returns `this` for chaining. After registering systems
|
|
25
|
+
* call {@link World.start} once, then drive the loop with
|
|
26
|
+
* {@link World.runPhase} or {@link World.progress}.
|
|
26
27
|
*
|
|
27
28
|
* Internally each system holds a single ordered **inbox** of routed events
|
|
28
29
|
* (`enter`, `exit`, `update`). The world appends to it during command-queue
|
|
@@ -31,83 +32,135 @@ type RunCallback = (now: number, delta: number) => void;
|
|
|
31
32
|
*
|
|
32
33
|
* ### Component injection and type inference
|
|
33
34
|
*
|
|
34
|
-
* `enter`, `exit`, `update`, `each`, and `sort`
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* `enter`, `exit`, `update`, `each`, and `sort` accept an array of component
|
|
36
|
+
* classes resolved from the entity and passed as a typed tuple to the
|
|
37
|
+
* callback. Use `{ parent: SomeComponent }` to resolve from the entity's
|
|
38
|
+
* parent instead of the entity itself.
|
|
38
39
|
*
|
|
39
|
-
* Components declared via {@link requires} (or the
|
|
40
|
-
* {@link query}) are tracked as
|
|
41
|
-
* `
|
|
42
|
-
*
|
|
40
|
+
* Components declared via {@link requires} (or the `_guaranteed` argument of
|
|
41
|
+
* {@link query}) are tracked as the type parameter `R`. Inside `sort`,
|
|
42
|
+
* `each`, and `update` injection callbacks they are non-nullable; any other
|
|
43
|
+
* component remains `Type | undefined`.
|
|
44
|
+
*
|
|
45
|
+
* @typeParam R - Component classes guaranteed present on every matched entity.
|
|
43
46
|
*/
|
|
44
|
-
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;
|
|
47
|
+
export declare class System<R extends (typeof Component)[] = []> extends Query<R> implements ITickSource {
|
|
50
48
|
constructor(name: string, world: World);
|
|
49
|
+
/** True when this system's cadence source fired during the current frame. */
|
|
50
|
+
get didTick(): boolean;
|
|
51
|
+
/** Milliseconds accumulated into this system's most recent fire. */
|
|
52
|
+
get lastFireDelta(): number;
|
|
53
|
+
/**
|
|
54
|
+
* Run this system at a fixed interval, expressed in seconds.
|
|
55
|
+
*
|
|
56
|
+
* This is seconds, unlike `World.beginFrame`, `World.progress`, and
|
|
57
|
+
* `runPhase`, which receive millisecond deltas. Calling `interval` replaces
|
|
58
|
+
* the current cadence source with an {@link IntervalTickSource}. When this
|
|
59
|
+
* system has a cadence source, the `delta` passed to {@link run} is the
|
|
60
|
+
* accumulated milliseconds since the previous fire, not the per-frame delta.
|
|
61
|
+
*
|
|
62
|
+
* @param seconds - Positive interval duration in seconds.
|
|
63
|
+
* @returns This system, for chaining.
|
|
64
|
+
* @throws When `seconds` is less than or equal to zero.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* world.system("AI")
|
|
69
|
+
* .interval(0.5)
|
|
70
|
+
* .run((now, delta) => tickAI(delta));
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
interval(seconds: number): this;
|
|
74
|
+
/**
|
|
75
|
+
* Run this system every `n` ticks from the world or an upstream source.
|
|
76
|
+
*
|
|
77
|
+
* Without a `source`, this composes with the current cadence source. For an
|
|
78
|
+
* unconfigured system, that means every `n` frames. With a `source`, it
|
|
79
|
+
* replaces the current cadence with a {@link RateTickSource} over that source.
|
|
80
|
+
* The `delta` passed to {@link run} is the accumulated milliseconds since
|
|
81
|
+
* this system last fired.
|
|
82
|
+
*
|
|
83
|
+
* @param n - Positive integer tick divisor.
|
|
84
|
+
* @param source - Optional upstream source to divide.
|
|
85
|
+
* @returns This system, for chaining.
|
|
86
|
+
* @throws When `n` is not a positive integer.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* world.system("SendSnapshots")
|
|
91
|
+
* .rate(2)
|
|
92
|
+
* .run(flushNetwork);
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
rate(n: number): this;
|
|
96
|
+
rate(n: number, source: ITickSource): this;
|
|
97
|
+
/**
|
|
98
|
+
* Run this system only when another timer or system ticks.
|
|
99
|
+
*
|
|
100
|
+
* Calling `tickSource` mirrors `source` directly; no wrapper source is
|
|
101
|
+
* created. Use `.tickSource(source).rate(n)` or `.rate(n, source)` when this
|
|
102
|
+
* system should divide an upstream source. The `delta` passed to {@link run}
|
|
103
|
+
* is the accumulated milliseconds since this system last fired.
|
|
104
|
+
*
|
|
105
|
+
* @param source - Tick source or system source to mirror.
|
|
106
|
+
* @returns This system, for chaining.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const second = new IntervalTickSource(1);
|
|
111
|
+
* world.system("Logger").tickSource(second).run(logStats);
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
tickSource(source: ITickSource): this;
|
|
115
|
+
private _setTickSource;
|
|
51
116
|
/**
|
|
52
117
|
* Assign this system to a pipeline phase.
|
|
53
118
|
*
|
|
54
|
-
*
|
|
55
|
-
* {@link
|
|
56
|
-
*
|
|
57
|
-
* are placed in the built-in `"update"` phase.
|
|
119
|
+
* Pass either a phase name (resolved at {@link World.start}) or an
|
|
120
|
+
* {@link IPhase} reference returned from {@link World.addPhase}. Systems
|
|
121
|
+
* with no explicit phase fall into the built-in `"update"` phase.
|
|
58
122
|
*
|
|
59
123
|
* @param p - Phase name or `IPhase` reference.
|
|
60
|
-
* @returns
|
|
124
|
+
* @returns This system, for chaining.
|
|
125
|
+
* @throws When the phase reference is not a `Phase`, or belongs to a
|
|
126
|
+
* different world.
|
|
61
127
|
*/
|
|
62
128
|
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
129
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
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
|
-
/**
|
|
77
|
-
* Register a per-tick callback that runs every time this system's phase
|
|
78
|
-
* executes, regardless of entity membership.
|
|
130
|
+
* Register a per-tick callback fired every time this system's phase runs,
|
|
131
|
+
* regardless of entity membership.
|
|
79
132
|
*
|
|
80
|
-
* Use
|
|
133
|
+
* Use it for logic that is not driven by component changes — polling,
|
|
81
134
|
* network flushing, global timers, etc.
|
|
82
135
|
*
|
|
83
136
|
* @param callback - Receives `now` (absolute timestamp in ms) and `delta`
|
|
84
|
-
* (ms since the
|
|
85
|
-
*
|
|
137
|
+
* (ms since the previous tick). If the system has an active interval,
|
|
138
|
+
* rate, or tick source, `delta` is the accumulated milliseconds since this
|
|
139
|
+
* system last fired.
|
|
140
|
+
* @returns This system, for chaining.
|
|
86
141
|
*/
|
|
87
142
|
run(callback: RunCallback): this;
|
|
88
143
|
/**
|
|
89
|
-
* Register a callback
|
|
90
|
-
*
|
|
91
|
-
* entity.
|
|
144
|
+
* Register a callback fired **every tick** for **every tracked entity**,
|
|
145
|
+
* unconditionally, with the listed components resolved from each entity.
|
|
92
146
|
*
|
|
93
147
|
* 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.
|
|
148
|
+
* called), `each` fires every tick the system runs, once per tracked entity.
|
|
149
|
+
* Components declared via {@link requires} are non-nullable in the resolved
|
|
150
|
+
* tuple; any other component class may be `undefined` if the entity lacks it.
|
|
98
151
|
*
|
|
99
152
|
* `each` does **not** modify the system's query — define membership with
|
|
100
153
|
* {@link requires} or {@link query} as usual. It does, however, implicitly
|
|
101
154
|
* enable {@link track}, so matched entities are exposed via {@link entities}.
|
|
102
155
|
*
|
|
103
|
-
* Only
|
|
104
|
-
*
|
|
156
|
+
* Only one `each` callback may be registered per system; calling `each` a
|
|
157
|
+
* second time throws.
|
|
105
158
|
*
|
|
106
159
|
* @param components - Component classes to resolve from each entity.
|
|
107
160
|
* @param callback - Receives the entity and a tuple of resolved component
|
|
108
|
-
* instances (`undefined` for
|
|
109
|
-
* @returns
|
|
110
|
-
* @throws
|
|
161
|
+
* instances (`undefined` for any not covered by {@link requires}).
|
|
162
|
+
* @returns This system, for chaining.
|
|
163
|
+
* @throws When `each` has already been registered on this system.
|
|
111
164
|
*
|
|
112
165
|
* @example
|
|
113
166
|
* ```ts
|
|
@@ -123,50 +176,81 @@ export declare class System<R extends (typeof Component)[] = []> extends Query<R
|
|
|
123
176
|
[K in keyof J]: MaybeRequired<J[K], R>;
|
|
124
177
|
}) => void): this;
|
|
125
178
|
/**
|
|
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.
|
|
179
|
+
* Set the entity-membership predicate using a {@link QueryDSL} expression.
|
|
134
180
|
*
|
|
135
181
|
* Replaces any implicit query derived from `update` watchlists and any
|
|
136
|
-
* previous `requires` call. After calling `query`, auto-
|
|
137
|
-
* `update`
|
|
182
|
+
* previous `requires` call. After calling `query`, watchlist auto-expansion
|
|
183
|
+
* via `update` is disabled.
|
|
138
184
|
*
|
|
139
|
-
* The optional `
|
|
140
|
-
*
|
|
141
|
-
* to be present on every matched entity, eliminating `| undefined` from
|
|
142
|
-
* those positions. It has no effect at runtime.
|
|
185
|
+
* The optional `_guaranteed` tuple is a pure type-level hint — see
|
|
186
|
+
* {@link Query.query} for details.
|
|
143
187
|
*
|
|
144
|
-
* @param q -
|
|
188
|
+
* @param q - Query expression.
|
|
145
189
|
* @param _guaranteed - Component classes guaranteed present on every matched
|
|
146
190
|
* entity (type hint only — not validated at runtime).
|
|
147
|
-
* @returns
|
|
191
|
+
* @returns This system, retyped with the guaranteed tuple as its `R`.
|
|
192
|
+
*/
|
|
193
|
+
query<T extends (typeof Component)[] = []>(q: QueryDSL, _guaranteed?: readonly [...T]): System<T>;
|
|
194
|
+
/**
|
|
195
|
+
* Shorthand for `query([...components])` — tracks entities that have **all**
|
|
196
|
+
* of the listed component types.
|
|
197
|
+
*
|
|
198
|
+
* Equivalent to `query({ HAS: components })`. The listed components are also
|
|
199
|
+
* recorded in the type parameter `R`, so {@link sort}, {@link each}, and
|
|
200
|
+
* {@link update} callbacks treat them as non-nullable.
|
|
201
|
+
*
|
|
202
|
+
* @param components - Component classes to require.
|
|
203
|
+
* @returns This system, retyped with the required tuple as its `R`.
|
|
204
|
+
*/
|
|
205
|
+
requires<T extends (typeof Component)[]>(...components: [...T]): System<T>;
|
|
206
|
+
/**
|
|
207
|
+
* Disable this system.
|
|
208
|
+
*
|
|
209
|
+
* While disabled the system is effectively invisible: the inbox is cleared
|
|
210
|
+
* immediately, any new `enter`, `exit`, or `update` events are silently
|
|
211
|
+
* dropped, and {@link _run} returns without executing any callbacks. Entity
|
|
212
|
+
* membership in the underlying query is still maintained so the tracked set
|
|
213
|
+
* remains consistent and the system resumes correctly when
|
|
214
|
+
* {@link enable} is called.
|
|
215
|
+
*
|
|
216
|
+
* Disabling is independent from tick-source cadence: `disable` suppresses
|
|
217
|
+
* callbacks, but a disabled system used as a tick source still drives
|
|
218
|
+
* downstream consumers. Use `stop()` on an external `IntervalTickSource` or
|
|
219
|
+
* `RateTickSource` reference to halt that clock itself.
|
|
220
|
+
*
|
|
221
|
+
* Calling `disable` on an already-disabled system is a no-op.
|
|
222
|
+
*
|
|
223
|
+
* @returns This system, for chaining.
|
|
148
224
|
*
|
|
149
225
|
* @example
|
|
150
226
|
* ```ts
|
|
151
|
-
* world.system("
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
227
|
+
* const sys = world.system("AI").requires(Enemy).run(runAI);
|
|
228
|
+
* // Pause AI processing during a cutscene:
|
|
229
|
+
* sys.disable();
|
|
230
|
+
* // Resume:
|
|
231
|
+
* sys.enable();
|
|
156
232
|
* ```
|
|
157
233
|
*/
|
|
158
|
-
|
|
234
|
+
disable(): this;
|
|
159
235
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
236
|
+
* Enable this system after a previous {@link disable} call.
|
|
237
|
+
*
|
|
238
|
+
* Once re-enabled the system resumes its normal tick behaviour: enter, exit,
|
|
239
|
+
* and update events are queued, and {@link _run} processes the inbox and fires
|
|
240
|
+
* all registered callbacks. Events that occurred while the system was disabled
|
|
241
|
+
* are not replayed.
|
|
162
242
|
*
|
|
163
|
-
*
|
|
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.
|
|
243
|
+
* Calling `enable` on an already-enabled system is a no-op.
|
|
167
244
|
*
|
|
168
|
-
* @
|
|
169
|
-
* @returns `this` for chaining.
|
|
245
|
+
* @returns This system, for chaining.
|
|
170
246
|
*/
|
|
171
|
-
|
|
247
|
+
enable(): this;
|
|
248
|
+
/**
|
|
249
|
+
* Not supported on `System`. Throws unconditionally.
|
|
250
|
+
*
|
|
251
|
+
* Systems are owned by the world for the duration of the session; if you
|
|
252
|
+
* need a temporary reactive set use a standalone {@link Query} via
|
|
253
|
+
* {@link World.query}.
|
|
254
|
+
*/
|
|
255
|
+
destroy(): never;
|
|
172
256
|
}
|