@latticexyz/recs 2.0.12-main-d7526607 → 2.0.12-main-96e7bf43
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/package.json +6 -13
- package/CHANGELOG.md +0 -1248
- package/src/Component.spec.ts +0 -275
- package/src/Component.ts +0 -531
- package/src/Entity.spec.ts +0 -45
- package/src/Entity.ts +0 -46
- package/src/Indexer.spec.ts +0 -288
- package/src/Indexer.ts +0 -71
- package/src/Performance.spec.ts +0 -153
- package/src/Query.spec.ts +0 -811
- package/src/Query.ts +0 -554
- package/src/System.spec.ts +0 -139
- package/src/System.ts +0 -150
- package/src/World.spec.ts +0 -79
- package/src/World.ts +0 -102
- package/src/constants.ts +0 -54
- package/src/deprecated/constants.ts +0 -9
- package/src/deprecated/createActionSystem.spec.ts +0 -501
- package/src/deprecated/createActionSystem.ts +0 -236
- package/src/deprecated/defineActionComponent.ts +0 -18
- package/src/deprecated/index.ts +0 -2
- package/src/deprecated/types.ts +0 -45
- package/src/deprecated/waitForActionCompletion.ts +0 -15
- package/src/deprecated/waitForComponentValueIn.ts +0 -38
- package/src/index.ts +0 -9
- package/src/types.ts +0 -260
- package/src/utils.ts +0 -68
package/src/System.ts
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
import { concat, EMPTY, from, Observable } from "rxjs";
|
2
|
-
import { getComponentEntities, removeComponent, setComponent } from "./Component";
|
3
|
-
import { UpdateType } from "./constants";
|
4
|
-
import { defineEnterQuery, defineExitQuery, defineQuery, defineUpdateQuery } from "./Query";
|
5
|
-
import { Component, ComponentUpdate, ComponentValue, Entity, QueryFragment, Schema, World } from "./types";
|
6
|
-
import { toUpdateStream } from "./utils";
|
7
|
-
|
8
|
-
/**
|
9
|
-
* Create a system that is called on every update of the given observable.
|
10
|
-
*
|
11
|
-
* @remarks
|
12
|
-
* Advantage of using this function over directly subscribing to the RxJS observable is that the system is registered in the `world` and
|
13
|
-
* disposed when the `world` is disposed (eg. during a hot reload in development).
|
14
|
-
*
|
15
|
-
* @param world {@link World} object this system should be registered in.
|
16
|
-
* @param observable$ Observable to react to.
|
17
|
-
* @param system System function to run on updates of the `observable$`. System function gets passed the update events from the `observable$`.
|
18
|
-
*/
|
19
|
-
export function defineRxSystem<T>(world: World, observable$: Observable<T>, system: (event: T) => void) {
|
20
|
-
const subscription = observable$.subscribe(system);
|
21
|
-
world.registerDisposer(() => subscription?.unsubscribe());
|
22
|
-
}
|
23
|
-
|
24
|
-
/**
|
25
|
-
* Create a system that is called on every event of the given {@link defineUpdateQuery update query}.
|
26
|
-
*
|
27
|
-
* @param world {@link World} object this system should be registered in.
|
28
|
-
* @param query Update query to react to.
|
29
|
-
* @param system System function to run when the result of the given update query changes.
|
30
|
-
* @param options Optional: {
|
31
|
-
* runOnInit: if true, run this system for all entities matching the query when the system is created.
|
32
|
-
* Else only run on updates after the system is created. Default true.
|
33
|
-
* }
|
34
|
-
*/
|
35
|
-
export function defineUpdateSystem(
|
36
|
-
world: World,
|
37
|
-
query: QueryFragment[],
|
38
|
-
system: (update: ComponentUpdate) => void,
|
39
|
-
options: { runOnInit?: boolean } = { runOnInit: true },
|
40
|
-
) {
|
41
|
-
defineRxSystem(world, defineUpdateQuery(query, options), system);
|
42
|
-
}
|
43
|
-
|
44
|
-
/**
|
45
|
-
* Create a system that is called on every event of the given {@link defineEnterQuery enter query}.
|
46
|
-
*
|
47
|
-
* @param world {@link World} object this system should be registered in.
|
48
|
-
* @param query Enter query to react to.
|
49
|
-
* @param system System function to run when the result of the given enter query changes.
|
50
|
-
* @param options Optional: {
|
51
|
-
* runOnInit: if true, run this system for all entities matching the query when the system is created.
|
52
|
-
* Else only run on updates after the system is created. Default true.
|
53
|
-
* }
|
54
|
-
*/
|
55
|
-
export function defineEnterSystem(
|
56
|
-
world: World,
|
57
|
-
query: QueryFragment[],
|
58
|
-
system: (update: ComponentUpdate) => void,
|
59
|
-
options: { runOnInit?: boolean } = { runOnInit: true },
|
60
|
-
) {
|
61
|
-
defineRxSystem(world, defineEnterQuery(query, options), system);
|
62
|
-
}
|
63
|
-
|
64
|
-
/**
|
65
|
-
* Create a system that is called on every event of the given {@link defineExitQuery exit query}.
|
66
|
-
*
|
67
|
-
* @param world {@link World} object this system should be registered in.
|
68
|
-
* @param query Exit query to react to.
|
69
|
-
* @param system System function to run when the result of the given exit query changes.
|
70
|
-
* @param options Optional: {
|
71
|
-
* runOnInit: if true, run this system for all entities matching the query when the system is created.
|
72
|
-
* Else only run on updates after the system is created. Default true.
|
73
|
-
* }
|
74
|
-
*/
|
75
|
-
export function defineExitSystem(
|
76
|
-
world: World,
|
77
|
-
query: QueryFragment[],
|
78
|
-
system: (update: ComponentUpdate) => void,
|
79
|
-
options: { runOnInit?: boolean } = { runOnInit: true },
|
80
|
-
) {
|
81
|
-
defineRxSystem(world, defineExitQuery(query, options), system);
|
82
|
-
}
|
83
|
-
|
84
|
-
/**
|
85
|
-
* Create a system that is called on every event of the given {@link defineQuery query}.
|
86
|
-
*
|
87
|
-
* @param world {@link World} object this system should be registered in.
|
88
|
-
* @param query Query to react to.
|
89
|
-
* @param system System function to run when the result of the given query changes.
|
90
|
-
* @param options Optional: {
|
91
|
-
* runOnInit: if true, run this system for all entities matching the query when the system is created.
|
92
|
-
* Else only run on updates after the system is created. Default true.
|
93
|
-
* }
|
94
|
-
*/
|
95
|
-
export function defineSystem(
|
96
|
-
world: World,
|
97
|
-
query: QueryFragment[],
|
98
|
-
system: (update: ComponentUpdate & { type: UpdateType }) => void,
|
99
|
-
options: { runOnInit?: boolean } = { runOnInit: true },
|
100
|
-
) {
|
101
|
-
defineRxSystem(world, defineQuery(query, options).update$, system);
|
102
|
-
}
|
103
|
-
|
104
|
-
/**
|
105
|
-
* Create a system that is called every time the given component is updated.
|
106
|
-
*
|
107
|
-
* @param world {@link World} object this system should be registered in.
|
108
|
-
* @param component Component to whose updates to react.
|
109
|
-
* @param system System function to run when the given component is updated.
|
110
|
-
* @param options Optional: {
|
111
|
-
* runOnInit: if true, run this system for all entities in the component when the system is created.
|
112
|
-
* Else only run on updates after the system is created. Default true.
|
113
|
-
* }
|
114
|
-
*/
|
115
|
-
export function defineComponentSystem<S extends Schema>(
|
116
|
-
world: World,
|
117
|
-
component: Component<S>,
|
118
|
-
system: (update: ComponentUpdate<S>) => void,
|
119
|
-
options: { runOnInit?: boolean } = { runOnInit: true },
|
120
|
-
) {
|
121
|
-
const initial$ = options?.runOnInit ? from(getComponentEntities(component)).pipe(toUpdateStream(component)) : EMPTY;
|
122
|
-
defineRxSystem(world, concat(initial$, component.update$), system);
|
123
|
-
}
|
124
|
-
|
125
|
-
/**
|
126
|
-
* Create a system to synchronize updates to one component with another component.
|
127
|
-
*
|
128
|
-
* @param world {@link World} object this system should be registered in.
|
129
|
-
* @param query Result of `component` is added to all entites matching this query.
|
130
|
-
* @param component Function returning the component to be added to all entities matching the given query.
|
131
|
-
* @param value Function returning the component value to be added to all entities matching the given query.
|
132
|
-
*/
|
133
|
-
export function defineSyncSystem<T extends Schema>(
|
134
|
-
world: World,
|
135
|
-
query: QueryFragment[],
|
136
|
-
component: (entity: Entity) => Component<T>,
|
137
|
-
value: (entity: Entity) => ComponentValue<T>,
|
138
|
-
options: { update?: boolean; runOnInit?: boolean } = { update: false, runOnInit: true },
|
139
|
-
) {
|
140
|
-
defineSystem(
|
141
|
-
world,
|
142
|
-
query,
|
143
|
-
({ entity, type }) => {
|
144
|
-
if (type === UpdateType.Enter) setComponent(component(entity), entity, value(entity));
|
145
|
-
if (type === UpdateType.Exit) removeComponent(component(entity), entity);
|
146
|
-
if (options?.update && type === UpdateType.Update) setComponent(component(entity), entity, value(entity));
|
147
|
-
},
|
148
|
-
options,
|
149
|
-
);
|
150
|
-
}
|
package/src/World.spec.ts
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
import { arrayToIterator } from "@latticexyz/utils";
|
2
|
-
import { Subject } from "rxjs";
|
3
|
-
import { defineComponent, setComponent } from "./Component";
|
4
|
-
import { Type } from "./constants";
|
5
|
-
import { createEntity } from "./Entity";
|
6
|
-
import { World, AnyComponent, EntitySymbol } from "./types";
|
7
|
-
import { createWorld, getEntityComponents } from "./World";
|
8
|
-
|
9
|
-
describe("World", () => {
|
10
|
-
describe("createWorld", () => {
|
11
|
-
let world: World;
|
12
|
-
|
13
|
-
beforeEach(() => {
|
14
|
-
world = createWorld();
|
15
|
-
});
|
16
|
-
|
17
|
-
describe("registerEntity", () => {
|
18
|
-
it("should add the entitiy to the world's entities", () => {
|
19
|
-
expect([...world.getEntities()].length).toBe(0);
|
20
|
-
|
21
|
-
world.registerEntity();
|
22
|
-
expect([...world.getEntities()].length).toBe(1);
|
23
|
-
expect([...world.getEntities()][0]).not.toBe(undefined);
|
24
|
-
});
|
25
|
-
});
|
26
|
-
|
27
|
-
describe("registerComponent", () => {
|
28
|
-
let rawComponent: AnyComponent;
|
29
|
-
|
30
|
-
beforeEach(() => {
|
31
|
-
rawComponent = {
|
32
|
-
id: "some-id",
|
33
|
-
values: {
|
34
|
-
value: new Map<EntitySymbol, number>(),
|
35
|
-
},
|
36
|
-
update$: new Subject(),
|
37
|
-
schema: { value: Type.Number },
|
38
|
-
metadata: {},
|
39
|
-
entities: () => arrayToIterator([]),
|
40
|
-
world,
|
41
|
-
};
|
42
|
-
});
|
43
|
-
|
44
|
-
it("should add the component to the world's components", () => {
|
45
|
-
expect(world.components.length).toBe(0);
|
46
|
-
world.registerComponent(rawComponent);
|
47
|
-
expect(world.components.length).toBe(1);
|
48
|
-
expect(world.components.includes(rawComponent)).toBe(true);
|
49
|
-
});
|
50
|
-
|
51
|
-
describe("getEntitiyComponents", () => {
|
52
|
-
it("should return the set of components of a given entity", () => {
|
53
|
-
const components = new Set<AnyComponent>([
|
54
|
-
defineComponent(world, { value: Type.Number }),
|
55
|
-
defineComponent(world, { value: Type.Number }),
|
56
|
-
defineComponent(world, { value: Type.Number }),
|
57
|
-
]);
|
58
|
-
const entity = createEntity(world);
|
59
|
-
const value = 1;
|
60
|
-
|
61
|
-
for (const component of components) {
|
62
|
-
setComponent(component, entity, { value });
|
63
|
-
}
|
64
|
-
|
65
|
-
const received = getEntityComponents(world, entity);
|
66
|
-
expect(received.length).toEqual(components.size);
|
67
|
-
|
68
|
-
for (const comp of received) {
|
69
|
-
expect(components.has(comp)).toBe(true);
|
70
|
-
}
|
71
|
-
|
72
|
-
for (const comp of components) {
|
73
|
-
expect(received.includes(comp)).toBe(true);
|
74
|
-
}
|
75
|
-
});
|
76
|
-
});
|
77
|
-
});
|
78
|
-
});
|
79
|
-
});
|
package/src/World.ts
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
import { transformIterator } from "@latticexyz/utils";
|
2
|
-
import { hasComponent, removeComponent } from "./Component";
|
3
|
-
import { getEntityString, getEntitySymbol } from "./Entity";
|
4
|
-
import { Component, Entity, EntitySymbol, World } from "./types";
|
5
|
-
|
6
|
-
/**
|
7
|
-
* Create a new World.
|
8
|
-
*
|
9
|
-
* @remarks
|
10
|
-
* A World is the central object of an ECS application, where all {@link defineComponent Components},
|
11
|
-
* {@link registerEntity Entities} and {@link defineSystem Systems} are registerd.
|
12
|
-
*
|
13
|
-
* @returns A new World
|
14
|
-
*/
|
15
|
-
export function createWorld() {
|
16
|
-
const entitySymbols = new Set<EntitySymbol>();
|
17
|
-
const components: Component[] = [];
|
18
|
-
let disposers: [string, () => void][] = [];
|
19
|
-
|
20
|
-
function registerEntity({ id, idSuffix }: { id?: string; idSuffix?: string } = {}) {
|
21
|
-
const entity = (id || entitySymbols.size + (idSuffix ? "-" + idSuffix : "")) as Entity;
|
22
|
-
const entitySymbol = getEntitySymbol(entity);
|
23
|
-
|
24
|
-
// Register entity
|
25
|
-
entitySymbols.add(entitySymbol);
|
26
|
-
|
27
|
-
return entity;
|
28
|
-
}
|
29
|
-
|
30
|
-
function getEntities() {
|
31
|
-
return transformIterator(entitySymbols.values(), getEntityString);
|
32
|
-
}
|
33
|
-
|
34
|
-
function registerComponent(component: Component) {
|
35
|
-
components.push(component);
|
36
|
-
}
|
37
|
-
|
38
|
-
function dispose(namespace?: string) {
|
39
|
-
for (const [, disposer] of disposers.filter((d) => !namespace || d[0] === namespace)) {
|
40
|
-
disposer();
|
41
|
-
}
|
42
|
-
disposers = disposers.filter((d) => namespace && d[0] !== namespace);
|
43
|
-
}
|
44
|
-
|
45
|
-
function registerDisposer(disposer: () => void, namespace = "") {
|
46
|
-
disposers.push([namespace, disposer]);
|
47
|
-
}
|
48
|
-
|
49
|
-
function hasEntity(entity: Entity): boolean {
|
50
|
-
const entitySymbol = getEntitySymbol(entity);
|
51
|
-
return entitySymbols.has(entitySymbol);
|
52
|
-
}
|
53
|
-
|
54
|
-
function deleteEntity(entity: Entity) {
|
55
|
-
for (const component of components) {
|
56
|
-
if (hasComponent(component, entity)) removeComponent(component, entity);
|
57
|
-
}
|
58
|
-
entitySymbols.delete(getEntitySymbol(entity));
|
59
|
-
}
|
60
|
-
|
61
|
-
return {
|
62
|
-
registerEntity,
|
63
|
-
components,
|
64
|
-
registerComponent,
|
65
|
-
dispose,
|
66
|
-
registerDisposer,
|
67
|
-
hasEntity,
|
68
|
-
getEntities,
|
69
|
-
entitySymbols,
|
70
|
-
deleteEntity,
|
71
|
-
} satisfies World;
|
72
|
-
}
|
73
|
-
|
74
|
-
/**
|
75
|
-
* Create a new namespace from an existing World.
|
76
|
-
* The `dispose` method of a namespaced World only calls disposers registered on this namespace.
|
77
|
-
*
|
78
|
-
* @param world World to create a new namespace for.
|
79
|
-
* @param namespace String descriptor of the new namespace.
|
80
|
-
* @returns World with a new namespace.
|
81
|
-
*/
|
82
|
-
export function namespaceWorld(world: ReturnType<typeof createWorld>, namespace: string) {
|
83
|
-
return {
|
84
|
-
...world,
|
85
|
-
registerDisposer: (disposer: () => void) => world.registerDisposer(disposer, namespace),
|
86
|
-
dispose: () => world.dispose(namespace),
|
87
|
-
};
|
88
|
-
}
|
89
|
-
|
90
|
-
/**
|
91
|
-
* Get all components that have a value for the given entity.
|
92
|
-
*
|
93
|
-
* @dev Design decision: don't store a list of components for each entity but compute it dynamically when needed
|
94
|
-
* because there are less components than entities and maintaining a list of components per entity is a large overhead.
|
95
|
-
*
|
96
|
-
* @param world World object the given entity is registered on.
|
97
|
-
* @param entity {@link Entity} to get the list of components for.
|
98
|
-
* @returns Array of components that have a value for the given entity.
|
99
|
-
*/
|
100
|
-
export function getEntityComponents(world: World, entity: Entity): Component[] {
|
101
|
-
return world.components.filter((component) => hasComponent(component, entity));
|
102
|
-
}
|
package/src/constants.ts
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Type enum is used to specify value types in {@link ComponentSchema} to be able
|
3
|
-
* to access type values in JavaScript in addition to TypeScript type checks.
|
4
|
-
*/
|
5
|
-
export enum Type {
|
6
|
-
Boolean,
|
7
|
-
Number,
|
8
|
-
OptionalNumber,
|
9
|
-
BigInt,
|
10
|
-
OptionalBigInt,
|
11
|
-
String,
|
12
|
-
OptionalString,
|
13
|
-
NumberArray,
|
14
|
-
OptionalNumberArray,
|
15
|
-
BigIntArray,
|
16
|
-
OptionalBigIntArray,
|
17
|
-
StringArray,
|
18
|
-
OptionalStringArray,
|
19
|
-
Entity,
|
20
|
-
OptionalEntity,
|
21
|
-
EntityArray,
|
22
|
-
OptionalEntityArray,
|
23
|
-
T,
|
24
|
-
OptionalT,
|
25
|
-
}
|
26
|
-
|
27
|
-
/**
|
28
|
-
* Used to specify type of {@link ComponentUpdate}.
|
29
|
-
* - Enter: Update added a value to an entity that did not have a value before
|
30
|
-
* - Exit: Update removed a value from an entity that had a value before
|
31
|
-
* - Update: Update changed a value of an entity that already had a value before. Note: the value doesn't need to be different from the previous value.
|
32
|
-
* - Noop: Update did nothing (removed a value from an entity that did not have a value)
|
33
|
-
*/
|
34
|
-
export enum UpdateType {
|
35
|
-
Enter,
|
36
|
-
Exit,
|
37
|
-
Update,
|
38
|
-
Noop,
|
39
|
-
}
|
40
|
-
|
41
|
-
/**
|
42
|
-
* Helper constant with all optional {@link Type}s.
|
43
|
-
*/
|
44
|
-
export const OptionalTypes = [
|
45
|
-
Type.OptionalEntity,
|
46
|
-
Type.OptionalEntityArray,
|
47
|
-
Type.OptionalNumber,
|
48
|
-
Type.OptionalNumberArray,
|
49
|
-
Type.OptionalBigInt,
|
50
|
-
Type.OptionalBigIntArray,
|
51
|
-
Type.OptionalString,
|
52
|
-
Type.OptionalStringArray,
|
53
|
-
Type.OptionalT,
|
54
|
-
];
|