@latticexyz/recs 2.0.12-main-9be2bb86 → 2.0.12-main-e43c0938

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/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
- });