@latticexyz/recs 2.0.12-main-9be2bb86 → 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/Query.spec.ts
DELETED
@@ -1,811 +0,0 @@
|
|
1
|
-
import { defineComponent, removeComponent, setComponent, withValue } from "./Component";
|
2
|
-
import { UpdateType, Type } from "./constants";
|
3
|
-
import { createEntity } from "./Entity";
|
4
|
-
import {
|
5
|
-
Has,
|
6
|
-
Not,
|
7
|
-
defineEnterQuery,
|
8
|
-
defineExitQuery,
|
9
|
-
defineQuery,
|
10
|
-
HasValue,
|
11
|
-
NotValue,
|
12
|
-
ProxyRead,
|
13
|
-
ProxyExpand,
|
14
|
-
runQuery,
|
15
|
-
} from "./Query";
|
16
|
-
import { Component, Entity, World } from "./types";
|
17
|
-
import { createWorld } from "./World";
|
18
|
-
|
19
|
-
describe("Query", () => {
|
20
|
-
let world: World;
|
21
|
-
|
22
|
-
let Position: Component<{
|
23
|
-
x: Type.Number;
|
24
|
-
y: Type.Number;
|
25
|
-
}>;
|
26
|
-
|
27
|
-
let CanMove: Component<{ value: Type.Boolean }>;
|
28
|
-
|
29
|
-
let OwnedByEntity: Component<{ value: Type.Entity }>;
|
30
|
-
|
31
|
-
let Prototype: Component<{ value: Type.Boolean }>;
|
32
|
-
|
33
|
-
let FromPrototype: Component<{ value: Type.Entity }>;
|
34
|
-
|
35
|
-
let Name: Component<{ name: Type.String }>;
|
36
|
-
|
37
|
-
beforeEach(() => {
|
38
|
-
world = createWorld();
|
39
|
-
|
40
|
-
Position = defineComponent(world, { x: Type.Number, y: Type.Number });
|
41
|
-
CanMove = defineComponent(world, { value: Type.Boolean });
|
42
|
-
Name = defineComponent(world, { name: Type.String }, { id: "Name" });
|
43
|
-
OwnedByEntity = defineComponent(world, { value: Type.Entity }, { id: "OwnedByEntity" });
|
44
|
-
Prototype = defineComponent(world, { value: Type.Boolean });
|
45
|
-
FromPrototype = defineComponent(world, { value: Type.Entity });
|
46
|
-
});
|
47
|
-
|
48
|
-
describe("runQuery", () => {
|
49
|
-
it("should return all entities with Position and CanMove component", () => {
|
50
|
-
const Creature1 = createEntity(world, [withValue(Position, { x: 1, y: 2 }), withValue(CanMove, { value: true })]);
|
51
|
-
const Creature2 = createEntity(world, [withValue(Position, { x: 1, y: 1 }), withValue(CanMove, { value: true })]);
|
52
|
-
const Structure = createEntity(world, [withValue(Position, { x: 2, y: 3 })]);
|
53
|
-
|
54
|
-
const movableEntities = runQuery([Has(CanMove), Has(Position)]);
|
55
|
-
const staticEntities = runQuery([Has(Position), Not(CanMove)]);
|
56
|
-
|
57
|
-
expect(movableEntities).toEqual(new Set([Creature1, Creature2]));
|
58
|
-
expect(movableEntities.has(Structure)).toBe(false);
|
59
|
-
|
60
|
-
expect(staticEntities).toEqual(new Set([Structure]));
|
61
|
-
});
|
62
|
-
|
63
|
-
it("should return all entities with the given values for the Position component", () => {
|
64
|
-
const Creature1 = createEntity(world, [withValue(Position, { x: 1, y: 2 }), withValue(CanMove, { value: true })]);
|
65
|
-
const Creature2 = createEntity(world, [withValue(Position, { x: 1, y: 1 }), withValue(CanMove, { value: true })]);
|
66
|
-
const Creature3 = createEntity(world, [withValue(Position, { x: 1, y: 1 })]);
|
67
|
-
|
68
|
-
const valueQuery1 = runQuery([HasValue(Position, { x: 1, y: 1 })]);
|
69
|
-
expect(valueQuery1).toEqual(new Set([Creature2, Creature3]));
|
70
|
-
|
71
|
-
const valueQuery2 = runQuery([Has(CanMove), HasValue(Position, { x: 1, y: 1 })]);
|
72
|
-
expect(valueQuery2).toEqual(new Set([Creature2]));
|
73
|
-
|
74
|
-
const valueQuery3 = runQuery([Has(CanMove), HasValue(Position, { x: 1, y: 2 })]);
|
75
|
-
expect(valueQuery3).toEqual(new Set([Creature1]));
|
76
|
-
});
|
77
|
-
|
78
|
-
it("should return all entities with Position component except of a specific value", () => {
|
79
|
-
const Creature1 = createEntity(world, [withValue(Position, { x: 1, y: 2 }), withValue(CanMove, { value: true })]);
|
80
|
-
const Creature2 = createEntity(world, [withValue(Position, { x: 1, y: 1 }), withValue(CanMove, { value: true })]);
|
81
|
-
const Creature3 = createEntity(world, [withValue(Position, { x: 2, y: 1 })]);
|
82
|
-
|
83
|
-
const valueQuery1 = runQuery([Has(Position), NotValue(Position, { x: 1, y: 2 })]);
|
84
|
-
expect(valueQuery1).toEqual(new Set([Creature2, Creature3]));
|
85
|
-
|
86
|
-
const valueQuery2 = runQuery([Has(CanMove), NotValue(Position, { x: 1, y: 1 })]);
|
87
|
-
expect(valueQuery2).toEqual(new Set([Creature1]));
|
88
|
-
});
|
89
|
-
|
90
|
-
it("should return all player owned entities up to the given depth", () => {
|
91
|
-
const Player = createEntity(world);
|
92
|
-
const Depth1 = createEntity(world, [withValue(OwnedByEntity, { value: Player })]);
|
93
|
-
const Depth2 = createEntity(world, [withValue(OwnedByEntity, { value: Depth1 })]);
|
94
|
-
const Depth3 = createEntity(world, [withValue(OwnedByEntity, { value: Depth2 })]);
|
95
|
-
const Depth4 = createEntity(world, [withValue(OwnedByEntity, { value: Depth3 })]);
|
96
|
-
const Depth5 = createEntity(world, [withValue(OwnedByEntity, { value: Depth4 })]);
|
97
|
-
|
98
|
-
expect(runQuery([HasValue(OwnedByEntity, { value: Player })])).toEqual(new Set([Depth1]));
|
99
|
-
|
100
|
-
expect(runQuery([ProxyExpand(OwnedByEntity, 0), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
101
|
-
new Set([Depth1]),
|
102
|
-
);
|
103
|
-
|
104
|
-
expect(runQuery([ProxyExpand(OwnedByEntity, 1), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
105
|
-
new Set([Depth1, Depth2]),
|
106
|
-
);
|
107
|
-
|
108
|
-
expect(runQuery([ProxyExpand(OwnedByEntity, 2), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
109
|
-
new Set([Depth1, Depth2, Depth3]),
|
110
|
-
);
|
111
|
-
|
112
|
-
expect(runQuery([ProxyExpand(OwnedByEntity, 3), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
113
|
-
new Set([Depth1, Depth2, Depth3, Depth4]),
|
114
|
-
);
|
115
|
-
|
116
|
-
expect(runQuery([ProxyExpand(OwnedByEntity, 4), HasValue(OwnedByEntity, { value: Player })])).toEqual(
|
117
|
-
new Set([Depth1, Depth2, Depth3, Depth4, Depth5]),
|
118
|
-
);
|
119
|
-
|
120
|
-
expect(
|
121
|
-
runQuery([ProxyExpand(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(OwnedByEntity, { value: Player })]),
|
122
|
-
).toEqual(new Set([Depth1, Depth2, Depth3, Depth4, Depth5]));
|
123
|
-
});
|
124
|
-
|
125
|
-
it("should return entites owned by an entity with Name component Alice", () => {
|
126
|
-
const Player = createEntity(world, [withValue(Name, { name: "Alice" })]);
|
127
|
-
const Depth1 = createEntity(world, [withValue(OwnedByEntity, { value: Player })]);
|
128
|
-
const Depth2 = createEntity(world, [withValue(OwnedByEntity, { value: Depth1 })]);
|
129
|
-
const Depth3 = createEntity(world, [withValue(OwnedByEntity, { value: Depth2 })]);
|
130
|
-
const Depth4 = createEntity(world, [withValue(OwnedByEntity, { value: Depth3 })]);
|
131
|
-
|
132
|
-
expect(
|
133
|
-
runQuery(
|
134
|
-
[ProxyRead(OwnedByEntity, 1), HasValue(Name, { name: "Alice" })],
|
135
|
-
new Set([Depth1, Depth2, Depth3]), // Provide an initial set of entities
|
136
|
-
),
|
137
|
-
).toEqual(new Set([Depth1]));
|
138
|
-
|
139
|
-
expect(
|
140
|
-
runQuery([
|
141
|
-
ProxyExpand(OwnedByEntity, 1), // Turn on proxy expand
|
142
|
-
HasValue(Name, { name: "Alice" }), // Get all entities with name Alice or owned by Alice
|
143
|
-
ProxyExpand(OwnedByEntity, 0), // Turn off proxy expand
|
144
|
-
NotValue(Name, { name: "Alice" }), // Filter Alice, only keep entities owned by Alice
|
145
|
-
]),
|
146
|
-
).toEqual(new Set([Depth1]));
|
147
|
-
|
148
|
-
expect(
|
149
|
-
runQuery([
|
150
|
-
ProxyExpand(OwnedByEntity, Number.MAX_SAFE_INTEGER), // Include all child entities
|
151
|
-
HasValue(Name, { name: "Alice" }), // Get all child entities of Alice (including alice)
|
152
|
-
ProxyExpand(OwnedByEntity, 0), // Turn off proxy expand
|
153
|
-
NotValue(Name, { name: "Alice" }), // Filter Alice, only keep entities owned by Alice
|
154
|
-
]),
|
155
|
-
).toEqual(new Set([Depth1, Depth2, Depth3, Depth4]));
|
156
|
-
|
157
|
-
// Get all entities from the initial set [Depth3] that have an indirect owner called Alice
|
158
|
-
expect(
|
159
|
-
runQuery(
|
160
|
-
[ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(Name, { name: "Alice" })],
|
161
|
-
new Set([Depth3]), // Provide an initial set of entities
|
162
|
-
),
|
163
|
-
).toEqual(new Set([Depth3]));
|
164
|
-
|
165
|
-
// Get all entities that have an indirect owner called Alice
|
166
|
-
expect(
|
167
|
-
runQuery(
|
168
|
-
[
|
169
|
-
ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER),
|
170
|
-
HasValue(Name, { name: "Alice" }),
|
171
|
-
ProxyRead(OwnedByEntity, 0),
|
172
|
-
NotValue(Name, { name: "Alice" }),
|
173
|
-
],
|
174
|
-
new Set([Player, Depth1, Depth2, Depth3, Depth4]), // Provide an initial set of entities
|
175
|
-
),
|
176
|
-
).toEqual(new Set([Depth1, Depth2, Depth3, Depth4]));
|
177
|
-
|
178
|
-
// Get all entities from the initial set [Depth3] that have an indirect owner called Alice and their direct child
|
179
|
-
expect(
|
180
|
-
runQuery(
|
181
|
-
[
|
182
|
-
ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER),
|
183
|
-
ProxyExpand(OwnedByEntity, 1),
|
184
|
-
HasValue(Name, { name: "Alice" }),
|
185
|
-
],
|
186
|
-
new Set([Depth2]), // Provide an initial set of entities
|
187
|
-
),
|
188
|
-
).toEqual(new Set([Depth2, Depth3]));
|
189
|
-
});
|
190
|
-
|
191
|
-
it("should return all entities with CanMove component on themselves or their Prototype", () => {
|
192
|
-
const proto = createEntity(world, [withValue(Prototype, { value: true }), withValue(CanMove, { value: true })]);
|
193
|
-
|
194
|
-
const instance1 = createEntity(world, [
|
195
|
-
withValue(FromPrototype, { value: proto }),
|
196
|
-
withValue(Position, { x: 1, y: 1 }),
|
197
|
-
]);
|
198
|
-
|
199
|
-
const instance2 = createEntity(world, [
|
200
|
-
withValue(FromPrototype, { value: proto }),
|
201
|
-
withValue(Position, { x: 1, y: 1 }),
|
202
|
-
]);
|
203
|
-
|
204
|
-
createEntity(world, [withValue(Position, { x: 1, y: 1 })]);
|
205
|
-
|
206
|
-
expect(runQuery([ProxyExpand(FromPrototype, 1), Has(CanMove), Not(Prototype)])).toEqual(
|
207
|
-
new Set([instance1, instance2]),
|
208
|
-
);
|
209
|
-
|
210
|
-
expect(runQuery([Has(Position), ProxyRead(FromPrototype, 1), Has(CanMove)])).toEqual(
|
211
|
-
new Set([instance1, instance2]),
|
212
|
-
);
|
213
|
-
|
214
|
-
expect(runQuery([ProxyRead(FromPrototype, 1), Has(Position), Has(CanMove)])).toEqual(
|
215
|
-
new Set([instance1, instance2]),
|
216
|
-
);
|
217
|
-
});
|
218
|
-
|
219
|
-
it("should return all entities with Position component that can't move", () => {
|
220
|
-
const proto = createEntity(world, [withValue(Prototype, { value: true }), withValue(CanMove, { value: true })]);
|
221
|
-
|
222
|
-
createEntity(world, [withValue(FromPrototype, { value: proto }), withValue(Position, { x: 1, y: 1 })]);
|
223
|
-
|
224
|
-
createEntity(world, [withValue(FromPrototype, { value: proto }), withValue(Position, { x: 1, y: 1 })]);
|
225
|
-
|
226
|
-
const entity3 = createEntity(world, [withValue(Position, { x: 1, y: 1 })]);
|
227
|
-
|
228
|
-
expect(runQuery([ProxyRead(FromPrototype, 1), Has(Position), Not(CanMove)])).toEqual(new Set([entity3]));
|
229
|
-
});
|
230
|
-
|
231
|
-
it("should return all movable entities not owned by Alice", () => {
|
232
|
-
const Player1 = createEntity(world, [withValue(Name, { name: "Alice" })]);
|
233
|
-
const Player2 = createEntity(world, [withValue(Name, { name: "Bob" })]);
|
234
|
-
const Proto1 = createEntity(world, [withValue(Prototype, { value: true }), withValue(CanMove, { value: true })]);
|
235
|
-
const Proto2 = createEntity(world, [withValue(Prototype, { value: true })]);
|
236
|
-
|
237
|
-
// Instance 1
|
238
|
-
createEntity(world, [
|
239
|
-
withValue(FromPrototype, { value: Proto1 }),
|
240
|
-
withValue(OwnedByEntity, { value: Player1 }),
|
241
|
-
withValue(Position, { x: 1, y: 1 }),
|
242
|
-
]);
|
243
|
-
|
244
|
-
// Instance 2
|
245
|
-
createEntity(world, [
|
246
|
-
withValue(FromPrototype, { value: Proto2 }),
|
247
|
-
withValue(OwnedByEntity, { value: Player1 }),
|
248
|
-
withValue(Position, { x: 1, y: 1 }),
|
249
|
-
]);
|
250
|
-
|
251
|
-
const Instance3 = createEntity(world, [
|
252
|
-
withValue(FromPrototype, { value: Proto1 }),
|
253
|
-
withValue(OwnedByEntity, { value: Player2 }),
|
254
|
-
withValue(Position, { x: 1, y: 1 }),
|
255
|
-
]);
|
256
|
-
|
257
|
-
// Instance 4
|
258
|
-
createEntity(world, [
|
259
|
-
withValue(FromPrototype, { value: Proto2 }),
|
260
|
-
withValue(OwnedByEntity, { value: Player2 }),
|
261
|
-
withValue(Position, { x: 1, y: 1 }),
|
262
|
-
]);
|
263
|
-
|
264
|
-
// Entity 5
|
265
|
-
createEntity(world, [withValue(OwnedByEntity, { value: Player1 }), withValue(Position, { x: 1, y: 1 })]);
|
266
|
-
|
267
|
-
// Entity 6
|
268
|
-
createEntity(world, [withValue(OwnedByEntity, { value: Player2 }), withValue(Position, { x: 1, y: 1 })]);
|
269
|
-
|
270
|
-
// Entity 7
|
271
|
-
createEntity(world, [
|
272
|
-
withValue(CanMove, { value: true }),
|
273
|
-
withValue(OwnedByEntity, { value: Player1 }),
|
274
|
-
withValue(Position, { x: 1, y: 1 }),
|
275
|
-
]);
|
276
|
-
|
277
|
-
const Entity8 = createEntity(world, [
|
278
|
-
withValue(CanMove, { value: true }),
|
279
|
-
withValue(OwnedByEntity, { value: Player2 }),
|
280
|
-
withValue(Position, { x: 1, y: 1 }),
|
281
|
-
]);
|
282
|
-
|
283
|
-
expect(
|
284
|
-
runQuery([
|
285
|
-
Has(Position), // All entities with position component...
|
286
|
-
ProxyRead(FromPrototype, 1), // ...that on themselves or their prototype...
|
287
|
-
Has(CanMove), // ...have the CanMove component...
|
288
|
-
ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), // ...and for whose owner holds...
|
289
|
-
NotValue(Name, { name: "Alice" }), // ...their name is not Alice
|
290
|
-
]),
|
291
|
-
).toEqual(new Set([Instance3, Entity8]));
|
292
|
-
});
|
293
|
-
|
294
|
-
// it("should be observable", () => {
|
295
|
-
// let queryRanTimes = 0;
|
296
|
-
// let valueQueryRanTimes = 0;
|
297
|
-
// const entity = createEntity(world);
|
298
|
-
// const query = runQuery([Has(Position)]);
|
299
|
-
// const valueQuery = runQuery([HasValue(Position, { x: 2, y: 2 })]);
|
300
|
-
|
301
|
-
// reaction(
|
302
|
-
// () => query.get(),
|
303
|
-
// () => {
|
304
|
-
// queryRanTimes++;
|
305
|
-
// }
|
306
|
-
// );
|
307
|
-
|
308
|
-
// reaction(
|
309
|
-
// () => valueQuery.get(),
|
310
|
-
// () => {
|
311
|
-
// valueQueryRanTimes++;
|
312
|
-
// }
|
313
|
-
// );
|
314
|
-
|
315
|
-
// setComponent(Position, entity, { x: 2, y: 3 });
|
316
|
-
// expect(queryRanTimes).toBe(1);
|
317
|
-
// expect(valueQueryRanTimes).toBe(1);
|
318
|
-
|
319
|
-
// setComponent(Position, entity, { x: 2, y: 2 });
|
320
|
-
// expect(queryRanTimes).toBe(1);
|
321
|
-
// expect(valueQueryRanTimes).toBe(2);
|
322
|
-
|
323
|
-
// removeComponent(Position, entity);
|
324
|
-
// expect(queryRanTimes).toBe(2);
|
325
|
-
// expect(valueQueryRanTimes).toBe(3);
|
326
|
-
// });
|
327
|
-
});
|
328
|
-
|
329
|
-
describe("defineEnterQuery", () => {
|
330
|
-
it("should only return newly added entities", () => {
|
331
|
-
const enterQuery = defineEnterQuery([Has(CanMove)]);
|
332
|
-
const entities: Entity[] = [];
|
333
|
-
|
334
|
-
const mock = jest.fn();
|
335
|
-
enterQuery.subscribe(mock);
|
336
|
-
|
337
|
-
entities.push(createEntity(world, [withValue(CanMove, { value: true })]));
|
338
|
-
entities.push(createEntity(world, [withValue(CanMove, { value: true })]));
|
339
|
-
entities.push(createEntity(world));
|
340
|
-
|
341
|
-
expect(mock).toHaveBeenCalledWith(
|
342
|
-
expect.objectContaining({
|
343
|
-
entity: entities[0],
|
344
|
-
component: CanMove,
|
345
|
-
value: [{ value: true }, undefined],
|
346
|
-
}),
|
347
|
-
);
|
348
|
-
expect(mock).toHaveBeenCalledWith(
|
349
|
-
expect.objectContaining({
|
350
|
-
entity: entities[1],
|
351
|
-
component: CanMove,
|
352
|
-
value: [{ value: true }, undefined],
|
353
|
-
}),
|
354
|
-
);
|
355
|
-
expect(mock).toBeCalledTimes(2);
|
356
|
-
|
357
|
-
setComponent(CanMove, entities[2], { value: true });
|
358
|
-
expect(mock).toHaveBeenCalledWith(
|
359
|
-
expect.objectContaining({
|
360
|
-
entity: entities[2],
|
361
|
-
component: CanMove,
|
362
|
-
value: [{ value: true }, undefined],
|
363
|
-
}),
|
364
|
-
);
|
365
|
-
expect(mock).toHaveBeenCalledTimes(3);
|
366
|
-
});
|
367
|
-
});
|
368
|
-
|
369
|
-
describe("defineExitQuery", () => {
|
370
|
-
it("should only return removed entities", () => {
|
371
|
-
const exitQuery = defineExitQuery([Has(CanMove)]);
|
372
|
-
|
373
|
-
const mock = jest.fn();
|
374
|
-
exitQuery.subscribe(mock);
|
375
|
-
|
376
|
-
const entity1 = createEntity(world, [withValue(CanMove, { value: true })]);
|
377
|
-
const entity2 = createEntity(world);
|
378
|
-
|
379
|
-
setComponent(CanMove, entity2, { value: true });
|
380
|
-
|
381
|
-
expect(mock).toHaveBeenCalledTimes(0);
|
382
|
-
|
383
|
-
removeComponent(CanMove, entity1);
|
384
|
-
expect(mock).toHaveBeenCalledTimes(1);
|
385
|
-
|
386
|
-
expect(mock).toHaveBeenCalledWith(
|
387
|
-
expect.objectContaining({
|
388
|
-
entity: entity1,
|
389
|
-
component: CanMove,
|
390
|
-
value: [undefined, { value: true }],
|
391
|
-
}),
|
392
|
-
);
|
393
|
-
|
394
|
-
removeComponent(CanMove, entity2);
|
395
|
-
expect(mock).toHaveBeenCalledTimes(2);
|
396
|
-
expect(mock).toHaveBeenCalledWith(
|
397
|
-
expect.objectContaining({
|
398
|
-
entity: entity2,
|
399
|
-
component: CanMove,
|
400
|
-
value: [undefined, { value: true }],
|
401
|
-
}),
|
402
|
-
);
|
403
|
-
});
|
404
|
-
});
|
405
|
-
|
406
|
-
describe("defineUpdateQuery", () => {
|
407
|
-
it("should only return the last updated entity", () => {
|
408
|
-
const updateQuery = defineQuery([Has(Position)]);
|
409
|
-
|
410
|
-
const mock = jest.fn();
|
411
|
-
updateQuery.update$.subscribe(mock);
|
412
|
-
|
413
|
-
const entity1 = createEntity(world, [withValue(Position, { x: 1, y: 2 })]);
|
414
|
-
const entity2 = createEntity(world, [withValue(Position, { x: 1, y: 3 })]);
|
415
|
-
|
416
|
-
expect(mock).toHaveBeenCalledTimes(2);
|
417
|
-
|
418
|
-
expect(mock).toHaveBeenCalledWith({
|
419
|
-
entity: entity1,
|
420
|
-
value: [{ x: 1, y: 2 }, undefined],
|
421
|
-
component: Position,
|
422
|
-
type: UpdateType.Enter,
|
423
|
-
});
|
424
|
-
|
425
|
-
expect(mock).toHaveBeenCalledWith({
|
426
|
-
entity: entity2,
|
427
|
-
value: [{ x: 1, y: 3 }, undefined],
|
428
|
-
component: Position,
|
429
|
-
type: UpdateType.Enter,
|
430
|
-
});
|
431
|
-
|
432
|
-
setComponent(Position, entity1, { x: 2, y: 3 });
|
433
|
-
|
434
|
-
expect(mock).toHaveBeenCalledWith({
|
435
|
-
entity: entity1,
|
436
|
-
value: [
|
437
|
-
{ x: 2, y: 3 },
|
438
|
-
{ x: 1, y: 2 },
|
439
|
-
],
|
440
|
-
component: Position,
|
441
|
-
type: UpdateType.Update,
|
442
|
-
});
|
443
|
-
|
444
|
-
expect(mock).toHaveBeenCalledTimes(3);
|
445
|
-
|
446
|
-
removeComponent(Position, entity1);
|
447
|
-
|
448
|
-
expect(mock).toHaveBeenCalledWith({
|
449
|
-
entity: entity1,
|
450
|
-
value: [undefined, { x: 2, y: 3 }],
|
451
|
-
component: Position,
|
452
|
-
type: UpdateType.Exit,
|
453
|
-
});
|
454
|
-
|
455
|
-
expect(mock).toHaveBeenCalledTimes(4);
|
456
|
-
});
|
457
|
-
|
458
|
-
it("should not return entities matching the query before the query was subscribed to if runOnInit is undefined/false", () => {
|
459
|
-
const updateQuery = defineQuery([Has(Position)]);
|
460
|
-
const entity = createEntity(world, [withValue(Position, { x: 1, y: 2 })]);
|
461
|
-
|
462
|
-
const mock = jest.fn();
|
463
|
-
updateQuery.update$.subscribe(mock);
|
464
|
-
|
465
|
-
expect(mock).not.toHaveBeenCalled();
|
466
|
-
|
467
|
-
setComponent(Position, entity, { x: 1, y: 3 });
|
468
|
-
|
469
|
-
expect(mock).toHaveBeenCalledWith({
|
470
|
-
entity,
|
471
|
-
value: [
|
472
|
-
{ x: 1, y: 3 },
|
473
|
-
{ x: 1, y: 2 },
|
474
|
-
],
|
475
|
-
component: Position,
|
476
|
-
type: UpdateType.Enter,
|
477
|
-
});
|
478
|
-
|
479
|
-
expect(mock).toHaveBeenCalledTimes(1);
|
480
|
-
});
|
481
|
-
|
482
|
-
// it("should return entities matching the query before the query was defined if runOnInit is true", () => {
|
483
|
-
// const entity1 = createEntity(world, [withValue(Position, { x: 1, y: 2 })]);
|
484
|
-
// const entity2 = createEntity(world, [withValue(Position, { x: 4, y: 2 })]);
|
485
|
-
// const updateQuery = defineUpdateQuery([Has(Position)], { runOnInit: true });
|
486
|
-
|
487
|
-
// const mock = jest.fn();
|
488
|
-
// updateQuery.update$.subscribe(mock);
|
489
|
-
|
490
|
-
// expect(mock).toHaveBeenNthCalledWith(1, {
|
491
|
-
// entity: entity1,
|
492
|
-
// value: [{ x: 1, y: 2 }, undefined],
|
493
|
-
// component: Position,
|
494
|
-
// type: QueryUpdate.Enter,
|
495
|
-
// });
|
496
|
-
|
497
|
-
// expect(mock).toHaveBeenNthCalledWith(2, {
|
498
|
-
// entity: entity2,
|
499
|
-
// value: [{ x: 4, y: 2 }, undefined],
|
500
|
-
// component: Position,
|
501
|
-
// type: QueryUpdate.Enter,
|
502
|
-
// });
|
503
|
-
|
504
|
-
// expect(mock).toHaveBeenCalledTimes(2);
|
505
|
-
|
506
|
-
// const entity3 = createEntity(world, [withValue(Position, { x: 1, y: 3 })]);
|
507
|
-
|
508
|
-
// expect(mock).toHaveBeenNthCalledWith(3, {
|
509
|
-
// entity: entity3,
|
510
|
-
// value: [{ x: 1, y: 3 }, undefined],
|
511
|
-
// component: Position,
|
512
|
-
// type: QueryUpdate.Enter,
|
513
|
-
// });
|
514
|
-
|
515
|
-
// expect(mock).toHaveBeenCalledTimes(3);
|
516
|
-
// });
|
517
|
-
|
518
|
-
it("should work with queries including multiple components", () => {
|
519
|
-
const updateQuery = defineQuery([Has(Position), Has(CanMove)]);
|
520
|
-
|
521
|
-
const mock = jest.fn();
|
522
|
-
updateQuery.update$.subscribe(mock);
|
523
|
-
|
524
|
-
const entity1 = createEntity(world, [withValue(Position, { x: 1, y: 2 }), withValue(CanMove, { value: true })]);
|
525
|
-
const entity2 = createEntity(world, [withValue(Position, { x: 4, y: 2 })]);
|
526
|
-
|
527
|
-
expect(mock).toHaveBeenCalledTimes(1);
|
528
|
-
|
529
|
-
expect(mock).toHaveBeenNthCalledWith(1, {
|
530
|
-
entity: entity1,
|
531
|
-
value: [{ value: true }, undefined],
|
532
|
-
component: CanMove,
|
533
|
-
type: UpdateType.Enter,
|
534
|
-
});
|
535
|
-
|
536
|
-
setComponent(CanMove, entity2, { value: true });
|
537
|
-
|
538
|
-
expect(mock).toHaveBeenCalledTimes(2);
|
539
|
-
|
540
|
-
expect(mock).toHaveBeenNthCalledWith(2, {
|
541
|
-
entity: entity2,
|
542
|
-
value: [{ value: true }, undefined],
|
543
|
-
component: CanMove,
|
544
|
-
type: UpdateType.Enter,
|
545
|
-
});
|
546
|
-
|
547
|
-
setComponent(Position, entity1, { x: 2, y: 4 });
|
548
|
-
|
549
|
-
expect(mock).toHaveBeenCalledTimes(3);
|
550
|
-
|
551
|
-
expect(mock).toHaveBeenNthCalledWith(3, {
|
552
|
-
entity: entity1,
|
553
|
-
value: [
|
554
|
-
{ x: 2, y: 4 },
|
555
|
-
{ x: 1, y: 2 },
|
556
|
-
],
|
557
|
-
component: Position,
|
558
|
-
type: UpdateType.Update,
|
559
|
-
});
|
560
|
-
});
|
561
|
-
});
|
562
|
-
|
563
|
-
describe("defineQuery", () => {
|
564
|
-
it("should return all player owned entities up to the given depth", () => {
|
565
|
-
const Player = createEntity(world);
|
566
|
-
const Depth1 = createEntity(world);
|
567
|
-
const Depth2 = createEntity(world);
|
568
|
-
const Depth3 = createEntity(world);
|
569
|
-
const Depth4 = createEntity(world);
|
570
|
-
const Depth5 = createEntity(world);
|
571
|
-
|
572
|
-
const query1 = defineQuery([HasValue(OwnedByEntity, { value: Player })]);
|
573
|
-
query1.update$.subscribe();
|
574
|
-
|
575
|
-
const query2 = defineQuery([ProxyExpand(OwnedByEntity, 0), HasValue(OwnedByEntity, { value: Player })]);
|
576
|
-
query2.update$.subscribe();
|
577
|
-
|
578
|
-
const query3 = defineQuery([ProxyExpand(OwnedByEntity, 1), HasValue(OwnedByEntity, { value: Player })]);
|
579
|
-
query3.update$.subscribe();
|
580
|
-
|
581
|
-
const query4 = defineQuery([ProxyExpand(OwnedByEntity, 2), HasValue(OwnedByEntity, { value: Player })]);
|
582
|
-
query4.update$.subscribe();
|
583
|
-
|
584
|
-
const query5 = defineQuery([ProxyExpand(OwnedByEntity, 3), HasValue(OwnedByEntity, { value: Player })]);
|
585
|
-
query5.update$.subscribe();
|
586
|
-
|
587
|
-
const query6 = defineQuery([ProxyExpand(OwnedByEntity, 4), HasValue(OwnedByEntity, { value: Player })]);
|
588
|
-
query6.update$.subscribe();
|
589
|
-
|
590
|
-
const query7 = defineQuery([
|
591
|
-
ProxyExpand(OwnedByEntity, Number.MAX_SAFE_INTEGER),
|
592
|
-
HasValue(OwnedByEntity, { value: Player }),
|
593
|
-
]);
|
594
|
-
query7.update$.subscribe();
|
595
|
-
|
596
|
-
setComponent(OwnedByEntity, Depth1, { value: Player });
|
597
|
-
setComponent(OwnedByEntity, Depth2, { value: Depth1 });
|
598
|
-
setComponent(OwnedByEntity, Depth3, { value: Depth2 });
|
599
|
-
setComponent(OwnedByEntity, Depth4, { value: Depth3 });
|
600
|
-
setComponent(OwnedByEntity, Depth5, { value: Depth4 });
|
601
|
-
|
602
|
-
expect(new Set([...query1.matching])).toEqual(new Set([Depth1]));
|
603
|
-
expect(new Set([...query2.matching])).toEqual(new Set([Depth1]));
|
604
|
-
expect(new Set([...query3.matching])).toEqual(new Set([Depth1, Depth2]));
|
605
|
-
expect(new Set([...query4.matching])).toEqual(new Set([Depth1, Depth2, Depth3]));
|
606
|
-
expect(new Set([...query5.matching])).toEqual(new Set([Depth1, Depth2, Depth3, Depth4]));
|
607
|
-
expect(new Set([...query6.matching])).toEqual(new Set([Depth1, Depth2, Depth3, Depth4, Depth5]));
|
608
|
-
expect(new Set([...query7.matching])).toEqual(new Set([Depth1, Depth2, Depth3, Depth4, Depth5]));
|
609
|
-
});
|
610
|
-
|
611
|
-
it("should return entites owned by an entity with Name component Alice", () => {
|
612
|
-
const Player = createEntity(world);
|
613
|
-
const Depth1 = createEntity(world);
|
614
|
-
const Depth2 = createEntity(world);
|
615
|
-
const Depth3 = createEntity(world);
|
616
|
-
const Depth4 = createEntity(world);
|
617
|
-
|
618
|
-
const query1 = defineQuery(
|
619
|
-
[ProxyRead(OwnedByEntity, 1), HasValue(Name, { name: "Alice" })],
|
620
|
-
{ initialSet: new Set([Depth1, Depth2, Depth3]) }, // Provide an initial set of entities
|
621
|
-
);
|
622
|
-
query1.update$.subscribe();
|
623
|
-
|
624
|
-
const query2 = defineQuery([
|
625
|
-
ProxyExpand(OwnedByEntity, 1), // Turn on proxy expand
|
626
|
-
HasValue(Name, { name: "Alice" }), // Get all entities with name Alice or owned by Alice
|
627
|
-
ProxyExpand(OwnedByEntity, 0), // Turn off proxy expand
|
628
|
-
NotValue(Name, { name: "Alice" }), // Filter Alice, only keep entities owned by Alice
|
629
|
-
]);
|
630
|
-
query2.update$.subscribe();
|
631
|
-
|
632
|
-
const query3 = defineQuery([
|
633
|
-
ProxyExpand(OwnedByEntity, Number.MAX_SAFE_INTEGER), // Include all child entities
|
634
|
-
HasValue(Name, { name: "Alice" }), // Get all child entities of Alice (including alice)
|
635
|
-
ProxyExpand(OwnedByEntity, 0), // Turn off proxy expand
|
636
|
-
NotValue(Name, { name: "Alice" }), // Filter Alice, only keep entities owned by Alice
|
637
|
-
]);
|
638
|
-
query3.update$.subscribe();
|
639
|
-
|
640
|
-
const query4 = defineQuery(
|
641
|
-
[ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(Name, { name: "Alice" })],
|
642
|
-
{ initialSet: new Set([Depth3]) }, // Provide an initial set of entities
|
643
|
-
);
|
644
|
-
query4.update$.subscribe();
|
645
|
-
|
646
|
-
const query5 = defineQuery(
|
647
|
-
[
|
648
|
-
ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER),
|
649
|
-
HasValue(Name, { name: "Alice" }),
|
650
|
-
ProxyRead(OwnedByEntity, 0),
|
651
|
-
NotValue(Name, { name: "Alice" }),
|
652
|
-
],
|
653
|
-
{ initialSet: new Set([Player, Depth1, Depth2, Depth3, Depth4]) }, // Provide an initial set of entities
|
654
|
-
);
|
655
|
-
query5.update$.subscribe();
|
656
|
-
|
657
|
-
const query6 = defineQuery(
|
658
|
-
[
|
659
|
-
ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER),
|
660
|
-
ProxyExpand(OwnedByEntity, 1),
|
661
|
-
HasValue(Name, { name: "Alice" }),
|
662
|
-
],
|
663
|
-
{ initialSet: new Set([Depth2]) }, // Provide an initial set of entities
|
664
|
-
);
|
665
|
-
query6.update$.subscribe();
|
666
|
-
|
667
|
-
setComponent(Name, Player, { name: "Alice" });
|
668
|
-
setComponent(OwnedByEntity, Depth1, { value: Player });
|
669
|
-
setComponent(OwnedByEntity, Depth2, { value: Depth1 });
|
670
|
-
setComponent(OwnedByEntity, Depth3, { value: Depth2 });
|
671
|
-
setComponent(OwnedByEntity, Depth4, { value: Depth3 });
|
672
|
-
|
673
|
-
expect(new Set([...query1.matching])).toEqual(new Set([Depth1]));
|
674
|
-
expect(new Set([...query2.matching])).toEqual(new Set([Depth1]));
|
675
|
-
expect(new Set([...query3.matching])).toEqual(new Set([Depth1, Depth2, Depth3, Depth4]));
|
676
|
-
|
677
|
-
// Get all entities from the initial set [Depth3] that have an indirect owner called Alice
|
678
|
-
expect(new Set([...query4.matching])).toEqual(new Set([Depth3]));
|
679
|
-
|
680
|
-
// Get all entities that have an indirect owner called Alice
|
681
|
-
expect(new Set([...query5.matching])).toEqual(new Set([Depth1, Depth2, Depth3, Depth4]));
|
682
|
-
|
683
|
-
// Get all entities from the initial set [Depth3] that have an indirect owner called Alice and their direct child
|
684
|
-
expect(new Set([...query6.matching])).toEqual(new Set([Depth2, Depth3]));
|
685
|
-
});
|
686
|
-
|
687
|
-
it("should return all entities with CanMove component on themselves or their Prototype", () => {
|
688
|
-
const proto = createEntity(world);
|
689
|
-
|
690
|
-
const instance1 = createEntity(world);
|
691
|
-
const instance2 = createEntity(world);
|
692
|
-
|
693
|
-
const instance3 = createEntity(world);
|
694
|
-
|
695
|
-
const query1 = defineQuery([ProxyExpand(FromPrototype, 1), Has(CanMove), Not(Prototype)]);
|
696
|
-
query1.update$.subscribe();
|
697
|
-
const query2 = defineQuery([Has(Position), ProxyRead(FromPrototype, 1), Has(CanMove)]);
|
698
|
-
query2.update$.subscribe();
|
699
|
-
const query3 = defineQuery([ProxyRead(FromPrototype, 1), Has(Position), Has(CanMove)]);
|
700
|
-
query3.update$.subscribe();
|
701
|
-
|
702
|
-
setComponent(Prototype, proto, { value: true });
|
703
|
-
setComponent(CanMove, proto, { value: true });
|
704
|
-
|
705
|
-
setComponent(FromPrototype, instance1, { value: proto });
|
706
|
-
setComponent(Position, instance1, { x: 1, y: 1 });
|
707
|
-
|
708
|
-
setComponent(FromPrototype, instance2, { value: proto });
|
709
|
-
setComponent(Position, instance2, { x: 1, y: 1 });
|
710
|
-
|
711
|
-
setComponent(Position, instance3, { x: 1, y: 1 });
|
712
|
-
|
713
|
-
expect(new Set([...query1.matching])).toEqual(new Set([instance1, instance2]));
|
714
|
-
expect(new Set([...query2.matching])).toEqual(new Set([instance1, instance2]));
|
715
|
-
expect(new Set([...query3.matching])).toEqual(new Set([instance1, instance2]));
|
716
|
-
});
|
717
|
-
|
718
|
-
it("should return all entities with Position component that can't move", () => {
|
719
|
-
const proto = createEntity(world);
|
720
|
-
const entity1 = createEntity(world);
|
721
|
-
const entity2 = createEntity(world);
|
722
|
-
const entity3 = createEntity(world);
|
723
|
-
|
724
|
-
const query = defineQuery([ProxyRead(FromPrototype, 1), Has(Position), Not(CanMove)]);
|
725
|
-
query.update$.subscribe();
|
726
|
-
|
727
|
-
setComponent(Prototype, proto, { value: true });
|
728
|
-
setComponent(CanMove, proto, { value: true });
|
729
|
-
|
730
|
-
setComponent(FromPrototype, entity1, { value: proto });
|
731
|
-
setComponent(Position, entity1, { x: 1, y: 1 });
|
732
|
-
|
733
|
-
setComponent(FromPrototype, entity2, { value: proto });
|
734
|
-
setComponent(Position, entity2, { x: 1, y: 1 });
|
735
|
-
|
736
|
-
setComponent(Position, entity3, { x: 1, y: 1 });
|
737
|
-
|
738
|
-
expect(new Set([...query.matching])).toEqual(new Set([entity3]));
|
739
|
-
});
|
740
|
-
|
741
|
-
it("should return all movable entities not owned by Alice", () => {
|
742
|
-
const Player1 = createEntity(world);
|
743
|
-
const Player2 = createEntity(world);
|
744
|
-
const Proto1 = createEntity(world);
|
745
|
-
const Proto2 = createEntity(world);
|
746
|
-
const Instance1 = createEntity(world);
|
747
|
-
const Instance2 = createEntity(world);
|
748
|
-
const Instance3 = createEntity(world);
|
749
|
-
const Instance4 = createEntity(world);
|
750
|
-
const Entity5 = createEntity(world);
|
751
|
-
const Entity6 = createEntity(world);
|
752
|
-
const Entity7 = createEntity(world);
|
753
|
-
const Entity8 = createEntity(world);
|
754
|
-
|
755
|
-
const query = defineQuery([
|
756
|
-
Has(Position), // All entities with position component...
|
757
|
-
ProxyRead(FromPrototype, 1), // ...that on themselves or their prototype...
|
758
|
-
Has(CanMove), // ...have the CanMove component...
|
759
|
-
ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), // ...and for whose owner holds...
|
760
|
-
NotValue(Name, { name: "Alice" }), // ...their name is not Alice
|
761
|
-
]);
|
762
|
-
query.update$.subscribe();
|
763
|
-
|
764
|
-
setComponent(Name, Player1, { name: "Alice" });
|
765
|
-
setComponent(Name, Player2, { name: "Bob" });
|
766
|
-
setComponent(Prototype, Proto1, { value: true });
|
767
|
-
setComponent(CanMove, Proto1, { value: true });
|
768
|
-
setComponent(Prototype, Proto2, { value: true });
|
769
|
-
|
770
|
-
// Instance 1
|
771
|
-
setComponent(FromPrototype, Instance1, { value: Proto1 });
|
772
|
-
setComponent(OwnedByEntity, Instance1, { value: Player1 });
|
773
|
-
setComponent(Position, Instance1, { x: 1, y: 1 });
|
774
|
-
|
775
|
-
// Instance 2
|
776
|
-
setComponent(FromPrototype, Instance2, { value: Proto2 });
|
777
|
-
setComponent(OwnedByEntity, Instance2, { value: Player1 });
|
778
|
-
setComponent(Position, Instance2, { x: 1, y: 1 });
|
779
|
-
|
780
|
-
// Instance 3
|
781
|
-
setComponent(FromPrototype, Instance3, { value: Proto1 });
|
782
|
-
setComponent(OwnedByEntity, Instance3, { value: Player2 });
|
783
|
-
setComponent(Position, Instance3, { x: 1, y: 1 });
|
784
|
-
|
785
|
-
// Instance 4
|
786
|
-
setComponent(FromPrototype, Instance4, { value: Proto2 });
|
787
|
-
setComponent(OwnedByEntity, Instance4, { value: Player2 });
|
788
|
-
setComponent(Position, Instance4, { x: 1, y: 1 });
|
789
|
-
|
790
|
-
// Entity 5
|
791
|
-
setComponent(OwnedByEntity, Entity5, { value: Player1 });
|
792
|
-
setComponent(Position, Entity5, { x: 1, y: 1 });
|
793
|
-
|
794
|
-
// Entity 6
|
795
|
-
setComponent(OwnedByEntity, Entity6, { value: Player2 });
|
796
|
-
setComponent(Position, Entity6, { x: 1, y: 1 });
|
797
|
-
|
798
|
-
// Entity 7
|
799
|
-
setComponent(CanMove, Entity7, { value: true });
|
800
|
-
setComponent(OwnedByEntity, Entity7, { value: Player1 });
|
801
|
-
setComponent(Position, Entity7, { x: 1, y: 1 });
|
802
|
-
|
803
|
-
// Entity 8
|
804
|
-
setComponent(CanMove, Entity8, { value: true });
|
805
|
-
setComponent(OwnedByEntity, Entity8, { value: Player2 });
|
806
|
-
setComponent(Position, Entity8, { x: 1, y: 1 });
|
807
|
-
|
808
|
-
expect(new Set([...query.matching])).toEqual(new Set([Instance3, Entity8]));
|
809
|
-
});
|
810
|
-
});
|
811
|
-
});
|