archetype-ecs-lib 0.4.1 → 0.5.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/README.md +9 -176
- package/lib/ecs/Archetype.d.ts +1 -1
- package/lib/ecs/Commands.d.ts +8 -3
- package/lib/ecs/Commands.js +112 -2
- package/lib/ecs/EntityManager.d.ts +1 -1
- package/lib/ecs/Events.d.ts +23 -0
- package/lib/ecs/Events.js +76 -0
- package/lib/ecs/Schedule.d.ts +2 -2
- package/lib/ecs/Schedule.js +15 -2
- package/lib/ecs/Signature.d.ts +1 -1
- package/lib/ecs/TypeRegistry.d.ts +1 -1
- package/lib/ecs/Types.d.ts +131 -3
- package/lib/ecs/World.d.ts +35 -4
- package/lib/ecs/World.js +290 -83
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/package.json +15 -3
package/lib/ecs/Types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventChannel } from "./Events";
|
|
1
2
|
export type EntityId = number;
|
|
2
3
|
export type Entity = Readonly<{
|
|
3
4
|
id: EntityId;
|
|
@@ -12,13 +13,140 @@ export type EntityMeta = {
|
|
|
12
13
|
export type Column<T = unknown> = T[];
|
|
13
14
|
export type Signature = ReadonlyArray<TypeId>;
|
|
14
15
|
export type ComponentCtor<T> = new (...args: any[]) => T;
|
|
16
|
+
export type ComponentCtorBundleItem<T = any> = readonly [ComponentCtor<T>, T];
|
|
15
17
|
/**
|
|
16
18
|
* Internal numeric id for a component "type".
|
|
17
19
|
* (We keep it numeric so signatures can be sorted quickly.)
|
|
18
20
|
*/
|
|
19
21
|
export type TypeId = number;
|
|
20
|
-
export type SystemFn = (world:
|
|
21
|
-
/**
|
|
22
|
-
|
|
22
|
+
export type SystemFn = (world: WorldApi, dt: number) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Commands API exposed to systems.
|
|
25
|
+
* > Hides internal stuff like `drain()`
|
|
26
|
+
*/
|
|
27
|
+
export interface CommandsApi {
|
|
28
|
+
spawn(init?: (e: Entity) => void): void;
|
|
29
|
+
spawnBundle(...items: ComponentCtorBundleItem[]): void;
|
|
30
|
+
despawn(e: Entity): void;
|
|
31
|
+
despawnBundle(entities: Entity[]): void;
|
|
32
|
+
add<T>(e: Entity, ctor: ComponentCtor<T>, value: T): void;
|
|
33
|
+
addBundle(e: Entity, ...items: ComponentCtorBundleItem[]): void;
|
|
34
|
+
remove<T>(e: Entity, ctor: ComponentCtor<T>): void;
|
|
35
|
+
removeBundle(e: Entity, ...ctors: ComponentCtor<any>[]): void;
|
|
36
|
+
hasPending(): boolean;
|
|
37
|
+
}
|
|
38
|
+
export type QueryRow1<A> = {
|
|
39
|
+
e: Entity;
|
|
40
|
+
c1: A;
|
|
41
|
+
};
|
|
42
|
+
export type QueryRow2<A, B> = {
|
|
43
|
+
e: Entity;
|
|
44
|
+
c1: A;
|
|
45
|
+
c2: B;
|
|
46
|
+
};
|
|
47
|
+
export type QueryRow3<A, B, C> = {
|
|
48
|
+
e: Entity;
|
|
49
|
+
c1: A;
|
|
50
|
+
c2: B;
|
|
51
|
+
c3: C;
|
|
52
|
+
};
|
|
53
|
+
export type QueryRow4<A, B, C, D> = {
|
|
54
|
+
e: Entity;
|
|
55
|
+
c1: A;
|
|
56
|
+
c2: B;
|
|
57
|
+
c3: C;
|
|
58
|
+
c4: D;
|
|
59
|
+
};
|
|
60
|
+
export type QueryRow5<A, B, C, D, E> = {
|
|
61
|
+
e: Entity;
|
|
62
|
+
c1: A;
|
|
63
|
+
c2: B;
|
|
64
|
+
c3: C;
|
|
65
|
+
c4: D;
|
|
66
|
+
c5: E;
|
|
67
|
+
};
|
|
68
|
+
export type QueryRow6<A, B, C, D, E, F> = {
|
|
69
|
+
e: Entity;
|
|
70
|
+
c1: A;
|
|
71
|
+
c2: B;
|
|
72
|
+
c3: C;
|
|
73
|
+
c4: D;
|
|
74
|
+
c5: E;
|
|
75
|
+
c6: F;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Public World API visible from system functions.
|
|
79
|
+
* Structural typing keeps typings fast and avoids generic plumbing across the whole library.
|
|
80
|
+
*/
|
|
81
|
+
export interface WorldApi {
|
|
82
|
+
cmd(): CommandsApi;
|
|
23
83
|
flush(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Insert or replace a resource (singleton) stored on the World, keyed by ctor.
|
|
86
|
+
* This is NOT a structural change (safe during iteration).
|
|
87
|
+
*/
|
|
88
|
+
setResource<T>(key: ComponentCtor<T>, value: T): void;
|
|
89
|
+
/**
|
|
90
|
+
* Returns the resource value if present, otherwise `undefined`.
|
|
91
|
+
* Use this for optional resources (debug tools, plugins, editor-only state, etc.).
|
|
92
|
+
*
|
|
93
|
+
* Note: if you explicitly stored `undefined` as a resource value, this also returns `undefined`.
|
|
94
|
+
* Use `hasResource()` to distinguish "missing" vs "present but undefined".
|
|
95
|
+
*/
|
|
96
|
+
getResource<T>(key: ComponentCtor<T>): T | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Returns the resource value if present, otherwise throws.
|
|
99
|
+
* Use this for required resources (Time, Input, AssetCache, Config...) to keep systems clean.
|
|
100
|
+
*
|
|
101
|
+
* The check is based on `hasResource(key)` so "missing" is unambiguous even if the stored value is `undefined`.
|
|
102
|
+
*/
|
|
103
|
+
requireResource<T>(key: ComponentCtor<T>): T;
|
|
104
|
+
hasResource<T>(key: ComponentCtor<T>): boolean;
|
|
105
|
+
removeResource<T>(key: ComponentCtor<T>): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Insert once, returning the existing value if already present.
|
|
108
|
+
* Great for bootstrapping defaults without double-initializing.
|
|
109
|
+
*/
|
|
110
|
+
initResource<T>(key: ComponentCtor<T>, factory: () => T): T;
|
|
111
|
+
/** Emit an event into the current phase (write buffer). */
|
|
112
|
+
emit<T>(key: ComponentCtor<T>, ev: T): void;
|
|
113
|
+
/**
|
|
114
|
+
* Get the channel for an event type (created on first use).
|
|
115
|
+
* - readable events are from the previous phase
|
|
116
|
+
* - emitted events go to the current phase
|
|
117
|
+
*/
|
|
118
|
+
events<T>(key: ComponentCtor<T>): EventChannel<T>;
|
|
119
|
+
/**
|
|
120
|
+
* Drain readable events for this type (previous phase), calling fn for each.
|
|
121
|
+
* If the channel doesn't exist yet, this is a no-op.
|
|
122
|
+
*/
|
|
123
|
+
drainEvents<T>(key: ComponentCtor<T>, fn: (ev: T) => void): void;
|
|
124
|
+
/**
|
|
125
|
+
* Clears readable events for a type (or all types if omitted).
|
|
126
|
+
* Does not affect entity structure.
|
|
127
|
+
*/
|
|
128
|
+
clearEvents<T>(key?: ComponentCtor<T>): void;
|
|
129
|
+
/**
|
|
130
|
+
* @internal Called by Schedule at phase boundaries to deliver events to the next phase.
|
|
131
|
+
*/
|
|
132
|
+
swapEvents(): void;
|
|
133
|
+
spawn(): Entity;
|
|
134
|
+
spawnMany(...items: ComponentCtorBundleItem[]): void;
|
|
135
|
+
despawn(e: Entity): void;
|
|
136
|
+
despawnMany(entities: Entity[]): void;
|
|
137
|
+
isAlive(e: Entity): boolean;
|
|
138
|
+
add<T>(e: Entity, ctor: ComponentCtor<T>, value: T): void;
|
|
139
|
+
addMany(e: Entity, ...items: ComponentCtorBundleItem[]): void;
|
|
140
|
+
remove<T>(e: Entity, ctor: ComponentCtor<T>): void;
|
|
141
|
+
removeMany(e: Entity, ...ctors: ComponentCtor<any>[]): void;
|
|
142
|
+
has<T>(e: Entity, ctor: ComponentCtor<T>): boolean;
|
|
143
|
+
get<T>(e: Entity, ctor: ComponentCtor<T>): T | undefined;
|
|
144
|
+
set<T>(e: Entity, ctor: ComponentCtor<T>, value: T): void;
|
|
145
|
+
query<A>(c1: ComponentCtor<A>): Iterable<QueryRow1<A>>;
|
|
146
|
+
query<A, B>(c1: ComponentCtor<A>, c2: ComponentCtor<B>): Iterable<QueryRow2<A, B>>;
|
|
147
|
+
query<A, B, C>(c1: ComponentCtor<A>, c2: ComponentCtor<B>, c3: ComponentCtor<C>): Iterable<QueryRow3<A, B, C>>;
|
|
148
|
+
query<A, B, C, D>(c1: ComponentCtor<A>, c2: ComponentCtor<B>, c3: ComponentCtor<C>, c4: ComponentCtor<D>): Iterable<QueryRow4<A, B, C, D>>;
|
|
149
|
+
query<A, B, C, D, E>(c1: ComponentCtor<A>, c2: ComponentCtor<B>, c3: ComponentCtor<C>, c4: ComponentCtor<D>, c5: ComponentCtor<E>): Iterable<QueryRow5<A, B, C, D, E>>;
|
|
150
|
+
query<A, B, C, D, E, F>(c1: ComponentCtor<A>, c2: ComponentCtor<B>, c3: ComponentCtor<C>, c4: ComponentCtor<D>, c5: ComponentCtor<E>, c6: ComponentCtor<F>): Iterable<QueryRow6<A, B, C, D, E, F>>;
|
|
151
|
+
query(...ctors: ComponentCtor<any>[]): Iterable<any>;
|
|
24
152
|
}
|
package/lib/ecs/World.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { Commands } from "./Commands";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { EventChannel } from "./Events";
|
|
3
|
+
import type { ComponentCtor, ComponentCtorBundleItem, Entity, QueryRow1, QueryRow2, QueryRow3, QueryRow4, QueryRow5, QueryRow6, SystemFn, WorldApi } from "./Types";
|
|
4
|
+
export declare class World implements WorldApi {
|
|
4
5
|
private readonly entities;
|
|
5
6
|
private readonly archetypes;
|
|
6
7
|
private readonly archByKey;
|
|
7
8
|
private readonly systems;
|
|
8
9
|
private readonly commands;
|
|
9
|
-
private
|
|
10
|
+
private _iterateDepth;
|
|
11
|
+
private readonly resources;
|
|
12
|
+
private readonly eventChannels;
|
|
10
13
|
constructor();
|
|
11
14
|
/** Queue structural changes to apply safely after systems run. */
|
|
12
15
|
cmd(): Commands;
|
|
@@ -18,19 +21,40 @@ export declare class World implements WorldI {
|
|
|
18
21
|
*/
|
|
19
22
|
update(dt: number): void;
|
|
20
23
|
flush(): void;
|
|
24
|
+
setResource<T>(key: ComponentCtor<T>, value: T): void;
|
|
25
|
+
getResource<T>(key: ComponentCtor<T>): T | undefined;
|
|
26
|
+
requireResource<T>(key: ComponentCtor<T>): T;
|
|
27
|
+
hasResource<T>(key: ComponentCtor<T>): boolean;
|
|
28
|
+
removeResource<T>(key: ComponentCtor<T>): boolean;
|
|
29
|
+
initResource<T>(key: ComponentCtor<T>, factory: () => T): T;
|
|
30
|
+
emit<T>(key: ComponentCtor<T>, ev: T): void;
|
|
31
|
+
events<T>(key: ComponentCtor<T>): EventChannel<T>;
|
|
32
|
+
drainEvents<T>(key: ComponentCtor<T>, fn: (ev: T) => void): void;
|
|
33
|
+
clearEvents<T>(key?: ComponentCtor<T>): void;
|
|
34
|
+
/** @internal Called by Schedule at phase boundaries */
|
|
35
|
+
swapEvents(): void;
|
|
21
36
|
spawn(): Entity;
|
|
37
|
+
spawnMany(...items: ComponentCtorBundleItem[]): Entity;
|
|
22
38
|
isAlive(e: Entity): boolean;
|
|
23
39
|
despawn(e: Entity): void;
|
|
40
|
+
despawnMany(entities: Entity[]): void;
|
|
24
41
|
has<T>(e: Entity, ctor: ComponentCtor<T>): boolean;
|
|
25
42
|
get<T>(e: Entity, ctor: ComponentCtor<T>): T | undefined;
|
|
26
43
|
set<T>(e: Entity, ctor: ComponentCtor<T>, value: T): void;
|
|
27
44
|
add<T>(e: Entity, ctor: ComponentCtor<T>, value: T): void;
|
|
45
|
+
addMany(e: Entity, ...items: ComponentCtorBundleItem[]): void;
|
|
28
46
|
remove<T>(e: Entity, ctor: ComponentCtor<T>): void;
|
|
47
|
+
removeMany(e: Entity, ...ctors: ComponentCtor<any>[]): void;
|
|
29
48
|
/**
|
|
30
49
|
* Query all entities having all required component types.
|
|
31
50
|
* Iterates archetypes (tables) and yields SoA columns for cache-friendly loops.
|
|
32
51
|
*/
|
|
33
|
-
query(
|
|
52
|
+
query<A>(c1: ComponentCtor<A>): Iterable<QueryRow1<A>>;
|
|
53
|
+
query<A, B>(c1: ComponentCtor<A>, c2: ComponentCtor<B>): Iterable<QueryRow2<A, B>>;
|
|
54
|
+
query<A, B, C>(c1: ComponentCtor<A>, c2: ComponentCtor<B>, c3: ComponentCtor<C>): Iterable<QueryRow3<A, B, C>>;
|
|
55
|
+
query<A, B, C, D>(c1: ComponentCtor<A>, c2: ComponentCtor<B>, c3: ComponentCtor<C>, c4: ComponentCtor<D>): Iterable<QueryRow4<A, B, C, D>>;
|
|
56
|
+
query<A, B, C, D, E>(c1: ComponentCtor<A>, c2: ComponentCtor<B>, c3: ComponentCtor<C>, c4: ComponentCtor<D>, c5: ComponentCtor<E>): Iterable<QueryRow5<A, B, C, D, E>>;
|
|
57
|
+
query<A, B, C, D, E, F>(c1: ComponentCtor<A>, c2: ComponentCtor<B>, c3: ComponentCtor<C>, c4: ComponentCtor<D>, c5: ComponentCtor<E>, c6: ComponentCtor<F>): Iterable<QueryRow6<A, B, C, D, E, F>>;
|
|
34
58
|
private _ensureNotIterating;
|
|
35
59
|
private _getOrCreateArchetype;
|
|
36
60
|
private _removeFromArchetype;
|
|
@@ -40,4 +64,11 @@ export declare class World implements WorldI {
|
|
|
40
64
|
*/
|
|
41
65
|
private _moveEntity;
|
|
42
66
|
private _apply;
|
|
67
|
+
private _formatEntity;
|
|
68
|
+
private _formatCtor;
|
|
69
|
+
/**
|
|
70
|
+
* Throws an error if the entity is not alive
|
|
71
|
+
*/
|
|
72
|
+
private _assertAlive;
|
|
73
|
+
private _events;
|
|
43
74
|
}
|