@vworlds/vecs 1.0.0
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/.claude/settings.json +12 -0
- package/.devcontainer/devcontainer.json +22 -0
- package/.github/workflows/publish.yml +32 -0
- package/README.md +464 -0
- package/dist/component.d.ts +135 -0
- package/dist/component.js +101 -0
- package/dist/component.js.map +1 -0
- package/dist/entity.d.ts +157 -0
- package/dist/entity.js +199 -0
- package/dist/entity.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +25 -0
- package/dist/phase.d.ts +47 -0
- package/dist/phase.js +23 -0
- package/dist/phase.js.map +1 -0
- package/dist/system.d.ts +361 -0
- package/dist/system.js +396 -0
- package/dist/system.js.map +1 -0
- package/dist/util/array_map.d.ts +58 -0
- package/dist/util/array_map.js +84 -0
- package/dist/util/array_map.js.map +1 -0
- package/dist/util/bitset.d.ts +117 -0
- package/dist/util/bitset.js +177 -0
- package/dist/util/bitset.js.map +1 -0
- package/dist/util/events.d.ts +27 -0
- package/dist/util/events.js +43 -0
- package/dist/util/events.js.map +1 -0
- package/dist/util/ordered_set.d.ts +17 -0
- package/dist/util/ordered_set.js +69 -0
- package/dist/util/ordered_set.js.map +1 -0
- package/dist/world.d.ts +279 -0
- package/dist/world.js +453 -0
- package/dist/world.js.map +1 -0
- package/package.json +25 -0
- package/src/component.ts +180 -0
- package/src/entity.ts +276 -0
- package/src/index.ts +6 -0
- package/src/phase.ts +49 -0
- package/src/system.ts +693 -0
- package/src/util/array_map.ts +93 -0
- package/src/util/bitset.ts +199 -0
- package/src/util/events.ts +95 -0
- package/src/util/ordered_set.ts +82 -0
- package/src/world.ts +534 -0
- package/tests/_helpers.ts +30 -0
- package/tests/array_map.test.ts +68 -0
- package/tests/bitset.test.ts +127 -0
- package/tests/component.test.ts +104 -0
- package/tests/entity.test.ts +179 -0
- package/tests/events.test.ts +48 -0
- package/tests/ordered_set.test.ts +153 -0
- package/tests/setup.ts +6 -0
- package/tests/system.test.ts +800 -0
- package/tests/world.test.ts +174 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +9 -0
package/dist/system.js
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { ArrayMap } from "./util/array_map.js";
|
|
2
|
+
import { Bitset } from "./util/bitset.js";
|
|
3
|
+
import { OrderedSet } from "./util/ordered_set.js";
|
|
4
|
+
import { Component, calculateComponentBitmask, } from "./component.js";
|
|
5
|
+
import { Phase } from "./phase.js";
|
|
6
|
+
function HAS(world, ...components) {
|
|
7
|
+
const testBitmask = calculateComponentBitmask(components, world);
|
|
8
|
+
return (e) => e.componentBitmask.hasBitset(testBitmask);
|
|
9
|
+
}
|
|
10
|
+
function HAS_ONLY(world, ...components) {
|
|
11
|
+
const testBitmask = calculateComponentBitmask(components, world);
|
|
12
|
+
return (e) => e.componentBitmask.equal(testBitmask);
|
|
13
|
+
}
|
|
14
|
+
function NOT(func) {
|
|
15
|
+
return (e) => !func(e);
|
|
16
|
+
}
|
|
17
|
+
function AND(...funcs) {
|
|
18
|
+
return (e) => funcs.every((f) => f(e));
|
|
19
|
+
}
|
|
20
|
+
function OR(...funcs) {
|
|
21
|
+
return (e) => funcs.some((f) => f(e));
|
|
22
|
+
}
|
|
23
|
+
function PARENT(func) {
|
|
24
|
+
return (e) => (e.parent && func(e.parent)) || false;
|
|
25
|
+
}
|
|
26
|
+
const EMPTY_ENTITIES = new Set();
|
|
27
|
+
export class System {
|
|
28
|
+
constructor(
|
|
29
|
+
/** Unique name for this system, used in logs and pipeline output. */
|
|
30
|
+
name,
|
|
31
|
+
/** The world that owns this system. */
|
|
32
|
+
world) {
|
|
33
|
+
this.name = name;
|
|
34
|
+
this.world = world;
|
|
35
|
+
this.componentUpdateCallbacks = new ArrayMap();
|
|
36
|
+
this._enterCallback = [];
|
|
37
|
+
this._exitCallback = [];
|
|
38
|
+
this._belongs = (e) => false;
|
|
39
|
+
this.updateQueue = [];
|
|
40
|
+
this.hasQuery = false;
|
|
41
|
+
this.watchlistBitmask = new Bitset();
|
|
42
|
+
}
|
|
43
|
+
/** Returns the system name. */
|
|
44
|
+
toString() {
|
|
45
|
+
return this.name;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Read-only view of the entities currently tracked by this system.
|
|
49
|
+
*
|
|
50
|
+
* Empty unless {@link track} (or {@link each}, which implies it) was
|
|
51
|
+
* called during system configuration.
|
|
52
|
+
*/
|
|
53
|
+
get entities() {
|
|
54
|
+
return this._entities ?? EMPTY_ENTITIES;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Assign this system to a pipeline phase.
|
|
58
|
+
*
|
|
59
|
+
* The phase can be specified by name (the world will resolve it at
|
|
60
|
+
* {@link World.start | start} time) or by an {@link IPhase} reference
|
|
61
|
+
* returned from {@link World.addPhase}. Systems without an explicit phase
|
|
62
|
+
* are placed in the built-in `"update"` phase.
|
|
63
|
+
*
|
|
64
|
+
* @param p - Phase name or `IPhase` reference.
|
|
65
|
+
* @returns `this` for chaining.
|
|
66
|
+
*/
|
|
67
|
+
phase(p) {
|
|
68
|
+
if (typeof p !== "string") {
|
|
69
|
+
if (!(p instanceof Phase))
|
|
70
|
+
throw "Invalid Phase object";
|
|
71
|
+
if (p.world !== this.world)
|
|
72
|
+
throw "Phase does not belong to this system's world";
|
|
73
|
+
}
|
|
74
|
+
this._phase = p;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
/** @internal Delivers a component-modified notification to this system. */
|
|
78
|
+
notifyModified(c) {
|
|
79
|
+
if (!this.watchlistBitmask.hasBit(c.bitPtr))
|
|
80
|
+
return;
|
|
81
|
+
this.updateQueue.push(c);
|
|
82
|
+
}
|
|
83
|
+
/** Returns `true` if the entity satisfies this system's query. */
|
|
84
|
+
belongs(e) {
|
|
85
|
+
return this._belongs(e);
|
|
86
|
+
}
|
|
87
|
+
/** @internal Fires `enter` callbacks for a newly matched entity. */
|
|
88
|
+
_enter(e) {
|
|
89
|
+
this._enterCallback.forEach((callback) => callback(e));
|
|
90
|
+
e.forEachComponent((c) => this.notifyModified(c));
|
|
91
|
+
this._entities?.add(e);
|
|
92
|
+
}
|
|
93
|
+
/** @internal Fires `exit` callbacks when an entity leaves the system. */
|
|
94
|
+
_exit(e) {
|
|
95
|
+
this._exitCallback.forEach((callback) => callback(e));
|
|
96
|
+
this._entities?.delete(e);
|
|
97
|
+
// remove queued updates for components of the exiting entity:
|
|
98
|
+
this.updateQueue.forEach((c, i) => {
|
|
99
|
+
if (!c)
|
|
100
|
+
return;
|
|
101
|
+
if (c.entity === e)
|
|
102
|
+
this.updateQueue[i] = undefined;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/** @internal Execute one tick: run `run`, fire `each`, then drain the update queue. */
|
|
106
|
+
_run(now, delta) {
|
|
107
|
+
if (this._runCallback)
|
|
108
|
+
this._runCallback(now, delta);
|
|
109
|
+
if (this.eachCallback) {
|
|
110
|
+
const cb = this.eachCallback;
|
|
111
|
+
this._entities?.forEach((e) => cb(e));
|
|
112
|
+
}
|
|
113
|
+
this.updateQueue.forEach((c) => {
|
|
114
|
+
if (!c)
|
|
115
|
+
return;
|
|
116
|
+
const callback = this.componentUpdateCallbacks.get(c.type);
|
|
117
|
+
if (callback) {
|
|
118
|
+
callback(c);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
this.updateQueue.length = 0;
|
|
122
|
+
}
|
|
123
|
+
getComponent(e, C, considerDeleted) {
|
|
124
|
+
let c;
|
|
125
|
+
if (typeof C === "number") {
|
|
126
|
+
c = e.get(C, considerDeleted); // obtain an instance of C
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
c = e.parent && e.parent.get(C.parent, considerDeleted);
|
|
130
|
+
}
|
|
131
|
+
return c;
|
|
132
|
+
}
|
|
133
|
+
getInjected(e, inject, considerDeleted = false) {
|
|
134
|
+
const injected = [];
|
|
135
|
+
inject.forEach((C) => {
|
|
136
|
+
const c = this.getComponent(e, C, considerDeleted);
|
|
137
|
+
if (!c)
|
|
138
|
+
throw "system does not contain component";
|
|
139
|
+
injected.push(c);
|
|
140
|
+
});
|
|
141
|
+
return injected;
|
|
142
|
+
}
|
|
143
|
+
mapInjectedClassToTypes(inject) {
|
|
144
|
+
//map injected class constructors to type numbers which are faster to search for later
|
|
145
|
+
return inject.map((C) => {
|
|
146
|
+
if (typeof C === "function")
|
|
147
|
+
return this.world.getComponentType(C);
|
|
148
|
+
return { parent: this.world.getComponentType(C.parent) };
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// Implement the overloaded function
|
|
152
|
+
enter(injectOrCallback, callback) {
|
|
153
|
+
if (typeof injectOrCallback === "function") {
|
|
154
|
+
// It is the second signature
|
|
155
|
+
this._enterCallback.push(injectOrCallback);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
// It is the first signature
|
|
159
|
+
const inject = this.mapInjectedClassToTypes(injectOrCallback);
|
|
160
|
+
this._enterCallback.push((e) => {
|
|
161
|
+
callback(e, this.getInjected(e, inject));
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
// Implement the overloaded function
|
|
167
|
+
exit(injectOrCallback, callback) {
|
|
168
|
+
if (typeof injectOrCallback === "function") {
|
|
169
|
+
// It is the second signature
|
|
170
|
+
this._exitCallback.push(injectOrCallback);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// It is the first signature
|
|
174
|
+
const inject = this.mapInjectedClassToTypes(injectOrCallback);
|
|
175
|
+
this._exitCallback.push((e) => {
|
|
176
|
+
callback(e, this.getInjected(e, inject, true));
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Register a per-tick callback that runs every time this system's phase
|
|
183
|
+
* executes, regardless of entity membership.
|
|
184
|
+
*
|
|
185
|
+
* Use this for logic that is not driven by component updates — polling,
|
|
186
|
+
* network flushing, global timers, etc.
|
|
187
|
+
*
|
|
188
|
+
* @param callback - Receives `now` (absolute timestamp in ms) and `delta`
|
|
189
|
+
* (ms since the last tick).
|
|
190
|
+
* @returns `this` for chaining.
|
|
191
|
+
*/
|
|
192
|
+
run(callback) {
|
|
193
|
+
this._runCallback = callback;
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
update(ComponentClass, injectOrCallback, callback) {
|
|
197
|
+
const type = this.world.getComponentType(ComponentClass);
|
|
198
|
+
if (typeof injectOrCallback === "function") {
|
|
199
|
+
// Only ComponentClass and callback are passed
|
|
200
|
+
callback = injectOrCallback;
|
|
201
|
+
this.componentUpdateCallbacks.set(type, callback);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// ComponentClass, inject, and callback are passed
|
|
205
|
+
const inject = injectOrCallback;
|
|
206
|
+
//map injected class constructors to component type numbers which are faster to search for later
|
|
207
|
+
const injectedComponentTypes = inject.map((C) => this.world.getComponentType(C));
|
|
208
|
+
const cb = (c) => {
|
|
209
|
+
const injected = [];
|
|
210
|
+
injectedComponentTypes.forEach((InjectedComponentType) => {
|
|
211
|
+
injected.push(c.entity.get(InjectedComponentType));
|
|
212
|
+
});
|
|
213
|
+
if (callback) {
|
|
214
|
+
callback(c, injected);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
this.componentUpdateCallbacks.set(type, cb);
|
|
218
|
+
}
|
|
219
|
+
this.watchlistBitmask.add(type);
|
|
220
|
+
if (!this.hasQuery) {
|
|
221
|
+
const watchlist = this.watchlistBitmask.indices();
|
|
222
|
+
this._belongs = HAS(this.world, ...watchlist);
|
|
223
|
+
}
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Register a callback that fires **every tick** for every entity currently
|
|
228
|
+
* tracked by this system, with the listed components resolved from each
|
|
229
|
+
* entity.
|
|
230
|
+
*
|
|
231
|
+
* Unlike {@link update} (which only fires when `component.modified()` is
|
|
232
|
+
* called), `each` fires unconditionally on every tick the system runs,
|
|
233
|
+
* once per tracked entity. Components declared via {@link requires} are
|
|
234
|
+
* guaranteed non-null in the resolved tuple; any other component class
|
|
235
|
+
* may be `undefined` if the entity lacks it.
|
|
236
|
+
*
|
|
237
|
+
* `each` does **not** modify the system's query — define membership with
|
|
238
|
+
* {@link requires} or {@link query} as usual. It does, however, implicitly
|
|
239
|
+
* enable {@link track}, so matched entities are exposed via {@link entities}.
|
|
240
|
+
*
|
|
241
|
+
* Only a single `each` callback may be registered per system; calling
|
|
242
|
+
* `each` a second time throws.
|
|
243
|
+
*
|
|
244
|
+
* @param components - Component classes to resolve from each entity.
|
|
245
|
+
* @param callback - Receives the entity and a tuple of resolved component
|
|
246
|
+
* instances (`undefined` for components not covered by {@link requires}).
|
|
247
|
+
* @returns `this` for chaining.
|
|
248
|
+
* @throws If `each` has already been registered on this system.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* world.system("Move")
|
|
253
|
+
* .requires(Position, Velocity)
|
|
254
|
+
* .each([Position, Velocity], (e, [pos, vel]) => {
|
|
255
|
+
* pos.x += vel.vx;
|
|
256
|
+
* pos.y += vel.vy;
|
|
257
|
+
* });
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
each(components, callback) {
|
|
261
|
+
if (this.eachCallback) {
|
|
262
|
+
throw `each already registered for system '${this.name}'`;
|
|
263
|
+
}
|
|
264
|
+
this.track();
|
|
265
|
+
const types = components.map((C) => this.world.getComponentType(C));
|
|
266
|
+
this.eachCallback = (e) => {
|
|
267
|
+
const resolved = types.map((t) => e.get(t));
|
|
268
|
+
callback(e, resolved);
|
|
269
|
+
};
|
|
270
|
+
return this;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Enable entity tracking: matched entities are inserted into
|
|
274
|
+
* {@link entities} as they enter the system and removed as they exit.
|
|
275
|
+
*
|
|
276
|
+
* Idempotent. Intended to be called during system configuration before
|
|
277
|
+
* `world.start()`; entities already matched when `track` is called late
|
|
278
|
+
* will not be backfilled.
|
|
279
|
+
*
|
|
280
|
+
* {@link each} implies `track` — call this directly only when you want
|
|
281
|
+
* the tracked set without an `each` callback.
|
|
282
|
+
*
|
|
283
|
+
* @returns `this` for chaining.
|
|
284
|
+
*/
|
|
285
|
+
track() {
|
|
286
|
+
this._entities ?? (this._entities = new Set());
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Enable sorted entity tracking: matched entities are stored in insertion
|
|
291
|
+
* order determined by `compare`, which receives a tuple of resolved
|
|
292
|
+
* component instances for each pair of entities being ordered.
|
|
293
|
+
*
|
|
294
|
+
* Implies {@link track}.
|
|
295
|
+
*
|
|
296
|
+
* @param components - Component classes to resolve and pass to `compare`.
|
|
297
|
+
* @param compare - Returns a negative number, zero, or positive number when
|
|
298
|
+
* `a` should sort before, equal to, or after `b`.
|
|
299
|
+
* @returns `this` for chaining.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```ts
|
|
303
|
+
* world.system("Render")
|
|
304
|
+
* .requires(Position, Sprite)
|
|
305
|
+
* .sort([Position], ([posA], [posB]) => posA.z - posB.z);
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
sort(components, compare) {
|
|
309
|
+
const types = components.map((C) => this.world.getComponentType(C));
|
|
310
|
+
this._entities = new OrderedSet((a, b) => compare(types.map((t) => a.get(t, true)), types.map((t) => b.get(t, true))));
|
|
311
|
+
return this;
|
|
312
|
+
}
|
|
313
|
+
queryBuilder(q) {
|
|
314
|
+
if (typeof q === "number" ||
|
|
315
|
+
(typeof q === "function" && q.prototype instanceof Component)) {
|
|
316
|
+
return HAS(this.world, q);
|
|
317
|
+
}
|
|
318
|
+
else if (typeof q === "function") {
|
|
319
|
+
return q;
|
|
320
|
+
}
|
|
321
|
+
if (q instanceof Array) {
|
|
322
|
+
return HAS(this.world, ...q);
|
|
323
|
+
}
|
|
324
|
+
if ("HAS" in q) {
|
|
325
|
+
return this.queryBuilder(q.HAS);
|
|
326
|
+
}
|
|
327
|
+
if ("HAS_ONLY" in q) {
|
|
328
|
+
const v = q.HAS_ONLY;
|
|
329
|
+
if (v instanceof Array) {
|
|
330
|
+
return HAS_ONLY(this.world, ...v);
|
|
331
|
+
}
|
|
332
|
+
return HAS_ONLY(this.world, v);
|
|
333
|
+
}
|
|
334
|
+
if ("AND" in q) {
|
|
335
|
+
return AND(...q.AND.map((sq) => this.queryBuilder(sq)));
|
|
336
|
+
}
|
|
337
|
+
if ("OR" in q) {
|
|
338
|
+
return OR(...q.OR.map((sq) => this.queryBuilder(sq)));
|
|
339
|
+
}
|
|
340
|
+
if ("NOT" in q) {
|
|
341
|
+
return NOT(this.queryBuilder(q.NOT));
|
|
342
|
+
}
|
|
343
|
+
if ("PARENT" in q) {
|
|
344
|
+
return PARENT(this.queryBuilder(q.PARENT));
|
|
345
|
+
}
|
|
346
|
+
throw "Unrecognized query term";
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Set the entity membership predicate using the {@link SystemQuery} DSL.
|
|
350
|
+
*
|
|
351
|
+
* Replaces any implicit query derived from `update` watchlists and any
|
|
352
|
+
* previous `requires` call. After calling `query`, auto-expanding of
|
|
353
|
+
* `update` watchlists is disabled.
|
|
354
|
+
*
|
|
355
|
+
* The optional `guaranteed` tuple is a pure type-level hint: it tells
|
|
356
|
+
* `sort`, `each`, and `update` callbacks which components are guaranteed
|
|
357
|
+
* to be present on every matched entity, eliminating `| undefined` from
|
|
358
|
+
* those positions. It has no effect at runtime.
|
|
359
|
+
*
|
|
360
|
+
* @param q - A {@link SystemQuery} expression.
|
|
361
|
+
* @param _guaranteed - Component classes guaranteed present on every matched
|
|
362
|
+
* entity (type hint only — not validated at runtime).
|
|
363
|
+
* @returns `this` for chaining.
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```ts
|
|
367
|
+
* world.system("Move")
|
|
368
|
+
* .query({ AND: [{ HAS: Position }, { HAS: Velocity }] }, [Position, Velocity])
|
|
369
|
+
* .each([Position, Velocity], (e, [pos, vel]) => {
|
|
370
|
+
* pos.x += vel.vx; // no ! needed
|
|
371
|
+
* });
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
query(q, _guaranteed) {
|
|
375
|
+
this._belongs = this.queryBuilder(q);
|
|
376
|
+
this.hasQuery = true;
|
|
377
|
+
return this;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Shorthand for `query([...components])` — the system tracks entities that
|
|
381
|
+
* have **all** of the listed component types.
|
|
382
|
+
*
|
|
383
|
+
* Equivalent to `query({ HAS: components })`. Unlike `query`, passing
|
|
384
|
+
* component classes here also informs the types of {@link sort} and
|
|
385
|
+
* {@link each} callbacks: listed components will be non-nullable in those
|
|
386
|
+
* tuples.
|
|
387
|
+
*
|
|
388
|
+
* @param components - One or more component classes.
|
|
389
|
+
* @returns `this` for chaining.
|
|
390
|
+
*/
|
|
391
|
+
requires(...components) {
|
|
392
|
+
this.query(components);
|
|
393
|
+
return this;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
//# sourceMappingURL=system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../src/system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `Map<number, T>` backed by a sparse JavaScript array.
|
|
3
|
+
*
|
|
4
|
+
* For small, dense integer key spaces this is significantly faster than
|
|
5
|
+
* `Map` because array index access avoids the hash-table overhead. Used
|
|
6
|
+
* internally to store per-entity component instances and per-type component
|
|
7
|
+
* metadata.
|
|
8
|
+
*
|
|
9
|
+
* Keys must be non-negative integers. Gaps in the key space are represented
|
|
10
|
+
* as `undefined` slots and do not count toward `size`.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The value type stored in the map.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ArrayMap<T> {
|
|
15
|
+
private backend;
|
|
16
|
+
private _size;
|
|
17
|
+
constructor();
|
|
18
|
+
/**
|
|
19
|
+
* Store `value` at `key`, replacing any existing value.
|
|
20
|
+
*
|
|
21
|
+
* @param key - Non-negative integer key.
|
|
22
|
+
* @param value - Value to store.
|
|
23
|
+
*/
|
|
24
|
+
set(key: number, value: T): void;
|
|
25
|
+
/**
|
|
26
|
+
* Return the value stored at `key`, or `undefined` if not present.
|
|
27
|
+
*
|
|
28
|
+
* @param key - Non-negative integer key.
|
|
29
|
+
*/
|
|
30
|
+
get(key: number): T | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Remove the entry at `key`. Does nothing if `key` is not present.
|
|
33
|
+
*
|
|
34
|
+
* @param key - Non-negative integer key.
|
|
35
|
+
*/
|
|
36
|
+
delete(key: number): void;
|
|
37
|
+
/**
|
|
38
|
+
* Return `true` if an entry exists at `key`.
|
|
39
|
+
*
|
|
40
|
+
* @param key - Non-negative integer key.
|
|
41
|
+
*/
|
|
42
|
+
has(key: number): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Iterate over all present entries.
|
|
45
|
+
*
|
|
46
|
+
* Undefined slots are skipped; the callback is only called for keys that
|
|
47
|
+
* have an associated value.
|
|
48
|
+
*
|
|
49
|
+
* @param callback - Called with `(value, key, map)` for each entry.
|
|
50
|
+
*/
|
|
51
|
+
forEach(callback: (value: T, key: number, map: ArrayMap<T>) => void): void;
|
|
52
|
+
/**
|
|
53
|
+
* Remove all entries and reset the size to zero.
|
|
54
|
+
*/
|
|
55
|
+
clear(): void;
|
|
56
|
+
/** The number of entries currently in the map. */
|
|
57
|
+
get size(): number;
|
|
58
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `Map<number, T>` backed by a sparse JavaScript array.
|
|
3
|
+
*
|
|
4
|
+
* For small, dense integer key spaces this is significantly faster than
|
|
5
|
+
* `Map` because array index access avoids the hash-table overhead. Used
|
|
6
|
+
* internally to store per-entity component instances and per-type component
|
|
7
|
+
* metadata.
|
|
8
|
+
*
|
|
9
|
+
* Keys must be non-negative integers. Gaps in the key space are represented
|
|
10
|
+
* as `undefined` slots and do not count toward `size`.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The value type stored in the map.
|
|
13
|
+
*/
|
|
14
|
+
export class ArrayMap {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.backend = [];
|
|
17
|
+
this._size = 0;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Store `value` at `key`, replacing any existing value.
|
|
21
|
+
*
|
|
22
|
+
* @param key - Non-negative integer key.
|
|
23
|
+
* @param value - Value to store.
|
|
24
|
+
*/
|
|
25
|
+
set(key, value) {
|
|
26
|
+
if (this.backend[key] === undefined) {
|
|
27
|
+
this._size++;
|
|
28
|
+
}
|
|
29
|
+
this.backend[key] = value;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Return the value stored at `key`, or `undefined` if not present.
|
|
33
|
+
*
|
|
34
|
+
* @param key - Non-negative integer key.
|
|
35
|
+
*/
|
|
36
|
+
get(key) {
|
|
37
|
+
return this.backend[key];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Remove the entry at `key`. Does nothing if `key` is not present.
|
|
41
|
+
*
|
|
42
|
+
* @param key - Non-negative integer key.
|
|
43
|
+
*/
|
|
44
|
+
delete(key) {
|
|
45
|
+
if (this.backend[key] !== undefined) {
|
|
46
|
+
this.backend[key] = undefined;
|
|
47
|
+
this._size--;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Return `true` if an entry exists at `key`.
|
|
52
|
+
*
|
|
53
|
+
* @param key - Non-negative integer key.
|
|
54
|
+
*/
|
|
55
|
+
has(key) {
|
|
56
|
+
return this.backend[key] !== undefined;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Iterate over all present entries.
|
|
60
|
+
*
|
|
61
|
+
* Undefined slots are skipped; the callback is only called for keys that
|
|
62
|
+
* have an associated value.
|
|
63
|
+
*
|
|
64
|
+
* @param callback - Called with `(value, key, map)` for each entry.
|
|
65
|
+
*/
|
|
66
|
+
forEach(callback) {
|
|
67
|
+
this.backend.forEach((value, index) => {
|
|
68
|
+
if (value !== undefined) {
|
|
69
|
+
callback(value, index, this);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Remove all entries and reset the size to zero.
|
|
75
|
+
*/
|
|
76
|
+
clear() {
|
|
77
|
+
this.backend.length = 0;
|
|
78
|
+
}
|
|
79
|
+
/** The number of entries currently in the map. */
|
|
80
|
+
get size() {
|
|
81
|
+
return this._size;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=array_map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array_map.js","sourceRoot":"","sources":["../../src/util/array_map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,QAAQ;IAInB;QACE,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,GAAW,EAAE,KAAQ;QACvB,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;YACnC,IAAI,CAAC,KAAK,EAAE,CAAC;SACd;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,GAAW;QAChB,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;YACnC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;YAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;SACd;IACH,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IACzC,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,QAA2D;QACjE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACpC,IAAI,KAAK,KAAK,SAAS,EAAE;gBACvB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;aAC9B;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,kDAAkD;IAClD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A compact, growable set of non-negative integers backed by an array of
|
|
3
|
+
* 32-bit words.
|
|
4
|
+
*
|
|
5
|
+
* Used internally to represent entity archetypes (the set of component type
|
|
6
|
+
* ids attached to an entity) and system watchlists. Exposed in the public API
|
|
7
|
+
* so that component data can use it for bit-flag fields:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* class Tags extends Component {
|
|
11
|
+
* tags = new Bitset();
|
|
12
|
+
* oldTags = new Bitset();
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* // Check a specific tag bit:
|
|
16
|
+
* if (tags.tags.has(TAG_VISIBLE)) { ... }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare class Bitset {
|
|
20
|
+
private bits;
|
|
21
|
+
constructor();
|
|
22
|
+
/**
|
|
23
|
+
* Return `true` if this bitset and `other` have exactly the same bits set.
|
|
24
|
+
*/
|
|
25
|
+
equal(other: Bitset): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* OR the given `bitmask` word into the word at position `arrayIndex`.
|
|
28
|
+
*
|
|
29
|
+
* @internal Low-level bulk operation; prefer {@link add} for single bits.
|
|
30
|
+
*/
|
|
31
|
+
addIndexBitmask(arrayIndex: number, bitmask: number): void;
|
|
32
|
+
/**
|
|
33
|
+
* Replace the word at position `arrayIndex` with `bitmask`.
|
|
34
|
+
*
|
|
35
|
+
* @internal Used by network deserialization to set a whole word at once.
|
|
36
|
+
*/
|
|
37
|
+
setIndexBitmask(arrayIndex: number, bitmask: number): void;
|
|
38
|
+
/**
|
|
39
|
+
* Set the bit described by `bptr` (fast path using a pre-computed
|
|
40
|
+
* {@link BitPtr}).
|
|
41
|
+
*/
|
|
42
|
+
addBit(bptr: BitPtr): void;
|
|
43
|
+
/**
|
|
44
|
+
* Set bit `n`.
|
|
45
|
+
*
|
|
46
|
+
* @param n - Non-negative integer bit index.
|
|
47
|
+
*/
|
|
48
|
+
add(n: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* Clear bit `n`.
|
|
51
|
+
*
|
|
52
|
+
* Trailing zero words are trimmed so that the internal array stays compact.
|
|
53
|
+
*
|
|
54
|
+
* @param n - Non-negative integer bit index.
|
|
55
|
+
*/
|
|
56
|
+
delete(n: number): void;
|
|
57
|
+
/**
|
|
58
|
+
* Return `true` if the bit described by `bptr` is set (fast path).
|
|
59
|
+
*/
|
|
60
|
+
hasBit(bptr: BitPtr): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Return `true` if bit `n` is set.
|
|
63
|
+
*
|
|
64
|
+
* @param n - Non-negative integer bit index.
|
|
65
|
+
*/
|
|
66
|
+
has(n: number): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Return `true` if the given word-level bitmask is fully set at `arrayIndex`.
|
|
69
|
+
*
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
hasIndexBitmask(arrayIndex: number, bitmask: number): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Return `true` if every bit set in `other` is also set in `this` (i.e.
|
|
75
|
+
* `other` is a subset of `this`).
|
|
76
|
+
*
|
|
77
|
+
* Used by the world to test whether an entity's archetype satisfies a
|
|
78
|
+
* system's `HAS` query.
|
|
79
|
+
*/
|
|
80
|
+
hasBitset(other: Bitset): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Iterate over every set bit index in ascending order.
|
|
83
|
+
*
|
|
84
|
+
* @param callback - Called with each set bit index.
|
|
85
|
+
*/
|
|
86
|
+
forEach(callback: (n: number) => void): void;
|
|
87
|
+
/**
|
|
88
|
+
* Return an array of all set bit indices in ascending order.
|
|
89
|
+
*
|
|
90
|
+
* @returns `number[]` of set bit positions.
|
|
91
|
+
*/
|
|
92
|
+
indices(): number[];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A pre-computed pointer into a {@link Bitset}'s internal word array.
|
|
96
|
+
*
|
|
97
|
+
* Computing `arrayIndex` and `bitmask` from a raw bit index requires a floor
|
|
98
|
+
* division and a bitshift. `BitPtr` caches those values so that hot-path
|
|
99
|
+
* archetype checks ({@link Bitset.hasBit}, {@link Bitset.addBit}) avoid
|
|
100
|
+
* repeating the arithmetic on every entity update.
|
|
101
|
+
*
|
|
102
|
+
* A `BitPtr` is created once per component type and stored on
|
|
103
|
+
* {@link ComponentMeta.bitPtr}.
|
|
104
|
+
*/
|
|
105
|
+
export declare class BitPtr {
|
|
106
|
+
/** The raw bit index this pointer refers to. */
|
|
107
|
+
readonly value: number;
|
|
108
|
+
/** Index of the 32-bit word that contains this bit. */
|
|
109
|
+
readonly arrayIndex: number;
|
|
110
|
+
/** Single-bit mask within that word. */
|
|
111
|
+
readonly bitmask: number;
|
|
112
|
+
constructor(
|
|
113
|
+
/** The raw bit index this pointer refers to. */
|
|
114
|
+
value: number);
|
|
115
|
+
/** Return `true` if both pointers refer to the same bit position. */
|
|
116
|
+
equals(other: BitPtr): boolean;
|
|
117
|
+
}
|