@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.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Query } from "./query.js";
|
|
2
2
|
import { Phase } from "./phase.js";
|
|
3
|
+
import { ALWAYS_TICK_SOURCE, IntervalTickSource, RateTickSource, } from "./timer.js";
|
|
3
4
|
/**
|
|
4
|
-
* A reactive processor
|
|
5
|
+
* A reactive processor running over a filtered subset of world entities.
|
|
5
6
|
*
|
|
6
|
-
* Systems are created and
|
|
7
|
+
* Systems are created and configured through {@link World.system}:
|
|
7
8
|
*
|
|
8
9
|
* ```ts
|
|
9
10
|
* world.system("Move")
|
|
@@ -14,9 +15,9 @@ import { Phase } from "./phase.js";
|
|
|
14
15
|
* .exit((e) => { console.log("entity left", e.eid); });
|
|
15
16
|
* ```
|
|
16
17
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* {@link World.runPhase}.
|
|
18
|
+
* Every builder method returns `this` for chaining. After registering systems
|
|
19
|
+
* call {@link World.start} once, then drive the loop with
|
|
20
|
+
* {@link World.runPhase} or {@link World.progress}.
|
|
20
21
|
*
|
|
21
22
|
* Internally each system holds a single ordered **inbox** of routed events
|
|
22
23
|
* (`enter`, `exit`, `update`). The world appends to it during command-queue
|
|
@@ -25,67 +26,62 @@ import { Phase } from "./phase.js";
|
|
|
25
26
|
*
|
|
26
27
|
* ### Component injection and type inference
|
|
27
28
|
*
|
|
28
|
-
* `enter`, `exit`, `update`, `each`, and `sort`
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* `enter`, `exit`, `update`, `each`, and `sort` accept an array of component
|
|
30
|
+
* classes resolved from the entity and passed as a typed tuple to the
|
|
31
|
+
* callback. Use `{ parent: SomeComponent }` to resolve from the entity's
|
|
32
|
+
* parent instead of the entity itself.
|
|
32
33
|
*
|
|
33
|
-
* Components declared via {@link requires} (or the
|
|
34
|
-
* {@link query}) are tracked as
|
|
35
|
-
* `
|
|
36
|
-
*
|
|
34
|
+
* Components declared via {@link requires} (or the `_guaranteed` argument of
|
|
35
|
+
* {@link query}) are tracked as the type parameter `R`. Inside `sort`,
|
|
36
|
+
* `each`, and `update` injection callbacks they are non-nullable; any other
|
|
37
|
+
* component remains `Type | undefined`.
|
|
38
|
+
*
|
|
39
|
+
* @typeParam R - Component classes guaranteed present on every matched entity.
|
|
37
40
|
*/
|
|
38
41
|
export class System extends Query {
|
|
39
42
|
constructor(name, world) {
|
|
40
43
|
super(name, world, false);
|
|
41
|
-
|
|
44
|
+
/** @internal Single inbox replayed in arrival order on every `_run`. */
|
|
45
|
+
this._inbox = [];
|
|
46
|
+
/** @internal Whether this system processes events and runs callbacks. */
|
|
47
|
+
this._enabled = true;
|
|
48
|
+
/** @internal Cadence source for this system. Defaults to every frame. */
|
|
49
|
+
this._tickSource = ALWAYS_TICK_SOURCE;
|
|
42
50
|
}
|
|
43
51
|
/**
|
|
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.
|
|
52
|
+
* @internal Routing entry: register query membership for `e`, push an
|
|
53
|
+
* inbox `enter` event when an `enter` callback is registered, and bridge
|
|
54
|
+
* watched components through {@link _notifyModified} to surface them as
|
|
55
|
+
* inbox `update` events on entry.
|
|
53
56
|
*/
|
|
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
57
|
_enter(e) {
|
|
68
58
|
this._entities?.add(e);
|
|
69
59
|
e._addQueryMembership(this);
|
|
60
|
+
if (!this._enabled) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
70
63
|
if (this._enterCallback !== undefined) {
|
|
71
|
-
this.
|
|
64
|
+
this._inbox.push({ kind: 0 /* InboxCommand.Enter */, entity: e });
|
|
72
65
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (this.watchlistBitmask.hasBit(c.bitPtr)) {
|
|
77
|
-
this.notifyModified(c);
|
|
66
|
+
e.components.forEach((c) => {
|
|
67
|
+
if (this._watchlistBitmask.hasBit(c.bitPtr)) {
|
|
68
|
+
this._notifyModified(c);
|
|
78
69
|
}
|
|
79
70
|
});
|
|
80
71
|
}
|
|
81
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* @internal Routing entry: deregister query membership for `e` and push an
|
|
74
|
+
* inbox `exit` event when an `exit` callback is registered, capturing a
|
|
75
|
+
* snapshot of the components the callback wants to inject so they remain
|
|
76
|
+
* resolvable after the underlying components are removed.
|
|
77
|
+
*/
|
|
82
78
|
_exit(e) {
|
|
83
79
|
this._entities?.delete(e);
|
|
84
80
|
e._removeQueryMembership(this);
|
|
81
|
+
if (!this._enabled) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
85
84
|
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
85
|
let snapshot;
|
|
90
86
|
if (this._exitSnapshotTypes && this._exitSnapshotTypes.length > 0) {
|
|
91
87
|
snapshot = new Map();
|
|
@@ -96,26 +92,37 @@ export class System extends Query {
|
|
|
96
92
|
}
|
|
97
93
|
}
|
|
98
94
|
}
|
|
99
|
-
this.
|
|
95
|
+
this._inbox.push({ kind: 1 /* InboxCommand.Exit */, entity: e, snapshot });
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
|
-
/**
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
/**
|
|
99
|
+
* @internal Routing entry: push an inbox `update` event when the modified
|
|
100
|
+
* component matches the watchlist.
|
|
101
|
+
*/
|
|
102
|
+
_notifyModified(c) {
|
|
103
|
+
if (!this._enabled || !this._watchlistBitmask.hasBit(c.bitPtr)) {
|
|
105
104
|
return;
|
|
106
105
|
}
|
|
107
|
-
this.
|
|
106
|
+
this._inbox.push({ kind: 2 /* InboxCommand.Update */, component: c });
|
|
108
107
|
}
|
|
109
108
|
/**
|
|
110
109
|
* @internal Execute one tick: drain the inbox in arrival order, then run
|
|
111
|
-
* `
|
|
112
|
-
*
|
|
113
|
-
*
|
|
110
|
+
* the `run` callback, then the `each` callback for every tracked entity.
|
|
111
|
+
*
|
|
112
|
+
* The whole body executes inside a `World.defer` scope; mutations made by
|
|
113
|
+
* callbacks land in the world queue and are processed when `_run` returns.
|
|
114
114
|
*/
|
|
115
115
|
_run(now, delta) {
|
|
116
|
+
if (!this._enabled) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (!this._tickSource.didTick) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const tickDelta = this._tickSource.lastFireDelta;
|
|
116
123
|
this.world.defer(() => {
|
|
117
|
-
for (let i = 0; i < this.
|
|
118
|
-
const event = this.
|
|
124
|
+
for (let i = 0; i < this._inbox.length; i++) {
|
|
125
|
+
const event = this._inbox[i];
|
|
119
126
|
switch (event.kind) {
|
|
120
127
|
case 0 /* InboxCommand.Enter */:
|
|
121
128
|
this._enterCallback(event.entity);
|
|
@@ -124,61 +131,155 @@ export class System extends Query {
|
|
|
124
131
|
this._exitCallback(event.entity, event.snapshot);
|
|
125
132
|
break;
|
|
126
133
|
case 2 /* InboxCommand.Update */:
|
|
127
|
-
const callback = this.
|
|
134
|
+
const callback = this._componentUpdateCallbacks.get(event.component.type);
|
|
128
135
|
if (callback) {
|
|
129
136
|
callback(event.component);
|
|
130
137
|
}
|
|
131
138
|
break;
|
|
132
139
|
}
|
|
133
140
|
}
|
|
134
|
-
this.
|
|
141
|
+
this._inbox.length = 0;
|
|
135
142
|
if (this._runCallback) {
|
|
136
|
-
this._runCallback(now,
|
|
143
|
+
this._runCallback(now, tickDelta);
|
|
137
144
|
}
|
|
138
|
-
if (this.
|
|
139
|
-
const cb = this.
|
|
145
|
+
if (this._eachCallback) {
|
|
146
|
+
const cb = this._eachCallback;
|
|
140
147
|
this.forEach((e) => cb(e));
|
|
141
148
|
}
|
|
142
149
|
});
|
|
143
150
|
}
|
|
151
|
+
/** True when this system's cadence source fired during the current frame. */
|
|
152
|
+
get didTick() {
|
|
153
|
+
return this._tickSource.didTick;
|
|
154
|
+
}
|
|
155
|
+
/** Milliseconds accumulated into this system's most recent fire. */
|
|
156
|
+
get lastFireDelta() {
|
|
157
|
+
return this._tickSource.lastFireDelta;
|
|
158
|
+
}
|
|
159
|
+
/** @internal Evaluate this system's cadence source for a frame. */
|
|
160
|
+
_evalTick(delta, frameId) {
|
|
161
|
+
return this._tickSource._evalTick(delta, frameId);
|
|
162
|
+
}
|
|
163
|
+
/** @internal Register this system source and its current cadence source. */
|
|
164
|
+
_register(world) {
|
|
165
|
+
world._registerTickSource(this);
|
|
166
|
+
this._tickSource._register(world);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Run this system at a fixed interval, expressed in seconds.
|
|
170
|
+
*
|
|
171
|
+
* This is seconds, unlike `World.beginFrame`, `World.progress`, and
|
|
172
|
+
* `runPhase`, which receive millisecond deltas. Calling `interval` replaces
|
|
173
|
+
* the current cadence source with an {@link IntervalTickSource}. When this
|
|
174
|
+
* system has a cadence source, the `delta` passed to {@link run} is the
|
|
175
|
+
* accumulated milliseconds since the previous fire, not the per-frame delta.
|
|
176
|
+
*
|
|
177
|
+
* @param seconds - Positive interval duration in seconds.
|
|
178
|
+
* @returns This system, for chaining.
|
|
179
|
+
* @throws When `seconds` is less than or equal to zero.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* world.system("AI")
|
|
184
|
+
* .interval(0.5)
|
|
185
|
+
* .run((now, delta) => tickAI(delta));
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
interval(seconds) {
|
|
189
|
+
this._setTickSource(new IntervalTickSource(seconds));
|
|
190
|
+
return this;
|
|
191
|
+
}
|
|
192
|
+
rate(n, source) {
|
|
193
|
+
this._setTickSource(new RateTickSource(n, source ?? this._tickSource));
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
144
196
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
197
|
+
* Run this system only when another timer or system ticks.
|
|
198
|
+
*
|
|
199
|
+
* Calling `tickSource` mirrors `source` directly; no wrapper source is
|
|
200
|
+
* created. Use `.tickSource(source).rate(n)` or `.rate(n, source)` when this
|
|
201
|
+
* system should divide an upstream source. The `delta` passed to {@link run}
|
|
202
|
+
* is the accumulated milliseconds since this system last fired.
|
|
147
203
|
*
|
|
148
|
-
*
|
|
204
|
+
* @param source - Tick source or system source to mirror.
|
|
205
|
+
* @returns This system, for chaining.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* const second = new IntervalTickSource(1);
|
|
210
|
+
* world.system("Logger").tickSource(second).run(logStats);
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
tickSource(source) {
|
|
214
|
+
this._setTickSource(source);
|
|
215
|
+
return this;
|
|
216
|
+
}
|
|
217
|
+
_setTickSource(source) {
|
|
218
|
+
this._tickSource = source;
|
|
219
|
+
source._register(this.world);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Assign this system to a pipeline phase.
|
|
223
|
+
*
|
|
224
|
+
* Pass either a phase name (resolved at {@link World.start}) or an
|
|
225
|
+
* {@link IPhase} reference returned from {@link World.addPhase}. Systems
|
|
226
|
+
* with no explicit phase fall into the built-in `"update"` phase.
|
|
227
|
+
*
|
|
228
|
+
* @param p - Phase name or `IPhase` reference.
|
|
229
|
+
* @returns This system, for chaining.
|
|
230
|
+
* @throws When the phase reference is not a `Phase`, or belongs to a
|
|
231
|
+
* different world.
|
|
232
|
+
*/
|
|
233
|
+
phase(p) {
|
|
234
|
+
if (typeof p !== "string") {
|
|
235
|
+
if (!(p instanceof Phase)) {
|
|
236
|
+
throw "Invalid Phase object";
|
|
237
|
+
}
|
|
238
|
+
if (p.world !== this.world) {
|
|
239
|
+
throw "Phase does not belong to this system's world";
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
this._phase = p;
|
|
243
|
+
return this;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Register a per-tick callback fired every time this system's phase runs,
|
|
247
|
+
* regardless of entity membership.
|
|
248
|
+
*
|
|
249
|
+
* Use it for logic that is not driven by component changes — polling,
|
|
149
250
|
* network flushing, global timers, etc.
|
|
150
251
|
*
|
|
151
252
|
* @param callback - Receives `now` (absolute timestamp in ms) and `delta`
|
|
152
|
-
* (ms since the
|
|
153
|
-
*
|
|
253
|
+
* (ms since the previous tick). If the system has an active interval,
|
|
254
|
+
* rate, or tick source, `delta` is the accumulated milliseconds since this
|
|
255
|
+
* system last fired.
|
|
256
|
+
* @returns This system, for chaining.
|
|
154
257
|
*/
|
|
155
258
|
run(callback) {
|
|
156
259
|
this._runCallback = callback;
|
|
157
260
|
return this;
|
|
158
261
|
}
|
|
159
262
|
/**
|
|
160
|
-
* Register a callback
|
|
161
|
-
*
|
|
162
|
-
* entity.
|
|
263
|
+
* Register a callback fired **every tick** for **every tracked entity**,
|
|
264
|
+
* unconditionally, with the listed components resolved from each entity.
|
|
163
265
|
*
|
|
164
266
|
* 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.
|
|
267
|
+
* called), `each` fires every tick the system runs, once per tracked entity.
|
|
268
|
+
* Components declared via {@link requires} are non-nullable in the resolved
|
|
269
|
+
* tuple; any other component class may be `undefined` if the entity lacks it.
|
|
169
270
|
*
|
|
170
271
|
* `each` does **not** modify the system's query — define membership with
|
|
171
272
|
* {@link requires} or {@link query} as usual. It does, however, implicitly
|
|
172
273
|
* enable {@link track}, so matched entities are exposed via {@link entities}.
|
|
173
274
|
*
|
|
174
|
-
* Only
|
|
175
|
-
*
|
|
275
|
+
* Only one `each` callback may be registered per system; calling `each` a
|
|
276
|
+
* second time throws.
|
|
176
277
|
*
|
|
177
278
|
* @param components - Component classes to resolve from each entity.
|
|
178
279
|
* @param callback - Receives the entity and a tuple of resolved component
|
|
179
|
-
* instances (`undefined` for
|
|
180
|
-
* @returns
|
|
181
|
-
* @throws
|
|
280
|
+
* instances (`undefined` for any not covered by {@link requires}).
|
|
281
|
+
* @returns This system, for chaining.
|
|
282
|
+
* @throws When `each` has already been registered on this system.
|
|
182
283
|
*
|
|
183
284
|
* @example
|
|
184
285
|
* ```ts
|
|
@@ -191,71 +292,109 @@ export class System extends Query {
|
|
|
191
292
|
* ```
|
|
192
293
|
*/
|
|
193
294
|
each(components, callback) {
|
|
194
|
-
if (this.
|
|
295
|
+
if (this._eachCallback) {
|
|
195
296
|
throw `each already registered for system '${this.name}'`;
|
|
196
297
|
}
|
|
197
298
|
this.track();
|
|
198
299
|
const types = components.map((C) => this.world.getComponentType(C));
|
|
199
|
-
this.
|
|
300
|
+
this._eachCallback = (e) => {
|
|
200
301
|
const resolved = types.map((t) => e.get(t));
|
|
201
302
|
callback(e, resolved);
|
|
202
303
|
};
|
|
203
304
|
return this;
|
|
204
305
|
}
|
|
205
306
|
/**
|
|
206
|
-
*
|
|
307
|
+
* Set the entity-membership predicate using a {@link QueryDSL} expression.
|
|
308
|
+
*
|
|
309
|
+
* Replaces any implicit query derived from `update` watchlists and any
|
|
310
|
+
* previous `requires` call. After calling `query`, watchlist auto-expansion
|
|
311
|
+
* via `update` is disabled.
|
|
207
312
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
313
|
+
* The optional `_guaranteed` tuple is a pure type-level hint — see
|
|
314
|
+
* {@link Query.query} for details.
|
|
315
|
+
*
|
|
316
|
+
* @param q - Query expression.
|
|
317
|
+
* @param _guaranteed - Component classes guaranteed present on every matched
|
|
318
|
+
* entity (type hint only — not validated at runtime).
|
|
319
|
+
* @returns This system, retyped with the guaranteed tuple as its `R`.
|
|
210
320
|
*/
|
|
211
|
-
|
|
212
|
-
|
|
321
|
+
query(q, _guaranteed) {
|
|
322
|
+
super.query(q, _guaranteed);
|
|
323
|
+
return this;
|
|
213
324
|
}
|
|
214
325
|
/**
|
|
215
|
-
*
|
|
326
|
+
* Shorthand for `query([...components])` — tracks entities that have **all**
|
|
327
|
+
* of the listed component types.
|
|
216
328
|
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
329
|
+
* Equivalent to `query({ HAS: components })`. The listed components are also
|
|
330
|
+
* recorded in the type parameter `R`, so {@link sort}, {@link each}, and
|
|
331
|
+
* {@link update} callbacks treat them as non-nullable.
|
|
332
|
+
*
|
|
333
|
+
* @param components - Component classes to require.
|
|
334
|
+
* @returns This system, retyped with the required tuple as its `R`.
|
|
335
|
+
*/
|
|
336
|
+
requires(...components) {
|
|
337
|
+
super.requires(...components);
|
|
338
|
+
return this;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Disable this system.
|
|
220
342
|
*
|
|
221
|
-
*
|
|
222
|
-
* `
|
|
223
|
-
*
|
|
224
|
-
*
|
|
343
|
+
* While disabled the system is effectively invisible: the inbox is cleared
|
|
344
|
+
* immediately, any new `enter`, `exit`, or `update` events are silently
|
|
345
|
+
* dropped, and {@link _run} returns without executing any callbacks. Entity
|
|
346
|
+
* membership in the underlying query is still maintained so the tracked set
|
|
347
|
+
* remains consistent and the system resumes correctly when
|
|
348
|
+
* {@link enable} is called.
|
|
225
349
|
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
350
|
+
* Disabling is independent from tick-source cadence: `disable` suppresses
|
|
351
|
+
* callbacks, but a disabled system used as a tick source still drives
|
|
352
|
+
* downstream consumers. Use `stop()` on an external `IntervalTickSource` or
|
|
353
|
+
* `RateTickSource` reference to halt that clock itself.
|
|
354
|
+
*
|
|
355
|
+
* Calling `disable` on an already-disabled system is a no-op.
|
|
356
|
+
*
|
|
357
|
+
* @returns This system, for chaining.
|
|
230
358
|
*
|
|
231
359
|
* @example
|
|
232
360
|
* ```ts
|
|
233
|
-
* world.system("
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
361
|
+
* const sys = world.system("AI").requires(Enemy).run(runAI);
|
|
362
|
+
* // Pause AI processing during a cutscene:
|
|
363
|
+
* sys.disable();
|
|
364
|
+
* // Resume:
|
|
365
|
+
* sys.enable();
|
|
238
366
|
* ```
|
|
239
367
|
*/
|
|
240
|
-
|
|
241
|
-
|
|
368
|
+
disable() {
|
|
369
|
+
this._enabled = false;
|
|
370
|
+
this._inbox.length = 0;
|
|
242
371
|
return this;
|
|
243
372
|
}
|
|
244
373
|
/**
|
|
245
|
-
*
|
|
246
|
-
* have **all** of the listed component types.
|
|
374
|
+
* Enable this system after a previous {@link disable} call.
|
|
247
375
|
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
376
|
+
* Once re-enabled the system resumes its normal tick behaviour: enter, exit,
|
|
377
|
+
* and update events are queued, and {@link _run} processes the inbox and fires
|
|
378
|
+
* all registered callbacks. Events that occurred while the system was disabled
|
|
379
|
+
* are not replayed.
|
|
252
380
|
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
381
|
+
* Calling `enable` on an already-enabled system is a no-op.
|
|
382
|
+
*
|
|
383
|
+
* @returns This system, for chaining.
|
|
255
384
|
*/
|
|
256
|
-
|
|
257
|
-
|
|
385
|
+
enable() {
|
|
386
|
+
this._enabled = true;
|
|
258
387
|
return this;
|
|
259
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Not supported on `System`. Throws unconditionally.
|
|
391
|
+
*
|
|
392
|
+
* Systems are owned by the world for the duration of the session; if you
|
|
393
|
+
* need a temporary reactive set use a standalone {@link Query} via
|
|
394
|
+
* {@link World.query}.
|
|
395
|
+
*/
|
|
396
|
+
destroy() {
|
|
397
|
+
throw `destroy() is not supported on System '${this.name}'`;
|
|
398
|
+
}
|
|
260
399
|
}
|
|
261
400
|
//# 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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"}
|
package/dist/timer.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** A clock that the world evaluates once per frame. */
|
|
2
|
+
export interface ITickSource {
|
|
3
|
+
/** True when this source fired during the current frame. */
|
|
4
|
+
readonly didTick: boolean;
|
|
5
|
+
/** Milliseconds accumulated into the most recent fire. */
|
|
6
|
+
readonly lastFireDelta: number;
|
|
7
|
+
}
|
|
8
|
+
/** Shared state and start/stop control for concrete tick sources. */
|
|
9
|
+
declare abstract class BaseTickSource implements ITickSource {
|
|
10
|
+
get didTick(): boolean;
|
|
11
|
+
get lastFireDelta(): number;
|
|
12
|
+
/** Resume this source without replaying time elapsed while stopped. */
|
|
13
|
+
start(): this;
|
|
14
|
+
/** Pause this source, freezing accumulators and counters until `start()`. */
|
|
15
|
+
stop(): this;
|
|
16
|
+
}
|
|
17
|
+
/** Fires every `intervalSeconds` of accumulated wall-clock time. */
|
|
18
|
+
export declare class IntervalTickSource extends BaseTickSource {
|
|
19
|
+
private readonly _intervalMs;
|
|
20
|
+
private _accumulator;
|
|
21
|
+
/**
|
|
22
|
+
* Create an interval source.
|
|
23
|
+
*
|
|
24
|
+
* Intervals are expressed in seconds, unlike `World.progress` and
|
|
25
|
+
* `World.beginFrame`, which receive millisecond deltas. Large deltas produce
|
|
26
|
+
* at most one tick; residual time is preserved by subtracting the interval.
|
|
27
|
+
*
|
|
28
|
+
* @param intervalSeconds - Positive interval duration in seconds.
|
|
29
|
+
* @throws When `intervalSeconds` is less than or equal to zero.
|
|
30
|
+
*/
|
|
31
|
+
constructor(intervalSeconds: number);
|
|
32
|
+
}
|
|
33
|
+
/** Fires every `rate` ticks of `source`, or every `rate` frames without one. */
|
|
34
|
+
export declare class RateTickSource extends BaseTickSource {
|
|
35
|
+
private readonly _rate;
|
|
36
|
+
private _counter;
|
|
37
|
+
/**
|
|
38
|
+
* Create a rate filter.
|
|
39
|
+
*
|
|
40
|
+
* Without `source`, this counts world frames. With `source`, it counts ticks
|
|
41
|
+
* from that upstream clock. The source is immutable, so cyclic source graphs
|
|
42
|
+
* cannot be constructed through the public API.
|
|
43
|
+
*
|
|
44
|
+
* @param rate - Positive integer tick divisor.
|
|
45
|
+
* @param source - Optional upstream source to divide.
|
|
46
|
+
* @throws When `rate` is not a positive integer.
|
|
47
|
+
*/
|
|
48
|
+
constructor(rate: number, source?: ITickSource);
|
|
49
|
+
}
|
|
50
|
+
export {};
|