@latticexyz/recs 2.0.0-main-257a0afc → 2.0.0-march-19-skystrife-playtest-f0a343b1
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/CHANGELOG.md +7 -33
- package/dist/{chunk-X4WOMEVS.js → chunk-YDQFEK6R.js} +1 -1
- package/dist/chunk-YDQFEK6R.js.map +1 -0
- package/dist/deprecated/index.js +1 -1
- package/dist/deprecated/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/Component.ts +17 -18
- package/src/Entity.ts +1 -1
- package/src/Indexer.ts +1 -1
- package/src/Performance.spec.ts +0 -1
- package/src/Query.spec.ts +29 -29
- package/src/Query.ts +13 -12
- package/src/System.spec.ts +4 -4
- package/src/System.ts +7 -7
- package/src/deprecated/createActionSystem.spec.ts +1 -1
- package/src/deprecated/createActionSystem.ts +3 -3
- package/src/deprecated/defineActionComponent.ts +1 -1
- package/src/deprecated/waitForActionCompletion.ts +1 -1
- package/src/deprecated/waitForComponentValueIn.ts +3 -3
- package/src/utils.ts +2 -2
- package/dist/chunk-X4WOMEVS.js.map +0 -1
- package/dist/deprecated/index.d.ts +0 -51
- package/dist/index.d.ts +0 -606
- package/dist/types-0972fad2.d.ts +0 -224
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@latticexyz/recs",
|
3
|
-
"version": "2.0.0-
|
3
|
+
"version": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
4
4
|
"repository": {
|
5
5
|
"type": "git",
|
6
6
|
"url": "https://github.com/latticexyz/mud.git",
|
@@ -25,8 +25,8 @@
|
|
25
25
|
"dependencies": {
|
26
26
|
"mobx": "^6.7.0",
|
27
27
|
"rxjs": "7.5.5",
|
28
|
-
"@latticexyz/schema-type": "2.0.0-
|
29
|
-
"@latticexyz/utils": "2.0.0-
|
28
|
+
"@latticexyz/schema-type": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
29
|
+
"@latticexyz/utils": "2.0.0-march-19-skystrife-playtest-f0a343b1"
|
30
30
|
},
|
31
31
|
"devDependencies": {
|
32
32
|
"@types/jest": "^27.4.1",
|
package/src/Component.ts
CHANGED
@@ -23,7 +23,6 @@ export type ComponentMutationOptions = {
|
|
23
23
|
skipUpdateStream?: boolean;
|
24
24
|
};
|
25
25
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
27
26
|
function getComponentName(component: Component<any, any, any>) {
|
28
27
|
return (
|
29
28
|
component.metadata?.componentName ??
|
@@ -56,7 +55,7 @@ function getComponentName(component: Component<any, any, any>) {
|
|
56
55
|
export function defineComponent<S extends Schema, M extends Metadata, T = unknown>(
|
57
56
|
world: World,
|
58
57
|
schema: S,
|
59
|
-
options?: { id?: string; metadata?: M; indexed?: boolean }
|
58
|
+
options?: { id?: string; metadata?: M; indexed?: boolean }
|
60
59
|
) {
|
61
60
|
if (Object.keys(schema).length === 0) throw new Error("Component schema must have at least one key");
|
62
61
|
const id = options?.id ?? uuid();
|
@@ -87,7 +86,7 @@ export function setComponent<S extends Schema, T = unknown>(
|
|
87
86
|
component: Component<S, Metadata, T>,
|
88
87
|
entity: Entity,
|
89
88
|
value: ComponentValue<S, T>,
|
90
|
-
options: ComponentMutationOptions = {}
|
89
|
+
options: ComponentMutationOptions = {}
|
91
90
|
) {
|
92
91
|
const entitySymbol = getEntitySymbol(entity);
|
93
92
|
const prevValue = getComponentValue(component, entity);
|
@@ -111,7 +110,7 @@ export function setComponent<S extends Schema, T = unknown>(
|
|
111
110
|
"for entity",
|
112
111
|
entity,
|
113
112
|
". Existing keys: ",
|
114
|
-
Object.keys(component.values)
|
113
|
+
Object.keys(component.values)
|
115
114
|
);
|
116
115
|
}
|
117
116
|
}
|
@@ -142,7 +141,7 @@ export function updateComponent<S extends Schema, T = unknown>(
|
|
142
141
|
entity: Entity,
|
143
142
|
value: Partial<ComponentValue<S, T>>,
|
144
143
|
initialValue?: ComponentValue<S, T>,
|
145
|
-
options: ComponentMutationOptions = {}
|
144
|
+
options: ComponentMutationOptions = {}
|
146
145
|
) {
|
147
146
|
const currentValue = getComponentValue(component, entity);
|
148
147
|
if (currentValue === undefined) {
|
@@ -164,7 +163,7 @@ export function updateComponent<S extends Schema, T = unknown>(
|
|
164
163
|
export function removeComponent<S extends Schema, M extends Metadata, T = unknown>(
|
165
164
|
component: Component<S, M, T>,
|
166
165
|
entity: Entity,
|
167
|
-
options: ComponentMutationOptions = {}
|
166
|
+
options: ComponentMutationOptions = {}
|
168
167
|
) {
|
169
168
|
const entitySymbol = getEntitySymbol(entity);
|
170
169
|
const prevValue = getComponentValue(component, entity);
|
@@ -185,7 +184,7 @@ export function removeComponent<S extends Schema, M extends Metadata, T = unknow
|
|
185
184
|
*/
|
186
185
|
export function hasComponent<S extends Schema, T = unknown>(
|
187
186
|
component: Component<S, Metadata, T>,
|
188
|
-
entity: Entity
|
187
|
+
entity: Entity
|
189
188
|
): boolean {
|
190
189
|
const entitySymbol = getEntitySymbol(entity);
|
191
190
|
const map = Object.values(component.values)[0];
|
@@ -202,7 +201,7 @@ export function hasComponent<S extends Schema, T = unknown>(
|
|
202
201
|
*/
|
203
202
|
export function getComponentValue<S extends Schema, T = unknown>(
|
204
203
|
component: Component<S, Metadata, T>,
|
205
|
-
entity: Entity
|
204
|
+
entity: Entity
|
206
205
|
): ComponentValue<S, T> | undefined {
|
207
206
|
const value: Record<string, unknown> = {};
|
208
207
|
const entitySymbol = getEntitySymbol(entity);
|
@@ -231,7 +230,7 @@ export function getComponentValue<S extends Schema, T = unknown>(
|
|
231
230
|
*/
|
232
231
|
export function getComponentValueStrict<S extends Schema, T = unknown>(
|
233
232
|
component: Component<S, Metadata, T>,
|
234
|
-
entity: Entity
|
233
|
+
entity: Entity
|
235
234
|
): ComponentValue<S, T> {
|
236
235
|
const value = getComponentValue(component, entity);
|
237
236
|
if (!value) throw new Error(`No value for component ${getComponentName(component)} on entity ${entity}`);
|
@@ -254,7 +253,7 @@ export function getComponentValueStrict<S extends Schema, T = unknown>(
|
|
254
253
|
*/
|
255
254
|
export function componentValueEquals<S extends Schema, T = unknown>(
|
256
255
|
a?: Partial<ComponentValue<S, T>>,
|
257
|
-
b?: ComponentValue<S, T
|
256
|
+
b?: ComponentValue<S, T>
|
258
257
|
): boolean {
|
259
258
|
if (!a && !b) return true;
|
260
259
|
if (!a || !b) return false;
|
@@ -277,7 +276,7 @@ export function componentValueEquals<S extends Schema, T = unknown>(
|
|
277
276
|
*/
|
278
277
|
export function withValue<S extends Schema, T = unknown>(
|
279
278
|
component: Component<S, Metadata, T>,
|
280
|
-
value: ComponentValue<S, T
|
279
|
+
value: ComponentValue<S, T>
|
281
280
|
): [Component<S, Metadata, T>, ComponentValue<S, T>] {
|
282
281
|
return [component, value];
|
283
282
|
}
|
@@ -291,7 +290,7 @@ export function withValue<S extends Schema, T = unknown>(
|
|
291
290
|
*/
|
292
291
|
export function getEntitiesWithValue<S extends Schema>(
|
293
292
|
component: Component<S> | Indexer<S>,
|
294
|
-
value: Partial<ComponentValue<S
|
293
|
+
value: Partial<ComponentValue<S>>
|
295
294
|
): Set<Entity> {
|
296
295
|
// Shortcut for indexers
|
297
296
|
if (isIndexer(component) && isFullComponentValue(component, value)) {
|
@@ -316,7 +315,7 @@ export function getEntitiesWithValue<S extends Schema>(
|
|
316
315
|
* @returns Set of all entities in the given component.
|
317
316
|
*/
|
318
317
|
export function getComponentEntities<S extends Schema, T = unknown>(
|
319
|
-
component: Component<S, Metadata, T
|
318
|
+
component: Component<S, Metadata, T>
|
320
319
|
): IterableIterator<Entity> {
|
321
320
|
return component.entities();
|
322
321
|
}
|
@@ -336,7 +335,7 @@ export function getComponentEntities<S extends Schema, T = unknown>(
|
|
336
335
|
* @returns overridable component
|
337
336
|
*/
|
338
337
|
export function overridableComponent<S extends Schema, M extends Metadata, T = unknown>(
|
339
|
-
component: Component<S, M, T
|
338
|
+
component: Component<S, M, T>
|
340
339
|
): OverridableComponent<S, M, T> {
|
341
340
|
let nonce = 0;
|
342
341
|
|
@@ -458,7 +457,7 @@ export function overridableComponent<S extends Schema, M extends Metadata, T = u
|
|
458
457
|
component.update$
|
459
458
|
.pipe(
|
460
459
|
filter((e) => !overriddenEntityValues.get(getEntitySymbol(e.entity))),
|
461
|
-
map((update) => ({ ...update, component: overriddenComponent }))
|
460
|
+
map((update) => ({ ...update, component: overriddenComponent }))
|
462
461
|
)
|
463
462
|
.subscribe(update$);
|
464
463
|
|
@@ -476,7 +475,7 @@ export function clearLocalCache(component: Component, uniqueWorldIdentifier?: st
|
|
476
475
|
// Note: Only proof of concept for now - use this only for component that do not update frequently
|
477
476
|
export function createLocalCache<S extends Schema, M extends Metadata, T = unknown>(
|
478
477
|
component: Component<S, M, T>,
|
479
|
-
uniqueWorldIdentifier?: string
|
478
|
+
uniqueWorldIdentifier?: string
|
480
479
|
): Component<S, M, T> {
|
481
480
|
const { world, update$, values } = component;
|
482
481
|
const cacheId = getLocalCacheId(component as Component, uniqueWorldIdentifier);
|
@@ -510,7 +509,7 @@ export function createLocalCache<S extends Schema, M extends Metadata, T = unkno
|
|
510
509
|
const updateSub = update$.subscribe(() => {
|
511
510
|
numUpdates++;
|
512
511
|
const encoded = JSON.stringify(
|
513
|
-
Object.entries(mapObject(values, (m) => [...m.entries()].map((e) => [getEntityString(e[0]), e[1]])))
|
512
|
+
Object.entries(mapObject(values, (m) => [...m.entries()].map((e) => [getEntityString(e[0]), e[1]])))
|
514
513
|
);
|
515
514
|
localStorage.setItem(cacheId, encoded);
|
516
515
|
if (numUpdates > 200) {
|
@@ -521,7 +520,7 @@ export function createLocalCache<S extends Schema, M extends Metadata, T = unkno
|
|
521
520
|
numUpdates,
|
522
521
|
"times since",
|
523
522
|
new Date(creation).toLocaleTimeString(),
|
524
|
-
"- the local cache is in an alpha state and should not be used with components that update frequently yet"
|
523
|
+
"- the local cache is in an alpha state and should not be used with components that update frequently yet"
|
525
524
|
);
|
526
525
|
}
|
527
526
|
});
|
package/src/Entity.ts
CHANGED
@@ -17,7 +17,7 @@ import { Component, ComponentValue, Entity, EntitySymbol, World } from "./types"
|
|
17
17
|
export function createEntity(
|
18
18
|
world: World,
|
19
19
|
components?: [Component, ComponentValue][],
|
20
|
-
options?: { id?: string } | { idSuffix?: string }
|
20
|
+
options?: { id?: string } | { idSuffix?: string }
|
21
21
|
): Entity {
|
22
22
|
const entity = world.registerEntity(options ?? {});
|
23
23
|
|
package/src/Indexer.ts
CHANGED
@@ -18,7 +18,7 @@ import { Component, ComponentValue, Entity, EntitySymbol, Indexer, Metadata, Sch
|
|
18
18
|
* @returns Indexed version of the component.
|
19
19
|
*/
|
20
20
|
export function createIndexer<S extends Schema, M extends Metadata, T = unknown>(
|
21
|
-
component: Component<S, M, T
|
21
|
+
component: Component<S, M, T>
|
22
22
|
): Indexer<S, M, T> {
|
23
23
|
const valueToEntities = new Map<string, Set<EntitySymbol>>();
|
24
24
|
|
package/src/Performance.spec.ts
CHANGED
@@ -35,7 +35,6 @@ describe("V2", () => {
|
|
35
35
|
const Position = defineComponentV2(world, { x: TypeV2.Number, y: TypeV2.Number });
|
36
36
|
|
37
37
|
defineSystem(world, [HasValueV2(Position, { x: 1, y: 1 })], (update) => {
|
38
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
39
38
|
const e = update;
|
40
39
|
});
|
41
40
|
|
package/src/Query.spec.ts
CHANGED
@@ -98,27 +98,27 @@ describe("Query", () => {
|
|
98
98
|
expect(runQuery([HasValue(OwnedByEntity, { value: Player })])).toEqual(new Set([Depth1]));
|
99
99
|
|
100
100
|
expect(runQuery([ProxyExpand(OwnedByEntity, 0), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
101
|
-
new Set([Depth1])
|
101
|
+
new Set([Depth1])
|
102
102
|
);
|
103
103
|
|
104
104
|
expect(runQuery([ProxyExpand(OwnedByEntity, 1), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
105
|
-
new Set([Depth1, Depth2])
|
105
|
+
new Set([Depth1, Depth2])
|
106
106
|
);
|
107
107
|
|
108
108
|
expect(runQuery([ProxyExpand(OwnedByEntity, 2), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
109
|
-
new Set([Depth1, Depth2, Depth3])
|
109
|
+
new Set([Depth1, Depth2, Depth3])
|
110
110
|
);
|
111
111
|
|
112
112
|
expect(runQuery([ProxyExpand(OwnedByEntity, 3), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
113
|
-
new Set([Depth1, Depth2, Depth3, Depth4])
|
113
|
+
new Set([Depth1, Depth2, Depth3, Depth4])
|
114
114
|
);
|
115
115
|
|
116
116
|
expect(runQuery([ProxyExpand(OwnedByEntity, 4), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
117
|
-
new Set([Depth1, Depth2, Depth3, Depth4, Depth5])
|
117
|
+
new Set([Depth1, Depth2, Depth3, Depth4, Depth5])
|
118
118
|
);
|
119
119
|
|
120
120
|
expect(
|
121
|
-
runQuery([ProxyExpand(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(OwnedByEntity, { value: Player })])
|
121
|
+
runQuery([ProxyExpand(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(OwnedByEntity, { value: Player })])
|
122
122
|
).toEqual(new Set([Depth1, Depth2, Depth3, Depth4, Depth5]));
|
123
123
|
});
|
124
124
|
|
@@ -132,8 +132,8 @@ describe("Query", () => {
|
|
132
132
|
expect(
|
133
133
|
runQuery(
|
134
134
|
[ProxyRead(OwnedByEntity, 1), HasValue(Name, { name: "Alice" })],
|
135
|
-
new Set([Depth1, Depth2, Depth3])
|
136
|
-
)
|
135
|
+
new Set([Depth1, Depth2, Depth3]) // Provide an initial set of entities
|
136
|
+
)
|
137
137
|
).toEqual(new Set([Depth1]));
|
138
138
|
|
139
139
|
expect(
|
@@ -142,7 +142,7 @@ describe("Query", () => {
|
|
142
142
|
HasValue(Name, { name: "Alice" }), // Get all entities with name Alice or owned by Alice
|
143
143
|
ProxyExpand(OwnedByEntity, 0), // Turn off proxy expand
|
144
144
|
NotValue(Name, { name: "Alice" }), // Filter Alice, only keep entities owned by Alice
|
145
|
-
])
|
145
|
+
])
|
146
146
|
).toEqual(new Set([Depth1]));
|
147
147
|
|
148
148
|
expect(
|
@@ -151,15 +151,15 @@ describe("Query", () => {
|
|
151
151
|
HasValue(Name, { name: "Alice" }), // Get all child entities of Alice (including alice)
|
152
152
|
ProxyExpand(OwnedByEntity, 0), // Turn off proxy expand
|
153
153
|
NotValue(Name, { name: "Alice" }), // Filter Alice, only keep entities owned by Alice
|
154
|
-
])
|
154
|
+
])
|
155
155
|
).toEqual(new Set([Depth1, Depth2, Depth3, Depth4]));
|
156
156
|
|
157
157
|
// Get all entities from the initial set [Depth3] that have an indirect owner called Alice
|
158
158
|
expect(
|
159
159
|
runQuery(
|
160
160
|
[ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(Name, { name: "Alice" })],
|
161
|
-
new Set([Depth3])
|
162
|
-
)
|
161
|
+
new Set([Depth3]) // Provide an initial set of entities
|
162
|
+
)
|
163
163
|
).toEqual(new Set([Depth3]));
|
164
164
|
|
165
165
|
// Get all entities that have an indirect owner called Alice
|
@@ -171,8 +171,8 @@ describe("Query", () => {
|
|
171
171
|
ProxyRead(OwnedByEntity, 0),
|
172
172
|
NotValue(Name, { name: "Alice" }),
|
173
173
|
],
|
174
|
-
new Set([Player, Depth1, Depth2, Depth3, Depth4])
|
175
|
-
)
|
174
|
+
new Set([Player, Depth1, Depth2, Depth3, Depth4]) // Provide an initial set of entities
|
175
|
+
)
|
176
176
|
).toEqual(new Set([Depth1, Depth2, Depth3, Depth4]));
|
177
177
|
|
178
178
|
// Get all entities from the initial set [Depth3] that have an indirect owner called Alice and their direct child
|
@@ -183,8 +183,8 @@ describe("Query", () => {
|
|
183
183
|
ProxyExpand(OwnedByEntity, 1),
|
184
184
|
HasValue(Name, { name: "Alice" }),
|
185
185
|
],
|
186
|
-
new Set([Depth2])
|
187
|
-
)
|
186
|
+
new Set([Depth2]) // Provide an initial set of entities
|
187
|
+
)
|
188
188
|
).toEqual(new Set([Depth2, Depth3]));
|
189
189
|
});
|
190
190
|
|
@@ -204,15 +204,15 @@ describe("Query", () => {
|
|
204
204
|
createEntity(world, [withValue(Position, { x: 1, y: 1 })]);
|
205
205
|
|
206
206
|
expect(runQuery([ProxyExpand(FromPrototype, 1), Has(CanMove), Not(Prototype)])).toEqual(
|
207
|
-
new Set([instance1, instance2])
|
207
|
+
new Set([instance1, instance2])
|
208
208
|
);
|
209
209
|
|
210
210
|
expect(runQuery([Has(Position), ProxyRead(FromPrototype, 1), Has(CanMove)])).toEqual(
|
211
|
-
new Set([instance1, instance2])
|
211
|
+
new Set([instance1, instance2])
|
212
212
|
);
|
213
213
|
|
214
214
|
expect(runQuery([ProxyRead(FromPrototype, 1), Has(Position), Has(CanMove)])).toEqual(
|
215
|
-
new Set([instance1, instance2])
|
215
|
+
new Set([instance1, instance2])
|
216
216
|
);
|
217
217
|
});
|
218
218
|
|
@@ -287,7 +287,7 @@ describe("Query", () => {
|
|
287
287
|
Has(CanMove), // ...have the CanMove component...
|
288
288
|
ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), // ...and for whose owner holds...
|
289
289
|
NotValue(Name, { name: "Alice" }), // ...their name is not Alice
|
290
|
-
])
|
290
|
+
])
|
291
291
|
).toEqual(new Set([Instance3, Entity8]));
|
292
292
|
});
|
293
293
|
|
@@ -343,14 +343,14 @@ describe("Query", () => {
|
|
343
343
|
entity: entities[0],
|
344
344
|
component: CanMove,
|
345
345
|
value: [{ value: true }, undefined],
|
346
|
-
})
|
346
|
+
})
|
347
347
|
);
|
348
348
|
expect(mock).toHaveBeenCalledWith(
|
349
349
|
expect.objectContaining({
|
350
350
|
entity: entities[1],
|
351
351
|
component: CanMove,
|
352
352
|
value: [{ value: true }, undefined],
|
353
|
-
})
|
353
|
+
})
|
354
354
|
);
|
355
355
|
expect(mock).toBeCalledTimes(2);
|
356
356
|
|
@@ -360,7 +360,7 @@ describe("Query", () => {
|
|
360
360
|
entity: entities[2],
|
361
361
|
component: CanMove,
|
362
362
|
value: [{ value: true }, undefined],
|
363
|
-
})
|
363
|
+
})
|
364
364
|
);
|
365
365
|
expect(mock).toHaveBeenCalledTimes(3);
|
366
366
|
});
|
@@ -388,7 +388,7 @@ describe("Query", () => {
|
|
388
388
|
entity: entity1,
|
389
389
|
component: CanMove,
|
390
390
|
value: [undefined, { value: true }],
|
391
|
-
})
|
391
|
+
})
|
392
392
|
);
|
393
393
|
|
394
394
|
removeComponent(CanMove, entity2);
|
@@ -398,7 +398,7 @@ describe("Query", () => {
|
|
398
398
|
entity: entity2,
|
399
399
|
component: CanMove,
|
400
400
|
value: [undefined, { value: true }],
|
401
|
-
})
|
401
|
+
})
|
402
402
|
);
|
403
403
|
});
|
404
404
|
});
|
@@ -617,7 +617,7 @@ describe("Query", () => {
|
|
617
617
|
|
618
618
|
const query1 = defineQuery(
|
619
619
|
[ProxyRead(OwnedByEntity, 1), HasValue(Name, { name: "Alice" })],
|
620
|
-
{ initialSet: new Set([Depth1, Depth2, Depth3]) }
|
620
|
+
{ initialSet: new Set([Depth1, Depth2, Depth3]) } // Provide an initial set of entities
|
621
621
|
);
|
622
622
|
query1.update$.subscribe();
|
623
623
|
|
@@ -639,7 +639,7 @@ describe("Query", () => {
|
|
639
639
|
|
640
640
|
const query4 = defineQuery(
|
641
641
|
[ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(Name, { name: "Alice" })],
|
642
|
-
{ initialSet: new Set([Depth3]) }
|
642
|
+
{ initialSet: new Set([Depth3]) } // Provide an initial set of entities
|
643
643
|
);
|
644
644
|
query4.update$.subscribe();
|
645
645
|
|
@@ -650,7 +650,7 @@ describe("Query", () => {
|
|
650
650
|
ProxyRead(OwnedByEntity, 0),
|
651
651
|
NotValue(Name, { name: "Alice" }),
|
652
652
|
],
|
653
|
-
{ initialSet: new Set([Player, Depth1, Depth2, Depth3, Depth4]) }
|
653
|
+
{ initialSet: new Set([Player, Depth1, Depth2, Depth3, Depth4]) } // Provide an initial set of entities
|
654
654
|
);
|
655
655
|
query5.update$.subscribe();
|
656
656
|
|
@@ -660,7 +660,7 @@ describe("Query", () => {
|
|
660
660
|
ProxyExpand(OwnedByEntity, 1),
|
661
661
|
HasValue(Name, { name: "Alice" }),
|
662
662
|
],
|
663
|
-
{ initialSet: new Set([Depth2]) }
|
663
|
+
{ initialSet: new Set([Depth2]) } // Provide an initial set of entities
|
664
664
|
);
|
665
665
|
query6.update$.subscribe();
|
666
666
|
|
package/src/Query.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { filterNullish } from "@latticexyz/utils";
|
2
2
|
import { observable, ObservableSet } from "mobx";
|
3
|
-
import { concat, concatMap, filter, from, map, merge, Observable, of, share } from "rxjs";
|
3
|
+
import { concat, concatMap, filter, from, map, merge, Observable, of, share, Subject } from "rxjs";
|
4
4
|
import {
|
5
5
|
componentValueEquals,
|
6
6
|
getComponentEntities,
|
@@ -15,6 +15,7 @@ import {
|
|
15
15
|
ComponentValue,
|
16
16
|
Entity,
|
17
17
|
EntityQueryFragment,
|
18
|
+
EntitySymbol,
|
18
19
|
HasQueryFragment,
|
19
20
|
HasValueQueryFragment,
|
20
21
|
NotQueryFragment,
|
@@ -87,7 +88,7 @@ export function Not<T extends Schema>(component: Component<T>): NotQueryFragment
|
|
87
88
|
*/
|
88
89
|
export function HasValue<T extends Schema>(
|
89
90
|
component: Component<T>,
|
90
|
-
value: Partial<ComponentValue<T
|
91
|
+
value: Partial<ComponentValue<T>>
|
91
92
|
): HasValueQueryFragment<T> {
|
92
93
|
return { type: QueryFragmentType.HasValue, component, value };
|
93
94
|
}
|
@@ -111,7 +112,7 @@ export function HasValue<T extends Schema>(
|
|
111
112
|
*/
|
112
113
|
export function NotValue<T extends Schema>(
|
113
114
|
component: Component<T>,
|
114
|
-
value: Partial<ComponentValue<T
|
115
|
+
value: Partial<ComponentValue<T>>
|
115
116
|
): NotValueQueryFragment<T> {
|
116
117
|
return { type: QueryFragmentType.NotValue, component, value };
|
117
118
|
}
|
@@ -198,7 +199,7 @@ function passesQueryFragment<T extends Schema>(entity: Entity, fragment: EntityQ
|
|
198
199
|
* @returns True if the query fragment is positive, else false.
|
199
200
|
*/
|
200
201
|
function isPositiveFragment<T extends Schema>(
|
201
|
-
fragment: QueryFragment<T
|
202
|
+
fragment: QueryFragment<T>
|
202
203
|
): fragment is HasQueryFragment<T> | HasValueQueryFragment<T> {
|
203
204
|
return fragment.type === QueryFragmentType.Has || fragment.type == QueryFragmentType.HasValue;
|
204
205
|
}
|
@@ -210,7 +211,7 @@ function isPositiveFragment<T extends Schema>(
|
|
210
211
|
* @returns True if the query fragment is negative, else false.
|
211
212
|
*/
|
212
213
|
function isNegativeFragment<T extends Schema>(
|
213
|
-
fragment: QueryFragment<T
|
214
|
+
fragment: QueryFragment<T>
|
214
215
|
): fragment is NotQueryFragment<T> | NotValueQueryFragment<T> {
|
215
216
|
return fragment.type === QueryFragmentType.Not || fragment.type == QueryFragmentType.NotValue;
|
216
217
|
}
|
@@ -252,7 +253,7 @@ function isBreakingPassState(passes: boolean, fragment: EntityQueryFragment<Sche
|
|
252
253
|
function passesQueryFragmentProxy<T extends Schema>(
|
253
254
|
entity: Entity,
|
254
255
|
fragment: EntityQueryFragment<T>,
|
255
|
-
proxyRead: ProxyReadQueryFragment
|
256
|
+
proxyRead: ProxyReadQueryFragment
|
256
257
|
): boolean | null {
|
257
258
|
let proxyEntity = entity;
|
258
259
|
let passes = false;
|
@@ -287,7 +288,7 @@ function passesQueryFragmentProxy<T extends Schema>(
|
|
287
288
|
export function getChildEntities(
|
288
289
|
entity: Entity,
|
289
290
|
component: Component<{ value: Type.Entity }>,
|
290
|
-
depth: number
|
291
|
+
depth: number
|
291
292
|
): Set<Entity> {
|
292
293
|
if (depth === 0) return new Set();
|
293
294
|
|
@@ -415,7 +416,7 @@ export function runQuery(fragments: QueryFragment[], initialSet?: Set<Entity>):
|
|
415
416
|
*/
|
416
417
|
export function defineQuery(
|
417
418
|
fragments: QueryFragment[],
|
418
|
-
options?: { runOnInit?: boolean; initialSet?: Set<Entity> }
|
419
|
+
options?: { runOnInit?: boolean; initialSet?: Set<Entity> }
|
419
420
|
): {
|
420
421
|
update$: Observable<ComponentUpdate & { type: UpdateType }>;
|
421
422
|
matching: ObservableSet<Entity>;
|
@@ -502,7 +503,7 @@ export function defineQuery(
|
|
502
503
|
return { ...update, type: UpdateType.Enter };
|
503
504
|
}
|
504
505
|
}),
|
505
|
-
filterNullish()
|
506
|
+
filterNullish()
|
506
507
|
);
|
507
508
|
|
508
509
|
return {
|
@@ -520,7 +521,7 @@ export function defineQuery(
|
|
520
521
|
*/
|
521
522
|
export function defineUpdateQuery(
|
522
523
|
fragments: QueryFragment[],
|
523
|
-
options?: { runOnInit?: boolean }
|
524
|
+
options?: { runOnInit?: boolean }
|
524
525
|
): Observable<ComponentUpdate & { type: UpdateType }> {
|
525
526
|
return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Update));
|
526
527
|
}
|
@@ -534,7 +535,7 @@ export function defineUpdateQuery(
|
|
534
535
|
*/
|
535
536
|
export function defineEnterQuery(
|
536
537
|
fragments: QueryFragment[],
|
537
|
-
options?: { runOnInit?: boolean }
|
538
|
+
options?: { runOnInit?: boolean }
|
538
539
|
): Observable<ComponentUpdate> {
|
539
540
|
return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Enter));
|
540
541
|
}
|
@@ -548,7 +549,7 @@ export function defineEnterQuery(
|
|
548
549
|
*/
|
549
550
|
export function defineExitQuery(
|
550
551
|
fragments: QueryFragment[],
|
551
|
-
options?: { runOnInit?: boolean }
|
552
|
+
options?: { runOnInit?: boolean }
|
552
553
|
): Observable<ComponentUpdate> {
|
553
554
|
return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Exit));
|
554
555
|
}
|
package/src/System.spec.ts
CHANGED
@@ -100,13 +100,13 @@ describe("System", () => {
|
|
100
100
|
|
101
101
|
expect(mock).toHaveBeenCalledTimes(1);
|
102
102
|
expect(mock).toHaveBeenCalledWith(
|
103
|
-
expect.objectContaining({ entity: entity1, component: CanMove, value: [{ value: true }, undefined] })
|
103
|
+
expect.objectContaining({ entity: entity1, component: CanMove, value: [{ value: true }, undefined] })
|
104
104
|
);
|
105
105
|
|
106
106
|
const entity2 = createEntity(world, [withValue(CanMove, { value: true })]);
|
107
107
|
expect(mock).toHaveBeenCalledTimes(2);
|
108
108
|
expect(mock).toHaveBeenCalledWith(
|
109
|
-
expect.objectContaining({ entity: entity2, component: CanMove, value: [{ value: true }, undefined] })
|
109
|
+
expect.objectContaining({ entity: entity2, component: CanMove, value: [{ value: true }, undefined] })
|
110
110
|
);
|
111
111
|
});
|
112
112
|
|
@@ -126,13 +126,13 @@ describe("System", () => {
|
|
126
126
|
|
127
127
|
expect(mock).toHaveBeenCalledTimes(1);
|
128
128
|
expect(mock).toHaveBeenCalledWith(
|
129
|
-
expect.objectContaining({ entity: entity1, component: CanMove, value: [undefined, { value: true }] })
|
129
|
+
expect.objectContaining({ entity: entity1, component: CanMove, value: [undefined, { value: true }] })
|
130
130
|
);
|
131
131
|
|
132
132
|
removeComponent(CanMove, entity2);
|
133
133
|
expect(mock).toHaveBeenCalledTimes(2);
|
134
134
|
expect(mock).toHaveBeenCalledWith(
|
135
|
-
expect.objectContaining({ entity: entity2, component: CanMove, value: [undefined, { value: true }] })
|
135
|
+
expect.objectContaining({ entity: entity2, component: CanMove, value: [undefined, { value: true }] })
|
136
136
|
);
|
137
137
|
});
|
138
138
|
});
|
package/src/System.ts
CHANGED
@@ -36,7 +36,7 @@ export function defineUpdateSystem(
|
|
36
36
|
world: World,
|
37
37
|
query: QueryFragment[],
|
38
38
|
system: (update: ComponentUpdate) => void,
|
39
|
-
options: { runOnInit?: boolean } = { runOnInit: true }
|
39
|
+
options: { runOnInit?: boolean } = { runOnInit: true }
|
40
40
|
) {
|
41
41
|
defineRxSystem(world, defineUpdateQuery(query, options), system);
|
42
42
|
}
|
@@ -56,7 +56,7 @@ export function defineEnterSystem(
|
|
56
56
|
world: World,
|
57
57
|
query: QueryFragment[],
|
58
58
|
system: (update: ComponentUpdate) => void,
|
59
|
-
options: { runOnInit?: boolean } = { runOnInit: true }
|
59
|
+
options: { runOnInit?: boolean } = { runOnInit: true }
|
60
60
|
) {
|
61
61
|
defineRxSystem(world, defineEnterQuery(query, options), system);
|
62
62
|
}
|
@@ -76,7 +76,7 @@ export function defineExitSystem(
|
|
76
76
|
world: World,
|
77
77
|
query: QueryFragment[],
|
78
78
|
system: (update: ComponentUpdate) => void,
|
79
|
-
options: { runOnInit?: boolean } = { runOnInit: true }
|
79
|
+
options: { runOnInit?: boolean } = { runOnInit: true }
|
80
80
|
) {
|
81
81
|
defineRxSystem(world, defineExitQuery(query, options), system);
|
82
82
|
}
|
@@ -96,7 +96,7 @@ export function defineSystem(
|
|
96
96
|
world: World,
|
97
97
|
query: QueryFragment[],
|
98
98
|
system: (update: ComponentUpdate & { type: UpdateType }) => void,
|
99
|
-
options: { runOnInit?: boolean } = { runOnInit: true }
|
99
|
+
options: { runOnInit?: boolean } = { runOnInit: true }
|
100
100
|
) {
|
101
101
|
defineRxSystem(world, defineQuery(query, options).update$, system);
|
102
102
|
}
|
@@ -116,7 +116,7 @@ export function defineComponentSystem<S extends Schema>(
|
|
116
116
|
world: World,
|
117
117
|
component: Component<S>,
|
118
118
|
system: (update: ComponentUpdate<S>) => void,
|
119
|
-
options: { runOnInit?: boolean } = { runOnInit: true }
|
119
|
+
options: { runOnInit?: boolean } = { runOnInit: true }
|
120
120
|
) {
|
121
121
|
const initial$ = options?.runOnInit ? from(getComponentEntities(component)).pipe(toUpdateStream(component)) : EMPTY;
|
122
122
|
defineRxSystem(world, concat(initial$, component.update$), system);
|
@@ -135,7 +135,7 @@ export function defineSyncSystem<T extends Schema>(
|
|
135
135
|
query: QueryFragment[],
|
136
136
|
component: (entity: Entity) => Component<T>,
|
137
137
|
value: (entity: Entity) => ComponentValue<T>,
|
138
|
-
options: { update?: boolean; runOnInit?: boolean } = { update: false, runOnInit: true }
|
138
|
+
options: { update?: boolean; runOnInit?: boolean } = { update: false, runOnInit: true }
|
139
139
|
) {
|
140
140
|
defineSystem(
|
141
141
|
world,
|
@@ -145,6 +145,6 @@ export function defineSyncSystem<T extends Schema>(
|
|
145
145
|
if (type === UpdateType.Exit) removeComponent(component(entity), entity);
|
146
146
|
if (options?.update && type === UpdateType.Update) setComponent(component(entity), entity, value(entity));
|
147
147
|
},
|
148
|
-
options
|
148
|
+
options
|
149
149
|
);
|
150
150
|
}
|
@@ -177,7 +177,7 @@ describe("ActionSystem", () => {
|
|
177
177
|
expect(runQuery([HasValue(Action, { on: settlement1 })])).toEqual(new Set([entity1]));
|
178
178
|
expect(runQuery([HasValue(Action, { on: settlement2 })])).toEqual(new Set([entity2]));
|
179
179
|
expect(runQuery([HasValue(Action, { state: ActionState.Requested })])).toEqual(
|
180
|
-
new Set([entity1, entity2, entity3])
|
180
|
+
new Set([entity1, entity2, entity3])
|
181
181
|
);
|
182
182
|
});
|
183
183
|
|
@@ -15,7 +15,7 @@ export type ActionSystem = ReturnType<typeof createActionSystem>;
|
|
15
15
|
export function createActionSystem<M = unknown>(
|
16
16
|
world: World,
|
17
17
|
txReduced$: Observable<string>,
|
18
|
-
waitForTransaction?: (tx: string) => Promise<void
|
18
|
+
waitForTransaction?: (tx: string) => Promise<void>
|
19
19
|
) {
|
20
20
|
// Action component
|
21
21
|
const Action = defineActionComponent<M>(world);
|
@@ -40,7 +40,7 @@ export function createActionSystem<M = unknown>(
|
|
40
40
|
* @returns Components including pending updates
|
41
41
|
*/
|
42
42
|
function withOptimisticUpdates<S extends Schema, M extends Metadata, T>(
|
43
|
-
component: Component<S, M, T
|
43
|
+
component: Component<S, M, T>
|
44
44
|
): OverridableComponent<S, M, T> {
|
45
45
|
const optimisticComponent = componentsWithOptimisticUpdates[component.id] || overridableComponent(component);
|
46
46
|
|
@@ -99,7 +99,7 @@ export function createActionSystem<M = unknown>(
|
|
99
99
|
// This subscriotion makes sure the action requirement is checked again every time
|
100
100
|
// one of the referenced components changes or the pending updates map changes
|
101
101
|
const subscription = merge(
|
102
|
-
...Object.values(action.componentsWithOptimisticUpdates).map((c) => c.update$)
|
102
|
+
...Object.values(action.componentsWithOptimisticUpdates).map((c) => c.update$)
|
103
103
|
).subscribe(() => checkRequirement(action));
|
104
104
|
checkRequirement(action);
|
105
105
|
disposer.set(action.id, { dispose: () => subscription?.unsubscribe() });
|
@@ -12,7 +12,7 @@ export function defineActionComponent<T = unknown>(world: World) {
|
|
12
12
|
overrides: Type.OptionalStringArray,
|
13
13
|
txHash: Type.OptionalString,
|
14
14
|
},
|
15
|
-
{ id: "Action" }
|
15
|
+
{ id: "Action" }
|
16
16
|
);
|
17
17
|
return Action as Component<SchemaOf<typeof Action>, Metadata, T>;
|
18
18
|
}
|
@@ -5,7 +5,7 @@ import { waitForComponentValueIn } from "./waitForComponentValueIn";
|
|
5
5
|
|
6
6
|
export async function waitForActionCompletion(
|
7
7
|
Action: ReturnType<typeof defineActionComponent>,
|
8
|
-
entity: Entity
|
8
|
+
entity: Entity
|
9
9
|
): Promise<void> {
|
10
10
|
return waitForComponentValueIn(Action, entity, [
|
11
11
|
{ state: ActionState.Cancelled },
|