@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
|
@@ -0,0 +1,177 @@
|
|
|
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 class Bitset {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.bits = [];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Return `true` if this bitset and `other` have exactly the same bits set.
|
|
25
|
+
*/
|
|
26
|
+
equal(other) {
|
|
27
|
+
return (this.bits.length === other.bits.length &&
|
|
28
|
+
this.bits.every((v, i) => other.bits[i] === v));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* OR the given `bitmask` word into the word at position `arrayIndex`.
|
|
32
|
+
*
|
|
33
|
+
* @internal Low-level bulk operation; prefer {@link add} for single bits.
|
|
34
|
+
*/
|
|
35
|
+
addIndexBitmask(arrayIndex, bitmask) {
|
|
36
|
+
this.bits[arrayIndex] |= bitmask;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Replace the word at position `arrayIndex` with `bitmask`.
|
|
40
|
+
*
|
|
41
|
+
* @internal Used by network deserialization to set a whole word at once.
|
|
42
|
+
*/
|
|
43
|
+
setIndexBitmask(arrayIndex, bitmask) {
|
|
44
|
+
this.bits[arrayIndex] = bitmask;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Set the bit described by `bptr` (fast path using a pre-computed
|
|
48
|
+
* {@link BitPtr}).
|
|
49
|
+
*/
|
|
50
|
+
addBit(bptr) {
|
|
51
|
+
this.addIndexBitmask(bptr.arrayIndex, bptr.bitmask);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Set bit `n`.
|
|
55
|
+
*
|
|
56
|
+
* @param n - Non-negative integer bit index.
|
|
57
|
+
*/
|
|
58
|
+
add(n) {
|
|
59
|
+
const arrayIndex = Math.floor(n / 32);
|
|
60
|
+
const bitmask = 1 << n % 32;
|
|
61
|
+
this.addIndexBitmask(arrayIndex, bitmask);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Clear bit `n`.
|
|
65
|
+
*
|
|
66
|
+
* Trailing zero words are trimmed so that the internal array stays compact.
|
|
67
|
+
*
|
|
68
|
+
* @param n - Non-negative integer bit index.
|
|
69
|
+
*/
|
|
70
|
+
delete(n) {
|
|
71
|
+
const arrayIndex = Math.floor(n / 32);
|
|
72
|
+
const current = this.bits[arrayIndex];
|
|
73
|
+
if (current === undefined) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
this.bits[arrayIndex] = current & ~(1 << n % 32);
|
|
78
|
+
}
|
|
79
|
+
while (this.bits.length && this.bits[this.bits.length - 1] === 0)
|
|
80
|
+
this.bits.pop();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Return `true` if the bit described by `bptr` is set (fast path).
|
|
84
|
+
*/
|
|
85
|
+
hasBit(bptr) {
|
|
86
|
+
return this.hasIndexBitmask(bptr.arrayIndex, bptr.bitmask);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Return `true` if bit `n` is set.
|
|
90
|
+
*
|
|
91
|
+
* @param n - Non-negative integer bit index.
|
|
92
|
+
*/
|
|
93
|
+
has(n) {
|
|
94
|
+
const arrayIndex = Math.floor(n / 32);
|
|
95
|
+
if (arrayIndex >= this.bits.length)
|
|
96
|
+
return false;
|
|
97
|
+
const bitIndex = n % 32;
|
|
98
|
+
const bitmask = 1 << bitIndex;
|
|
99
|
+
return this.hasIndexBitmask(arrayIndex, bitmask);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Return `true` if the given word-level bitmask is fully set at `arrayIndex`.
|
|
103
|
+
*
|
|
104
|
+
* @internal
|
|
105
|
+
*/
|
|
106
|
+
hasIndexBitmask(arrayIndex, bitmask) {
|
|
107
|
+
return (this.bits[arrayIndex] & bitmask) !== 0;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Return `true` if every bit set in `other` is also set in `this` (i.e.
|
|
111
|
+
* `other` is a subset of `this`).
|
|
112
|
+
*
|
|
113
|
+
* Used by the world to test whether an entity's archetype satisfies a
|
|
114
|
+
* system's `HAS` query.
|
|
115
|
+
*/
|
|
116
|
+
hasBitset(other) {
|
|
117
|
+
if (this.bits.length < other.bits.length) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
for (let i = 0; i < other.bits.length; i++) {
|
|
121
|
+
if ((this.bits[i] & other.bits[i]) !== (other.bits[i] || 0)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Iterate over every set bit index in ascending order.
|
|
129
|
+
*
|
|
130
|
+
* @param callback - Called with each set bit index.
|
|
131
|
+
*/
|
|
132
|
+
forEach(callback) {
|
|
133
|
+
this.bits.forEach((b, j) => {
|
|
134
|
+
for (let i = 0; i < 32; i++) {
|
|
135
|
+
if ((b & 1) !== 0) {
|
|
136
|
+
callback(i + j * 32);
|
|
137
|
+
}
|
|
138
|
+
b >>= 1;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Return an array of all set bit indices in ascending order.
|
|
144
|
+
*
|
|
145
|
+
* @returns `number[]` of set bit positions.
|
|
146
|
+
*/
|
|
147
|
+
indices() {
|
|
148
|
+
const idx = [];
|
|
149
|
+
this.forEach((i) => idx.push(i));
|
|
150
|
+
return idx;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* A pre-computed pointer into a {@link Bitset}'s internal word array.
|
|
155
|
+
*
|
|
156
|
+
* Computing `arrayIndex` and `bitmask` from a raw bit index requires a floor
|
|
157
|
+
* division and a bitshift. `BitPtr` caches those values so that hot-path
|
|
158
|
+
* archetype checks ({@link Bitset.hasBit}, {@link Bitset.addBit}) avoid
|
|
159
|
+
* repeating the arithmetic on every entity update.
|
|
160
|
+
*
|
|
161
|
+
* A `BitPtr` is created once per component type and stored on
|
|
162
|
+
* {@link ComponentMeta.bitPtr}.
|
|
163
|
+
*/
|
|
164
|
+
export class BitPtr {
|
|
165
|
+
constructor(
|
|
166
|
+
/** The raw bit index this pointer refers to. */
|
|
167
|
+
value) {
|
|
168
|
+
this.value = value;
|
|
169
|
+
this.arrayIndex = Math.floor(value / 32);
|
|
170
|
+
this.bitmask = 1 << value % 32;
|
|
171
|
+
}
|
|
172
|
+
/** Return `true` if both pointers refer to the same bit position. */
|
|
173
|
+
equals(other) {
|
|
174
|
+
return this.arrayIndex == other.arrayIndex && this.bitmask == other.bitmask;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=bitset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitset.js","sourceRoot":"","sources":["../../src/util/bitset.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The following type declarations define an alternative typings interface for eventemitter3
|
|
3
|
+
* Inspired by typings in @yandeu/events https://github.com/yandeu/events
|
|
4
|
+
* Turns out those typings pretty much can be used directly on eventemitter3
|
|
5
|
+
*/
|
|
6
|
+
declare type ValidEventMap<T = any> = T extends {
|
|
7
|
+
[P in keyof T]: (...args: any[]) => void;
|
|
8
|
+
} ? T : never;
|
|
9
|
+
declare type Handler<T extends any | ((...args: any[]) => R), R = any> = T;
|
|
10
|
+
export declare type EventListener<T extends ValidEventMap, K extends EventNames<T>> = T extends string | symbol ? (...args: any[]) => void : K extends keyof T ? Handler<T[K], void> : never;
|
|
11
|
+
declare type EventArgs<T extends ValidEventMap, K extends EventNames<T>> = Parameters<EventListener<T, K>>;
|
|
12
|
+
export declare type EventNames<T extends ValidEventMap> = T extends string | symbol ? T : keyof T;
|
|
13
|
+
declare class events<EventMap extends ValidEventMap = any> {
|
|
14
|
+
on<T extends EventNames<EventMap>>(event: T, fn: EventListener<EventMap, T>, context?: any): events<EventMap>;
|
|
15
|
+
emit<T extends EventNames<EventMap>>(event: T, ...args: EventArgs<EventMap, T>): boolean;
|
|
16
|
+
once<T extends EventNames<EventMap>>(event: T, fn: EventListener<EventMap, T>, context?: any): events<EventMap>;
|
|
17
|
+
eventNames(): EventNames<EventMap>[];
|
|
18
|
+
listeners(event: EventNames<EventMap>): any[];
|
|
19
|
+
listenerCount(event: EventNames<EventMap>): any;
|
|
20
|
+
removeListener<T extends EventNames<EventMap>>(event: T, fn?: EventListener<EventMap, T>, context?: any, once?: boolean): this;
|
|
21
|
+
removeAllListeners(event?: EventNames<EventMap>): this;
|
|
22
|
+
off<T extends EventNames<EventMap>>(event: T, fn?: EventListener<EventMap, T> | undefined, context?: any, once?: boolean | undefined): events<EventMap>;
|
|
23
|
+
addListener<T extends EventNames<EventMap>>(event: T, fn: EventListener<EventMap, T>, context?: any): events<EventMap>;
|
|
24
|
+
}
|
|
25
|
+
export declare class Events<EventMap extends ValidEventMap = any> extends events<EventMap> {
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The following type declarations define an alternative typings interface for eventemitter3
|
|
3
|
+
* Inspired by typings in @yandeu/events https://github.com/yandeu/events
|
|
4
|
+
* Turns out those typings pretty much can be used directly on eventemitter3
|
|
5
|
+
*/
|
|
6
|
+
import eventEmitter3 from "eventemitter3";
|
|
7
|
+
const { EventEmitter } = eventEmitter3;
|
|
8
|
+
class events {
|
|
9
|
+
on(event, fn, context) {
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
emit(event, ...args) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
once(event, fn, context) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
eventNames() {
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
listeners(event) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
listenerCount(event) {
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
removeListener(event, fn, context, once) {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
removeAllListeners(event) {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
off(event, fn, context, once) {
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
addListener(event, fn, context) {
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
events = EventEmitter;
|
|
41
|
+
export class Events extends events {
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/util/events.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,aAAa,MAAM,eAAe,CAAC;AAC1C,MAAM,EAAE,YAAY,EAAE,GAAG,aAAa,CAAC;AAyBvC,MAAM,MAAM;IACH,EAAE,CACP,KAAQ,EACR,EAA8B,EAC9B,OAAa;QAEb,OAAO,CAAQ,CAAC;IAClB,CAAC;IACM,IAAI,CACT,KAAQ,EACR,GAAG,IAA4B;QAE/B,OAAO,CAAQ,CAAC;IAClB,CAAC;IACM,IAAI,CACT,KAAQ,EACR,EAA8B,EAC9B,OAAa;QAEb,OAAO,CAAQ,CAAC;IAClB,CAAC;IACM,UAAU;QACf,OAAO,CAAQ,CAAC;IAClB,CAAC;IACM,SAAS,CAAC,KAA2B;QAC1C,OAAO,CAAQ,CAAC;IAClB,CAAC;IACM,aAAa,CAAC,KAA2B;QAC9C,OAAO,CAAQ,CAAC;IAClB,CAAC;IACM,cAAc,CACnB,KAAQ,EACR,EAA+B,EAC/B,OAAa,EACb,IAAc;QAEd,OAAO,CAAQ,CAAC;IAClB,CAAC;IACD,kBAAkB,CAAC,KAA4B;QAC7C,OAAO,CAAQ,CAAC;IAClB,CAAC;IACM,GAAG,CACR,KAAQ,EACR,EAA2C,EAC3C,OAAa,EACb,IAA0B;QAE1B,OAAO,CAAQ,CAAC;IAClB,CAAC;IACM,WAAW,CAChB,KAAQ,EACR,EAA8B,EAC9B,OAAa;QAEb,OAAO,CAAQ,CAAC;IAClB,CAAC;CACF;AAEA,MAAc,GAAG,YAAY,CAAC;AAE/B,MAAM,OAAO,MAEX,SAAQ,MAAgB;CAAG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class OrderedSet<T> implements Set<T> {
|
|
2
|
+
private items;
|
|
3
|
+
private readonly compare;
|
|
4
|
+
constructor(compare: (a: T, b: T) => number);
|
|
5
|
+
private bisect;
|
|
6
|
+
add(value: T): this;
|
|
7
|
+
has(value: T): boolean;
|
|
8
|
+
delete(value: T): boolean;
|
|
9
|
+
clear(): void;
|
|
10
|
+
get size(): number;
|
|
11
|
+
forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: unknown): void;
|
|
12
|
+
[Symbol.iterator](): IterableIterator<T>;
|
|
13
|
+
entries(): IterableIterator<[T, T]>;
|
|
14
|
+
keys(): IterableIterator<T>;
|
|
15
|
+
values(): IterableIterator<T>;
|
|
16
|
+
get [Symbol.toStringTag](): string;
|
|
17
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export class OrderedSet {
|
|
2
|
+
constructor(compare) {
|
|
3
|
+
this.items = [];
|
|
4
|
+
this.compare = compare;
|
|
5
|
+
}
|
|
6
|
+
bisect(value) {
|
|
7
|
+
let lo = 0;
|
|
8
|
+
let hi = this.items.length;
|
|
9
|
+
while (lo < hi) {
|
|
10
|
+
const mid = (lo + hi) >>> 1;
|
|
11
|
+
if (this.compare(this.items[mid], value) < 0) {
|
|
12
|
+
lo = mid + 1;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
hi = mid;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return lo;
|
|
19
|
+
}
|
|
20
|
+
add(value) {
|
|
21
|
+
const i = this.bisect(value);
|
|
22
|
+
if (i < this.items.length && this.compare(this.items[i], value) === 0) {
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
this.items.splice(i, 0, value);
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
has(value) {
|
|
29
|
+
const i = this.bisect(value);
|
|
30
|
+
return i < this.items.length && this.compare(this.items[i], value) === 0;
|
|
31
|
+
}
|
|
32
|
+
delete(value) {
|
|
33
|
+
const i = this.bisect(value);
|
|
34
|
+
if (i < this.items.length && this.compare(this.items[i], value) === 0) {
|
|
35
|
+
this.items.splice(i, 1);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
clear() {
|
|
41
|
+
this.items.length = 0;
|
|
42
|
+
}
|
|
43
|
+
get size() {
|
|
44
|
+
return this.items.length;
|
|
45
|
+
}
|
|
46
|
+
forEach(callbackfn, thisArg) {
|
|
47
|
+
for (const item of this.items) {
|
|
48
|
+
callbackfn.call(thisArg, item, item, this);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
[Symbol.iterator]() {
|
|
52
|
+
return this.items[Symbol.iterator]();
|
|
53
|
+
}
|
|
54
|
+
*entries() {
|
|
55
|
+
for (const item of this.items) {
|
|
56
|
+
yield [item, item];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
keys() {
|
|
60
|
+
return this.items[Symbol.iterator]();
|
|
61
|
+
}
|
|
62
|
+
values() {
|
|
63
|
+
return this.items[Symbol.iterator]();
|
|
64
|
+
}
|
|
65
|
+
get [Symbol.toStringTag]() {
|
|
66
|
+
return "OrderedSet";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=ordered_set.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ordered_set.js","sourceRoot":"","sources":["../../src/util/ordered_set.ts"],"names":[],"mappings":"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"}
|
package/dist/world.d.ts
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { Component, ComponentClassOrType, ComponentMeta, Hook } from "./component.js";
|
|
2
|
+
import { Entity } from "./entity.js";
|
|
3
|
+
import { System } from "./system.js";
|
|
4
|
+
import { IPhase } from "./phase.js";
|
|
5
|
+
/**
|
|
6
|
+
* The central ECS container.
|
|
7
|
+
*
|
|
8
|
+
* A `World` owns all entities, components, systems, and the update pipeline.
|
|
9
|
+
* Typical lifecycle:
|
|
10
|
+
*
|
|
11
|
+
* 1. **Register components** — call {@link registerComponent} (and optionally
|
|
12
|
+
* {@link registerComponentType}) for every component class.
|
|
13
|
+
* 2. **Register systems** — call {@link system} (or {@link addSystem}) to
|
|
14
|
+
* create and configure {@link System | systems}.
|
|
15
|
+
* 3. **Start** — call {@link start} to freeze registration and sort systems
|
|
16
|
+
* into their phases.
|
|
17
|
+
* 4. **Run loop** — call {@link runPhase} once per frame for each phase.
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* const world = new World();
|
|
21
|
+
*
|
|
22
|
+
* world.registerComponent(Position);
|
|
23
|
+
* world.registerComponent(Velocity);
|
|
24
|
+
*
|
|
25
|
+
* world.system("Move")
|
|
26
|
+
* .requires(Position, Velocity)
|
|
27
|
+
* .update(Position, (pos) => { pos.x += vel.x; });
|
|
28
|
+
*
|
|
29
|
+
* world.start();
|
|
30
|
+
*
|
|
31
|
+
* // game loop:
|
|
32
|
+
* world.runPhase(updatePhase, Date.now(), 16);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class World {
|
|
36
|
+
private entities;
|
|
37
|
+
private componentNameTypeMap;
|
|
38
|
+
private archChangeQueue;
|
|
39
|
+
private destroyedEntities;
|
|
40
|
+
private pendingSystems;
|
|
41
|
+
private allSystems;
|
|
42
|
+
private Class2Meta;
|
|
43
|
+
private Type2Meta;
|
|
44
|
+
private updatedComponents;
|
|
45
|
+
private localComponentCounter;
|
|
46
|
+
private componentRegistrationDisabled;
|
|
47
|
+
private systemRegistrationDisabled;
|
|
48
|
+
private pipeline;
|
|
49
|
+
private eidCounter;
|
|
50
|
+
constructor();
|
|
51
|
+
/**
|
|
52
|
+
* Return the entity with id `eid`, creating it if it does not yet exist.
|
|
53
|
+
*
|
|
54
|
+
* Used by networking code to materialise server-assigned entities:
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* const e = world.getOrCreateEntity(snapshot.eid, (e) => {
|
|
58
|
+
* networkEntities.add(e);
|
|
59
|
+
* });
|
|
60
|
+
* const c = e.add(snapshot.type, false);
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @param eid - The entity id to look up or create.
|
|
64
|
+
* @param onCreateCallback - Optional callback invoked only when a **new**
|
|
65
|
+
* entity is created, before it is returned. Use this to initialise
|
|
66
|
+
* bookkeeping (e.g. tracking it in a local set).
|
|
67
|
+
* @returns The existing or newly created entity.
|
|
68
|
+
*/
|
|
69
|
+
getOrCreateEntity(eid: number, onCreateCallback?: (e: Entity) => void): Entity;
|
|
70
|
+
/**
|
|
71
|
+
* Look up an entity by id.
|
|
72
|
+
*
|
|
73
|
+
* @param id - Numeric entity id.
|
|
74
|
+
* @returns The entity, or `undefined` if no entity with that id exists.
|
|
75
|
+
*/
|
|
76
|
+
entity(id: number): Entity | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Create a new entity with an auto-assigned id and register it in the world.
|
|
79
|
+
*
|
|
80
|
+
* The id counter starts at 0 (or at the value set by
|
|
81
|
+
* {@link setEntityIdRange}) and increments by one for each call.
|
|
82
|
+
*
|
|
83
|
+
* @returns The new entity.
|
|
84
|
+
*/
|
|
85
|
+
createEntity(): Entity;
|
|
86
|
+
/**
|
|
87
|
+
* Set the starting value for the auto-incrementing entity id counter.
|
|
88
|
+
*
|
|
89
|
+
* Must be called **before** {@link start} (or
|
|
90
|
+
* {@link disableComponentRegistration}). Useful when the world runs alongside
|
|
91
|
+
* a server that owns a different id range — for example, locally-created
|
|
92
|
+
* client entities can start at a high offset to avoid collisions with
|
|
93
|
+
* server-assigned ids.
|
|
94
|
+
*
|
|
95
|
+
* @param min - The first id that will be assigned by {@link createEntity}.
|
|
96
|
+
* @throws If called after registration has been disabled.
|
|
97
|
+
*/
|
|
98
|
+
setEntityIdRange(min: number): void;
|
|
99
|
+
private getComponentInstance;
|
|
100
|
+
/**
|
|
101
|
+
* Retrieve the {@link ComponentMeta} record for a registered component.
|
|
102
|
+
*
|
|
103
|
+
* @param typeOrClass - A component class constructor or a numeric type id.
|
|
104
|
+
* @returns The corresponding `ComponentMeta`.
|
|
105
|
+
* @throws If no component with that class or type id has been registered.
|
|
106
|
+
*/
|
|
107
|
+
getComponentMeta(typeOrClass: ComponentClassOrType): ComponentMeta;
|
|
108
|
+
/**
|
|
109
|
+
* Resolve a component class or type id to its numeric type id.
|
|
110
|
+
*
|
|
111
|
+
* @param typeOrClass - A component class constructor or a numeric type id.
|
|
112
|
+
* @returns The numeric type id.
|
|
113
|
+
*/
|
|
114
|
+
getComponentType(typeOrClass: ComponentClassOrType): number;
|
|
115
|
+
/**
|
|
116
|
+
* Mark an entity's archetype as changed, queuing it for re-evaluation
|
|
117
|
+
* against all system queries at the end of the current system run.
|
|
118
|
+
*
|
|
119
|
+
* Also recursively marks all children as changed so that `{ PARENT: ... }`
|
|
120
|
+
* queries are re-evaluated.
|
|
121
|
+
*
|
|
122
|
+
* @internal Called automatically by {@link Entity.add} and
|
|
123
|
+
* {@link Entity.remove}.
|
|
124
|
+
*/
|
|
125
|
+
archetypeChanged(e: Entity): void;
|
|
126
|
+
/** @internal */
|
|
127
|
+
_notifyComponentAdded(e: Entity, c: Component): void;
|
|
128
|
+
/** @internal */
|
|
129
|
+
_notifyComponentRemoved(e: Entity, c: Component): void;
|
|
130
|
+
/** @internal */
|
|
131
|
+
_notifyEntityDestroyed(e: Entity): void;
|
|
132
|
+
private updateArchetypes;
|
|
133
|
+
/** @internal Queues a component for onSet / update delivery. */
|
|
134
|
+
_queueUpdatedComponent(c: Component): void;
|
|
135
|
+
/**
|
|
136
|
+
* Register a component class with the world.
|
|
137
|
+
*
|
|
138
|
+
* Must be called before any entity can use the component. Registration is
|
|
139
|
+
* disabled once {@link start} is called.
|
|
140
|
+
*
|
|
141
|
+
* **Overloads:**
|
|
142
|
+
* - `registerComponent(Class)` — type id auto-assigned from the name map, or
|
|
143
|
+
* from a local counter (≥ 256) if the name is not yet mapped.
|
|
144
|
+
* - `registerComponent(Class, type)` — explicit numeric type id.
|
|
145
|
+
* - `registerComponent(Class, componentName)` — auto-assigned id, custom
|
|
146
|
+
* display name (useful when the class name differs from the network name).
|
|
147
|
+
* - `registerComponent(Class, type, componentName)` — explicit id + name.
|
|
148
|
+
*
|
|
149
|
+
* @param ComponentClass - The component class to register.
|
|
150
|
+
* @throws If the class has already been registered, or if registration is
|
|
151
|
+
* disabled.
|
|
152
|
+
*/
|
|
153
|
+
registerComponent(ComponentClass: typeof Component): void;
|
|
154
|
+
registerComponent(ComponentClass: typeof Component, type: number): void;
|
|
155
|
+
registerComponent(ComponentClass: typeof Component, componentName?: string): void;
|
|
156
|
+
registerComponent(ComponentClass: typeof Component, type: number, componentName: string): void;
|
|
157
|
+
/**
|
|
158
|
+
* Pre-register a component name → type id mapping without associating a
|
|
159
|
+
* class.
|
|
160
|
+
*
|
|
161
|
+
* Useful when network messages refer to components by type id and the
|
|
162
|
+
* corresponding class may be registered later. Call this before
|
|
163
|
+
* {@link registerComponent} to ensure the class picks up the server-assigned
|
|
164
|
+
* id rather than a locally generated one.
|
|
165
|
+
*
|
|
166
|
+
* @param componentName - The string name used in network payloads.
|
|
167
|
+
* @param type - The numeric type id assigned by the server.
|
|
168
|
+
*/
|
|
169
|
+
registerComponentType(componentName: string, type: number): void;
|
|
170
|
+
/**
|
|
171
|
+
* Register a pre-built {@link System} with the world.
|
|
172
|
+
*
|
|
173
|
+
* In most cases it is more convenient to use {@link system} which both
|
|
174
|
+
* creates and registers in one call. Use `addSystem` when you need to
|
|
175
|
+
* subclass `System` directly.
|
|
176
|
+
*
|
|
177
|
+
* @param s - The system to add.
|
|
178
|
+
* @throws If system registration is disabled (after {@link start}).
|
|
179
|
+
*/
|
|
180
|
+
addSystem(s: System): void;
|
|
181
|
+
/**
|
|
182
|
+
* Create a new {@link System}, register it, and return it for configuration.
|
|
183
|
+
*
|
|
184
|
+
* This is the primary way to define systems:
|
|
185
|
+
*
|
|
186
|
+
* ```ts
|
|
187
|
+
* world.system("Render")
|
|
188
|
+
* .phase("update")
|
|
189
|
+
* .requires(Position, Sprite)
|
|
190
|
+
* .enter([Sprite], (e, [sprite]) => sprite.initialize(scene))
|
|
191
|
+
* .update(Position, (pos) => { ... });
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @param name - A unique display name for the system.
|
|
195
|
+
* @returns The new `System` instance.
|
|
196
|
+
*/
|
|
197
|
+
system(name: string): System<[]>;
|
|
198
|
+
/**
|
|
199
|
+
* Prevent any further calls to {@link registerComponent}.
|
|
200
|
+
*
|
|
201
|
+
* Called automatically by {@link start}. Can be called early if you want to
|
|
202
|
+
* lock component registration before systems are fully configured.
|
|
203
|
+
*/
|
|
204
|
+
disableComponentRegistration(): void;
|
|
205
|
+
/**
|
|
206
|
+
* Freeze registration and prepare the world for running.
|
|
207
|
+
*
|
|
208
|
+
* Disables both component and system registration, then distributes all
|
|
209
|
+
* pending systems into their assigned pipeline phases (defaulting to
|
|
210
|
+
* `"update"`). Logs the resulting phase → system order to the console.
|
|
211
|
+
*
|
|
212
|
+
* Call this once, after all components and systems are registered but before
|
|
213
|
+
* the first {@link runPhase} call.
|
|
214
|
+
*/
|
|
215
|
+
start(): void;
|
|
216
|
+
private reindexSystems;
|
|
217
|
+
/**
|
|
218
|
+
* Return the {@link Hook} for a component class.
|
|
219
|
+
*
|
|
220
|
+
* Hooks let you react to component lifecycle events (add / remove / set)
|
|
221
|
+
* without building a full {@link System}. The hook is backed by the
|
|
222
|
+
* component's {@link ComponentMeta} and the same object is returned on every
|
|
223
|
+
* call.
|
|
224
|
+
*
|
|
225
|
+
* ```ts
|
|
226
|
+
* world.hook(Sprite)
|
|
227
|
+
* .onAdd(c => c.initialize(scene))
|
|
228
|
+
* .onRemove(c => c.destroy());
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* @param C - The component class.
|
|
232
|
+
* @returns The `Hook` for that component type.
|
|
233
|
+
*/
|
|
234
|
+
hook<T extends typeof Component>(C: T): Hook<InstanceType<T>>;
|
|
235
|
+
/**
|
|
236
|
+
* Add a named phase to the update pipeline and return it.
|
|
237
|
+
*
|
|
238
|
+
* Phases are executed in insertion order when you call {@link runPhase} for
|
|
239
|
+
* each one. Systems are assigned to a phase via {@link System.phase}.
|
|
240
|
+
*
|
|
241
|
+
* ```ts
|
|
242
|
+
* const preUpdate = world.addPhase("preupdate");
|
|
243
|
+
* const update = world.addPhase("update");
|
|
244
|
+
* const send = world.addPhase("send");
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* @param name - Unique phase name. Systems can reference it by this string.
|
|
248
|
+
* @returns The new {@link IPhase}.
|
|
249
|
+
*/
|
|
250
|
+
addPhase(name: string): IPhase;
|
|
251
|
+
/**
|
|
252
|
+
* Execute all systems in the given phase for one tick.
|
|
253
|
+
*
|
|
254
|
+
* After each system runs, pending archetype changes (entity add/remove
|
|
255
|
+
* component events) are flushed so that `enter` / `exit` callbacks are
|
|
256
|
+
* delivered before the next system in the same phase executes.
|
|
257
|
+
*
|
|
258
|
+
* @param phase - The {@link IPhase} to run (returned by {@link addPhase}).
|
|
259
|
+
* @param now - Absolute timestamp in milliseconds (e.g. `Date.now()`).
|
|
260
|
+
* @param delta - Milliseconds elapsed since the previous tick.
|
|
261
|
+
*/
|
|
262
|
+
runPhase(phase: IPhase, now: number, delta: number): void;
|
|
263
|
+
/**
|
|
264
|
+
* Run every phase in the pipeline in insertion order (the order phases were
|
|
265
|
+
* registered via {@link addPhase}). Equivalent to calling
|
|
266
|
+
* {@link runPhase} for each phase manually.
|
|
267
|
+
*
|
|
268
|
+
* @param now - Absolute timestamp in milliseconds (e.g. `Date.now()`).
|
|
269
|
+
* @param delta - Milliseconds elapsed since the previous tick.
|
|
270
|
+
*/
|
|
271
|
+
progress(now: number, delta: number): void;
|
|
272
|
+
/**
|
|
273
|
+
* Destroy every entity currently tracked by the world.
|
|
274
|
+
*
|
|
275
|
+
* Triggers all `onRemove` hooks and `exit` callbacks. Useful when
|
|
276
|
+
* transitioning between game sessions or resetting to a clean state.
|
|
277
|
+
*/
|
|
278
|
+
clearAllEntities(): void;
|
|
279
|
+
}
|