@latticexyz/recs 2.0.0-transaction-context-324984c5 → 2.0.1-main-4a6b4598

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 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]) // Provide an initial set of entities
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]) // Provide an initial set of entities
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]) // Provide an initial set of entities
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]) // Provide an initial set of entities
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]) } // Provide an initial set of entities
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]) } // Provide an initial set of entities
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]) } // Provide an initial set of entities
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]) } // Provide an initial set of entities
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, Subject } from "rxjs";
3
+ import { concat, concatMap, filter, from, map, merge, Observable, of, share } from "rxjs";
4
4
  import {
5
5
  componentValueEquals,
6
6
  getComponentEntities,
@@ -15,7 +15,6 @@ import {
15
15
  ComponentValue,
16
16
  Entity,
17
17
  EntityQueryFragment,
18
- EntitySymbol,
19
18
  HasQueryFragment,
20
19
  HasValueQueryFragment,
21
20
  NotQueryFragment,
@@ -88,7 +87,7 @@ export function Not<T extends Schema>(component: Component<T>): NotQueryFragment
88
87
  */
89
88
  export function HasValue<T extends Schema>(
90
89
  component: Component<T>,
91
- value: Partial<ComponentValue<T>>
90
+ value: Partial<ComponentValue<T>>,
92
91
  ): HasValueQueryFragment<T> {
93
92
  return { type: QueryFragmentType.HasValue, component, value };
94
93
  }
@@ -112,7 +111,7 @@ export function HasValue<T extends Schema>(
112
111
  */
113
112
  export function NotValue<T extends Schema>(
114
113
  component: Component<T>,
115
- value: Partial<ComponentValue<T>>
114
+ value: Partial<ComponentValue<T>>,
116
115
  ): NotValueQueryFragment<T> {
117
116
  return { type: QueryFragmentType.NotValue, component, value };
118
117
  }
@@ -199,7 +198,7 @@ function passesQueryFragment<T extends Schema>(entity: Entity, fragment: EntityQ
199
198
  * @returns True if the query fragment is positive, else false.
200
199
  */
201
200
  function isPositiveFragment<T extends Schema>(
202
- fragment: QueryFragment<T>
201
+ fragment: QueryFragment<T>,
203
202
  ): fragment is HasQueryFragment<T> | HasValueQueryFragment<T> {
204
203
  return fragment.type === QueryFragmentType.Has || fragment.type == QueryFragmentType.HasValue;
205
204
  }
@@ -211,7 +210,7 @@ function isPositiveFragment<T extends Schema>(
211
210
  * @returns True if the query fragment is negative, else false.
212
211
  */
213
212
  function isNegativeFragment<T extends Schema>(
214
- fragment: QueryFragment<T>
213
+ fragment: QueryFragment<T>,
215
214
  ): fragment is NotQueryFragment<T> | NotValueQueryFragment<T> {
216
215
  return fragment.type === QueryFragmentType.Not || fragment.type == QueryFragmentType.NotValue;
217
216
  }
@@ -253,7 +252,7 @@ function isBreakingPassState(passes: boolean, fragment: EntityQueryFragment<Sche
253
252
  function passesQueryFragmentProxy<T extends Schema>(
254
253
  entity: Entity,
255
254
  fragment: EntityQueryFragment<T>,
256
- proxyRead: ProxyReadQueryFragment
255
+ proxyRead: ProxyReadQueryFragment,
257
256
  ): boolean | null {
258
257
  let proxyEntity = entity;
259
258
  let passes = false;
@@ -288,7 +287,7 @@ function passesQueryFragmentProxy<T extends Schema>(
288
287
  export function getChildEntities(
289
288
  entity: Entity,
290
289
  component: Component<{ value: Type.Entity }>,
291
- depth: number
290
+ depth: number,
292
291
  ): Set<Entity> {
293
292
  if (depth === 0) return new Set();
294
293
 
@@ -416,7 +415,7 @@ export function runQuery(fragments: QueryFragment[], initialSet?: Set<Entity>):
416
415
  */
417
416
  export function defineQuery(
418
417
  fragments: QueryFragment[],
419
- options?: { runOnInit?: boolean; initialSet?: Set<Entity> }
418
+ options?: { runOnInit?: boolean; initialSet?: Set<Entity> },
420
419
  ): {
421
420
  update$: Observable<ComponentUpdate & { type: UpdateType }>;
422
421
  matching: ObservableSet<Entity>;
@@ -503,7 +502,7 @@ export function defineQuery(
503
502
  return { ...update, type: UpdateType.Enter };
504
503
  }
505
504
  }),
506
- filterNullish()
505
+ filterNullish(),
507
506
  );
508
507
 
509
508
  return {
@@ -521,7 +520,7 @@ export function defineQuery(
521
520
  */
522
521
  export function defineUpdateQuery(
523
522
  fragments: QueryFragment[],
524
- options?: { runOnInit?: boolean }
523
+ options?: { runOnInit?: boolean },
525
524
  ): Observable<ComponentUpdate & { type: UpdateType }> {
526
525
  return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Update));
527
526
  }
@@ -535,7 +534,7 @@ export function defineUpdateQuery(
535
534
  */
536
535
  export function defineEnterQuery(
537
536
  fragments: QueryFragment[],
538
- options?: { runOnInit?: boolean }
537
+ options?: { runOnInit?: boolean },
539
538
  ): Observable<ComponentUpdate> {
540
539
  return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Enter));
541
540
  }
@@ -549,7 +548,7 @@ export function defineEnterQuery(
549
548
  */
550
549
  export function defineExitQuery(
551
550
  fragments: QueryFragment[],
552
- options?: { runOnInit?: boolean }
551
+ options?: { runOnInit?: boolean },
553
552
  ): Observable<ComponentUpdate> {
554
553
  return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Exit));
555
554
  }
@@ -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 },
@@ -6,7 +6,7 @@ import { Component, Metadata, Entity, ComponentValue, Schema } from "../types";
6
6
  export function waitForComponentValueIn<S extends Schema, T>(
7
7
  component: Component<S, Metadata, T>,
8
8
  entity: Entity,
9
- values: Partial<ComponentValue<S>>[]
9
+ values: Partial<ComponentValue<S>>[],
10
10
  ): Promise<void> {
11
11
  const [resolve, , promise] = deferred<void>();
12
12
 
@@ -19,13 +19,13 @@ export function waitForComponentValueIn<S extends Schema, T>(
19
19
 
20
20
  const value$ = component.update$.pipe(
21
21
  filter((update) => update.entity === entity), // Ignore updates of other entities
22
- map((update) => update.value[0]) // Map the update to the current value
22
+ map((update) => update.value[0]), // Map the update to the current value
23
23
  );
24
24
 
25
25
  const subscription = value$
26
26
  .pipe(
27
27
  startWith(getComponentValue(component, entity)),
28
- filter((currentValue) => Boolean(values.find((searchValue) => componentValueEquals(searchValue, currentValue))))
28
+ filter((currentValue) => Boolean(values.find((searchValue) => componentValueEquals(searchValue, currentValue)))),
29
29
  )
30
30
  .subscribe(() => {
31
31
  resolve();
package/src/utils.ts CHANGED
@@ -12,7 +12,7 @@ import { Component, ComponentUpdate, ComponentValue, Entity, Indexer, Schema } f
12
12
  */
13
13
  export function isComponentUpdate<S extends Schema>(
14
14
  update: ComponentUpdate,
15
- component: Component<S>
15
+ component: Component<S>,
16
16
  ): update is ComponentUpdate<S> {
17
17
  return update.component === component;
18
18
  }
@@ -62,7 +62,7 @@ export function isIndexer<S extends Schema>(c: Component<S> | Indexer<S>): c is
62
62
  */
63
63
  export function isFullComponentValue<S extends Schema>(
64
64
  component: Component<S>,
65
- value: Partial<ComponentValue<S>>
65
+ value: Partial<ComponentValue<S>>,
66
66
  ): value is ComponentValue<S> {
67
67
  return Object.keys(component.schema).every((key) => key in value);
68
68
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/Component.ts","../src/Indexer.ts","../src/utils.ts","../src/Entity.ts"],"sourcesContent":["/**\n * Type enum is used to specify value types in {@link ComponentSchema} to be able\n * to access type values in JavaScript in addition to TypeScript type checks.\n */\nexport enum Type {\n Boolean,\n Number,\n OptionalNumber,\n BigInt,\n OptionalBigInt,\n String,\n OptionalString,\n NumberArray,\n OptionalNumberArray,\n BigIntArray,\n OptionalBigIntArray,\n StringArray,\n OptionalStringArray,\n Entity,\n OptionalEntity,\n EntityArray,\n OptionalEntityArray,\n T,\n OptionalT,\n}\n\n/**\n * Used to specify type of {@link ComponentUpdate}.\n * - Enter: Update added a value to an entity that did not have a value before\n * - Exit: Update removed a value from an entity that had a value before\n * - Update: Update changed a value of an entity that already had a value before. Note: the value doesn't need to be different from the previous value.\n * - Noop: Update did nothing (removed a value from an entity that did not have a value)\n */\nexport enum UpdateType {\n Enter,\n Exit,\n Update,\n Noop,\n}\n\n/**\n * Helper constant with all optional {@link Type}s.\n */\nexport const OptionalTypes = [\n Type.OptionalEntity,\n Type.OptionalEntityArray,\n Type.OptionalNumber,\n Type.OptionalNumberArray,\n Type.OptionalBigInt,\n Type.OptionalBigIntArray,\n Type.OptionalString,\n Type.OptionalStringArray,\n Type.OptionalT,\n];\n","import { transformIterator, uuid } from \"@latticexyz/utils\";\nimport { mapObject } from \"@latticexyz/utils\";\nimport { filter, map, Subject } from \"rxjs\";\nimport { OptionalTypes } from \"./constants\";\nimport { createIndexer } from \"./Indexer\";\nimport {\n Component,\n ComponentValue,\n Entity,\n EntitySymbol,\n Indexer,\n Metadata,\n OverridableComponent,\n Override,\n Schema,\n World,\n} from \"./types\";\nimport { isFullComponentValue, isIndexer } from \"./utils\";\nimport { getEntityString, getEntitySymbol } from \"./Entity\";\n\nexport type ComponentMutationOptions = {\n /** Skip publishing this mutation to the component's update stream. Mostly used internally during initial hydration. */\n skipUpdateStream?: boolean;\n};\n\nfunction getComponentName(component: Component<any, any, any>) {\n return (\n component.metadata?.componentName ??\n component.metadata?.tableName ??\n component.metadata?.tableId ??\n component.metadata?.contractId ??\n component.id\n );\n}\n\n/**\n * Components contain state indexed by entities and are one of the fundamental building blocks in ECS.\n * Besides containing the state, components expose an rxjs update$ stream, that emits an event any time the value\n * of an entity in this component is updated.\n *\n * @param world {@link World} object this component should be registered onto.\n * @param schema {@link Schema} of component values. Uses Type enum as bridge between typescript types and javascript accessible values.\n * @param options Optional: {\n * id: descriptive id for this component (otherwise an autogenerated id is used),\n * metadata: arbitrary metadata,\n * indexed: if this flag is set, an indexer is applied to this component (see {@link createIndexer})\n * }\n * @returns Component object linked to the provided World\n *\n * @example\n * ```\n * const Position = defineComponent(world, { x: Type.Number, y: Type.Number }, { id: \"Position\" });\n * ```\n */\nexport function defineComponent<S extends Schema, M extends Metadata, T = unknown>(\n world: World,\n schema: S,\n options?: { id?: string; metadata?: M; indexed?: boolean }\n) {\n if (Object.keys(schema).length === 0) throw new Error(\"Component schema must have at least one key\");\n const id = options?.id ?? uuid();\n const values = mapObject(schema, () => new Map());\n const update$ = new Subject();\n const metadata = options?.metadata;\n const entities = () =>\n transformIterator((Object.values(values)[0] as Map<EntitySymbol, unknown>).keys(), getEntityString);\n let component = { values, schema, id, update$, metadata, entities, world } as Component<S, M, T>;\n if (options?.indexed) component = createIndexer(component);\n world.registerComponent(component as Component);\n return component;\n}\n\n/**\n * Set the value for a given entity in a given component.\n *\n * @param component {@link defineComponent Component} to be updated.\n * @param entity {@link Entity} whose value in the given component should be set.\n * @param value Value to set, schema must match the component schema.\n *\n * @example\n * ```\n * setComponent(Position, entity, { x: 1, y: 2 });\n * ```\n */\nexport function setComponent<S extends Schema, T = unknown>(\n component: Component<S, Metadata, T>,\n entity: Entity,\n value: ComponentValue<S, T>,\n options: ComponentMutationOptions = {}\n) {\n const entitySymbol = getEntitySymbol(entity);\n const prevValue = getComponentValue(component, entity);\n for (const [key, val] of Object.entries(value)) {\n if (component.values[key]) {\n component.values[key].set(entitySymbol, val);\n } else {\n const isTableFieldIndex = component.metadata?.tableId && /^\\d+$/.test(key);\n if (!isTableFieldIndex) {\n // If this key looks like a field index from `defineStoreComponents`,\n // we can ignore this value without logging anything.\n //\n // Otherwise, we should let the user know we found undefined data.\n console.warn(\n \"Component definition for\",\n getComponentName(component),\n \"is missing key\",\n key,\n \", ignoring value\",\n val,\n \"for entity\",\n entity,\n \". Existing keys: \",\n Object.keys(component.values)\n );\n }\n }\n }\n if (!options.skipUpdateStream) {\n component.update$.next({ entity, value: [value, prevValue], component });\n }\n}\n\n/**\n * Update the value for a given entity in a given component while keeping the old value of keys not included in the update.\n *\n * @param component {@link defineComponent Component} to be updated.\n * @param entity {@link Entity} whose value in the given component should be updated.\n * @param value Partial value to be set, remaining keys will be taken from the existing component value.\n *\n * @remarks\n * This function fails silently during runtime if a partial value is set for an entity that\n * does not have a component value yet, since then a partial value will be set in the component for this entity.\n *\n * @example\n * ```\n * updateComponent(Position, entity, { x: 1 });\n * ```\n */\nexport function updateComponent<S extends Schema, T = unknown>(\n component: Component<S, Metadata, T>,\n entity: Entity,\n value: Partial<ComponentValue<S, T>>,\n initialValue?: ComponentValue<S, T>,\n options: ComponentMutationOptions = {}\n) {\n const currentValue = getComponentValue(component, entity);\n if (currentValue === undefined) {\n if (initialValue === undefined) {\n throw new Error(`Can't update component ${getComponentName(component)} without a current value or initial value`);\n }\n setComponent(component, entity, { ...initialValue, ...value }, options);\n } else {\n setComponent(component, entity, { ...currentValue, ...value }, options);\n }\n}\n\n/**\n * Remove a given entity from a given component.\n *\n * @param component {@link defineComponent Component} to be updated.\n * @param entity {@link Entity} whose value should be removed from this component.\n */\nexport function removeComponent<S extends Schema, M extends Metadata, T = unknown>(\n component: Component<S, M, T>,\n entity: Entity,\n options: ComponentMutationOptions = {}\n) {\n const entitySymbol = getEntitySymbol(entity);\n const prevValue = getComponentValue(component, entity);\n for (const key of Object.keys(component.values)) {\n component.values[key].delete(entitySymbol);\n }\n if (!options.skipUpdateStream) {\n component.update$.next({ entity, value: [undefined, prevValue], component });\n }\n}\n\n/**\n * Check whether a component contains a value for a given entity.\n *\n * @param component {@link defineComponent Component} to check whether it has a value for the given entity.\n * @param entity {@link Entity} to check whether it has a value in the given component.\n * @returns true if the component contains a value for the given entity, else false.\n */\nexport function hasComponent<S extends Schema, T = unknown>(\n component: Component<S, Metadata, T>,\n entity: Entity\n): boolean {\n const entitySymbol = getEntitySymbol(entity);\n const map = Object.values(component.values)[0];\n return map.has(entitySymbol);\n}\n\n/**\n * Get the value of a given entity in the given component.\n * Returns undefined if no value or only a partial value is found.\n *\n * @param component {@link defineComponent Component} to get the value from for the given entity.\n * @param entity {@link Entity} to get the value for from the given component.\n * @returns Value of the given entity in the given component or undefined if no value exists.\n */\nexport function getComponentValue<S extends Schema, T = unknown>(\n component: Component<S, Metadata, T>,\n entity: Entity\n): ComponentValue<S, T> | undefined {\n const value: Record<string, unknown> = {};\n const entitySymbol = getEntitySymbol(entity);\n\n // Get the value of each schema key\n const schemaKeys = Object.keys(component.schema);\n for (const key of schemaKeys) {\n const val = component.values[key].get(entitySymbol);\n if (val === undefined && !OptionalTypes.includes(component.schema[key])) return undefined;\n value[key] = val;\n }\n\n return value as ComponentValue<S, T>;\n}\n\n/**\n * Get the value of a given entity in the given component.\n * Throws an error if no value exists for the given entity in the given component.\n *\n * @param component {@link defineComponent Component} to get the value from for the given entity.\n * @param entity {@link Entity} of the entity to get the value for from the given component.\n * @returns Value of the given entity in the given component.\n *\n * @remarks\n * Throws an error if no value exists in the component for the given entity.\n */\nexport function getComponentValueStrict<S extends Schema, T = unknown>(\n component: Component<S, Metadata, T>,\n entity: Entity\n): ComponentValue<S, T> {\n const value = getComponentValue(component, entity);\n if (!value) throw new Error(`No value for component ${getComponentName(component)} on entity ${entity}`);\n return value;\n}\n\n/**\n * Compare two {@link ComponentValue}s.\n * `a` can be a partial component value, in which case only the keys present in `a` are compared to the corresponding keys in `b`.\n *\n * @param a Partial {@link ComponentValue} to compare to `b`\n * @param b Component value to compare `a` to.\n * @returns True if `a` equals `b` in the keys present in a or neither `a` nor `b` are defined, else false.\n *\n * @example\n * ```\n * componentValueEquals({ x: 1, y: 2 }, { x: 1, y: 3 }) // returns false because value of y doesn't match\n * componentValueEquals({ x: 1 }, { x: 1, y: 3 }) // returns true because x is equal and y is not present in a\n * ```\n */\nexport function componentValueEquals<S extends Schema, T = unknown>(\n a?: Partial<ComponentValue<S, T>>,\n b?: ComponentValue<S, T>\n): boolean {\n if (!a && !b) return true;\n if (!a || !b) return false;\n\n let equals = true;\n for (const key of Object.keys(a)) {\n equals = a[key] === b[key];\n if (!equals) return false;\n }\n return equals;\n}\n\n/**\n * Util to create a tuple of a component and value with matching schema.\n * (Used to enforce Typescript type safety.)\n *\n * @param component {@link defineComponent Component} with {@link ComponentSchema} `S`\n * @param value {@link ComponentValue} with {@link ComponentSchema} `S`\n * @returns Tuple `[component, value]`\n */\nexport function withValue<S extends Schema, T = unknown>(\n component: Component<S, Metadata, T>,\n value: ComponentValue<S, T>\n): [Component<S, Metadata, T>, ComponentValue<S, T>] {\n return [component, value];\n}\n\n/**\n * Get a set of entities that have the given component value in the given component.\n *\n * @param component {@link defineComponent Component} to get entities with the given value from.\n * @param value look for entities with this {@link ComponentValue}.\n * @returns Set with {@link Entity Entities} with the given component value.\n */\nexport function getEntitiesWithValue<S extends Schema>(\n component: Component<S> | Indexer<S>,\n value: Partial<ComponentValue<S>>\n): Set<Entity> {\n // Shortcut for indexers\n if (isIndexer(component) && isFullComponentValue(component, value)) {\n return component.getEntitiesWithValue(value);\n }\n\n // Trivial implementation for regular components\n const entities = new Set<Entity>();\n for (const entity of getComponentEntities(component)) {\n const val = getComponentValue(component, entity);\n if (componentValueEquals(value, val)) {\n entities.add(entity);\n }\n }\n return entities;\n}\n\n/**\n * Get a set of all entities of the given component.\n *\n * @param component {@link defineComponent Component} to get all entities from\n * @returns Set of all entities in the given component.\n */\nexport function getComponentEntities<S extends Schema, T = unknown>(\n component: Component<S, Metadata, T>\n): IterableIterator<Entity> {\n return component.entities();\n}\n\n/**\n * An overridable component is a mirror of the source component, with functions to lazily override specific entity values.\n * Lazily override means the values are not actually set to the source component, but the override is only returned if the value is read.\n *\n * - When an override for an entity is added to the component, the override is propagated via the component's `update$` stream.\n * - While an override is set for a specific entity, no updates to the source component for this entity will be propagated to the `update$` stream.\n * - When an override is removed for a specific entity and there are more overrides targeting this entity,\n * the override with the highest nonce will be propagated to the `update$` stream.\n * - When an override is removed for a specific entity and there are no more overrides targeting this entity,\n * the non-overridden underlying component value of this entity will be propagated to the `update$` stream.\n *\n * @param component {@link defineComponent Component} to use as underlying source for the overridable component\n * @returns overridable component\n */\nexport function overridableComponent<S extends Schema, M extends Metadata, T = unknown>(\n component: Component<S, M, T>\n): OverridableComponent<S, M, T> {\n let nonce = 0;\n\n // Map from OverrideId to Override (to be able to add multiple overrides to the same Entity)\n const overrides = new Map<string, { update: Override<S, T>; nonce: number }>();\n\n // Map from EntitySymbol to current overridden component value\n const overriddenEntityValues = new Map<EntitySymbol, Partial<ComponentValue<S, T>> | null>();\n\n // Update event stream that takes into account overridden entity values\n const update$ = new Subject<{\n entity: Entity;\n value: [ComponentValue<S, T> | undefined, ComponentValue<S, T> | undefined];\n component: Component<S, Metadata, T>;\n }>();\n\n // Add a new override to some entity\n function addOverride(id: string, update: Override<S, T>) {\n overrides.set(id, { update, nonce: nonce++ });\n setOverriddenComponentValue(update.entity, update.value);\n }\n\n // Remove an override from an entity\n function removeOverride(id: string) {\n const affectedEntity = overrides.get(id)?.update.entity;\n overrides.delete(id);\n\n if (affectedEntity == null) return;\n\n // If there are more overries affecting this entity,\n // set the overriddenEntityValue to the last override\n const relevantOverrides = [...overrides.values()]\n .filter((o) => o.update.entity === affectedEntity)\n .sort((a, b) => (a.nonce < b.nonce ? -1 : 1));\n\n if (relevantOverrides.length > 0) {\n const lastOverride = relevantOverrides[relevantOverrides.length - 1];\n setOverriddenComponentValue(affectedEntity, lastOverride.update.value);\n } else {\n setOverriddenComponentValue(affectedEntity, undefined);\n }\n }\n\n // Internal function to get the current overridden value or value of the source component\n function getOverriddenComponentValue(entity: Entity): ComponentValue<S, T> | undefined {\n const originalValue = getComponentValue(component, entity);\n const entitySymbol = getEntitySymbol(entity);\n const overriddenValue = overriddenEntityValues.get(entitySymbol);\n return (originalValue || overriddenValue) && overriddenValue !== null // null is a valid override, in this case return undefined\n ? ({ ...originalValue, ...overriddenValue } as ComponentValue<S, T>)\n : undefined;\n }\n\n const valueProxyHandler: (key: keyof S) => ProxyHandler<(typeof component.values)[typeof key]> = (key: keyof S) => ({\n get(target, prop) {\n // Intercept calls to component.value[key].get(entity)\n if (prop === \"get\") {\n return (entity: EntitySymbol) => {\n const originalValue = target.get(entity);\n const overriddenValue = overriddenEntityValues.get(entity);\n return overriddenValue && overriddenValue[key] != null ? overriddenValue[key] : originalValue;\n };\n }\n\n // Intercept calls to component.value[key].has(entity)\n if (prop === \"has\") {\n return (entity: EntitySymbol) => {\n return target.has(entity) || overriddenEntityValues.has(entity);\n };\n }\n\n // Intercept calls to component.value[key].keys()\n if (prop === \"keys\") {\n return () => new Set([...target.keys(), ...overriddenEntityValues.keys()]).values();\n }\n\n return Reflect.get(target, prop, target);\n },\n });\n\n const partialValues: Partial<Component<S, M, T>[\"values\"]> = {};\n for (const key of Object.keys(component.values) as (keyof S)[]) {\n partialValues[key] = new Proxy(component.values[key], valueProxyHandler(key));\n }\n const valuesProxy = partialValues as Component<S, M, T>[\"values\"];\n\n const overriddenComponent = new Proxy(component, {\n get(target, prop) {\n if (prop === \"addOverride\") return addOverride;\n if (prop === \"removeOverride\") return removeOverride;\n if (prop === \"values\") return valuesProxy;\n if (prop === \"update$\") return update$;\n if (prop === \"entities\")\n return () =>\n new Set([\n ...transformIterator(overriddenEntityValues.keys(), getEntityString),\n ...target.entities(),\n ]).values();\n\n return Reflect.get(target, prop);\n },\n has(target, prop) {\n if (prop === \"addOverride\" || prop === \"removeOverride\") return true;\n return prop in target;\n },\n }) as OverridableComponent<S, M, T>;\n\n // Internal function to set the current overridden component value and emit the update event\n function setOverriddenComponentValue(entity: Entity, value?: Partial<ComponentValue<S, T>> | null) {\n const entitySymbol = getEntitySymbol(entity);\n // Check specifically for undefined - null is a valid override\n const prevValue = getOverriddenComponentValue(entity);\n if (value !== undefined) overriddenEntityValues.set(entitySymbol, value);\n else overriddenEntityValues.delete(entitySymbol);\n update$.next({ entity, value: [getOverriddenComponentValue(entity), prevValue], component: overriddenComponent });\n }\n\n // Channel through update events from the original component if there are no overrides\n component.update$\n .pipe(\n filter((e) => !overriddenEntityValues.get(getEntitySymbol(e.entity))),\n map((update) => ({ ...update, component: overriddenComponent }))\n )\n .subscribe(update$);\n\n return overriddenComponent;\n}\n\nfunction getLocalCacheId(component: Component, uniqueWorldIdentifier?: string): string {\n return `localcache-${uniqueWorldIdentifier}-${component.id}`;\n}\n\nexport function clearLocalCache(component: Component, uniqueWorldIdentifier?: string): void {\n localStorage.removeItem(getLocalCacheId(component, uniqueWorldIdentifier));\n}\n\n// Note: Only proof of concept for now - use this only for component that do not update frequently\nexport function createLocalCache<S extends Schema, M extends Metadata, T = unknown>(\n component: Component<S, M, T>,\n uniqueWorldIdentifier?: string\n): Component<S, M, T> {\n const { world, update$, values } = component;\n const cacheId = getLocalCacheId(component as Component, uniqueWorldIdentifier);\n let numUpdates = 0;\n const creation = Date.now();\n\n // On creation, check if this component has locally cached values\n const encodedCache = localStorage.getItem(cacheId);\n if (encodedCache) {\n const cache = JSON.parse(encodedCache) as [string, [Entity, unknown][]][];\n const state: { [entity: Entity]: { [key: string]: unknown } } = {};\n\n for (const [key, values] of cache) {\n for (const [entity, value] of values) {\n state[entity] = state[entity] || {};\n state[entity][key] = value;\n }\n }\n\n for (const [entityId, value] of Object.entries(state)) {\n const entity = world.registerEntity({ id: entityId });\n setComponent(component, entity, value as ComponentValue<S, T>);\n }\n\n console.info(\"Loading component\", getComponentName(component), \"from local cache.\");\n }\n\n // Flush the entire component to the local cache every time it updates.\n // Note: this is highly unperformant and should only be used for components that\n // don't update often and don't have many values\n const updateSub = update$.subscribe(() => {\n numUpdates++;\n const encoded = JSON.stringify(\n Object.entries(mapObject(values, (m) => [...m.entries()].map((e) => [getEntityString(e[0]), e[1]])))\n );\n localStorage.setItem(cacheId, encoded);\n if (numUpdates > 200) {\n console.warn(\n \"Component\",\n getComponentName(component),\n \"was locally cached\",\n numUpdates,\n \"times since\",\n new Date(creation).toLocaleTimeString(),\n \"- the local cache is in an alpha state and should not be used with components that update frequently yet\"\n );\n }\n });\n component.world.registerDisposer(() => updateSub?.unsubscribe());\n\n return component;\n}\n","import { getComponentEntities, getComponentValue } from \"./Component\";\nimport { getEntityString, getEntitySymbol } from \"./Entity\";\nimport { Component, ComponentValue, Entity, EntitySymbol, Indexer, Metadata, Schema } from \"./types\";\n\n/**\n * Create an indexed component from a given component.\n *\n * @remarks\n * An indexed component keeps a \"reverse mapping\" from {@link ComponentValue} to the Set of {@link createEntity Entities} with this value.\n * This adds a performance overhead to modifying component values and a memory overhead since in the worst case there is one\n * Set per entity (if every entity has a different component value).\n * In return the performance for querying for entities with a given component value is close to O(1) (instead of O(#entities) in a regular non-indexed component).\n * As a rule of thumb only components that are added to many entities and are queried with {@link HasValue} a lot should be indexed (eg. the Position component).\n *\n * @dev This could be made more (memory) efficient by using a hash of the component value as key, but would require handling hash collisions.\n *\n * @param component {@link defineComponent Component} to index.\n * @returns Indexed version of the component.\n */\nexport function createIndexer<S extends Schema, M extends Metadata, T = unknown>(\n component: Component<S, M, T>\n): Indexer<S, M, T> {\n const valueToEntities = new Map<string, Set<EntitySymbol>>();\n\n function getEntitiesWithValue(value: ComponentValue<S, T>) {\n const entities = valueToEntities.get(getValueKey(value));\n return entities ? new Set([...entities].map(getEntityString)) : new Set<Entity>();\n }\n\n function getValueKey(value: ComponentValue<S, T>): string {\n return Object.values(value).join(\"/\");\n }\n\n function add(entity: EntitySymbol, value: ComponentValue<S, T> | undefined) {\n if (!value) return;\n const valueKey = getValueKey(value);\n let entitiesWithValue = valueToEntities.get(valueKey);\n if (!entitiesWithValue) {\n entitiesWithValue = new Set<EntitySymbol>();\n valueToEntities.set(valueKey, entitiesWithValue);\n }\n entitiesWithValue.add(entity);\n }\n\n function remove(entity: EntitySymbol, value: ComponentValue<S, T> | undefined) {\n if (!value) return;\n const valueKey = getValueKey(value);\n const entitiesWithValue = valueToEntities.get(valueKey);\n if (!entitiesWithValue) return;\n entitiesWithValue.delete(entity);\n }\n\n // Initial indexing\n for (const entity of getComponentEntities(component)) {\n const value = getComponentValue(component, entity);\n add(getEntitySymbol(entity), value);\n }\n\n // Keeping index up to date\n const subscription = component.update$.subscribe(({ entity, value }) => {\n // Remove from previous location\n remove(getEntitySymbol(entity), value[1]);\n\n // Add to new location\n add(getEntitySymbol(entity), value[0]);\n });\n\n component.world.registerDisposer(() => subscription?.unsubscribe());\n\n return { ...component, getEntitiesWithValue };\n}\n","import { map, pipe } from \"rxjs\";\nimport { getComponentValue } from \"./Component\";\nimport { UpdateType } from \"./constants\";\nimport { Component, ComponentUpdate, ComponentValue, Entity, Indexer, Schema } from \"./types\";\n\n/**\n * Type guard to infer the TypeScript type of a given component update\n *\n * @param update Component update to infer the type of.\n * @param component {@link defineComponent Component} to check whether the given update corresponds to it.\n * @returns True (+ infered type for `update`) if `update` belongs to `component`. Else false.\n */\nexport function isComponentUpdate<S extends Schema>(\n update: ComponentUpdate,\n component: Component<S>\n): update is ComponentUpdate<S> {\n return update.component === component;\n}\n\n/**\n * Helper function to create a component update for the current component value of a given entity.\n *\n * @param entity Entity to create the component update for.\n * @param component Component to create the component update for.\n * @returns Component update corresponding to the given entity, the given component and the entity's current component value.\n */\nexport function toUpdate<S extends Schema>(entity: Entity, component: Component<S>) {\n const value = getComponentValue(component, entity);\n return {\n entity,\n component,\n value: [value, undefined],\n type: value == null ? UpdateType.Noop : UpdateType.Enter,\n } as ComponentUpdate<S> & {\n type: UpdateType;\n };\n}\n\n/**\n * Helper function to turn a stream of {@link Entity Entities} into a stream of component updates of the given component.\n * @param component Component to create update stream for.\n * @returns Unary function to be used with RxJS that turns stream of {@link Entity Entities} into stream of component updates.\n */\nexport function toUpdateStream<S extends Schema>(component: Component<S>) {\n return pipe(map((entity: Entity) => toUpdate(entity, component)));\n}\n\n/**\n * Helper function to check whether a given component is indexed.\n * @param c\n * @returns\n */\nexport function isIndexer<S extends Schema>(c: Component<S> | Indexer<S>): c is Indexer<S> {\n return \"getEntitiesWithValue\" in c;\n}\n\n/**\n * Helper function to check whether a given component value is partial or full.\n * @param component\n * @param value\n * @returns\n */\nexport function isFullComponentValue<S extends Schema>(\n component: Component<S>,\n value: Partial<ComponentValue<S>>\n): value is ComponentValue<S> {\n return Object.keys(component.schema).every((key) => key in value);\n}\n","import { setComponent } from \"./Component\";\nimport { Component, ComponentValue, Entity, EntitySymbol, World } from \"./types\";\n\n/**\n * Register a new entity in the given {@link World} and initialize it with the given {@link ComponentValue}s.\n *\n * @param world World object this entity should be registered in.\n * @param components Array of [{@link defineComponent Component}, {@link ComponentValue}] tuples to be added to this entity.\n * (Use {@link withValue} to generate these tuples with type safety.)\n * @param options Optional: {\n * id: {@link Entity} for this entity. Use this for entities that were created outside of recs.\n * idSuffix: string to be appended to the auto-generated id. Use this for improved readability. Do not use this if the `id` option is provided.\n * }\n * @returns index of this entity in the {@link World}. This {@link Entity} is used to refer to this entity in other recs methods (eg {@link setComponent}).\n * (This is to avoid having to store strings in every component.)\n */\nexport function createEntity(\n world: World,\n components?: [Component, ComponentValue][],\n options?: { id?: string } | { idSuffix?: string }\n): Entity {\n const entity = world.registerEntity(options ?? {});\n\n if (components) {\n for (const [component, value] of components) {\n setComponent(component, entity, value);\n }\n }\n\n return entity;\n}\n\n/*\n * Get the symbol corresponding to an entity's string ID.\n * Entities are represented as symbols internally for memory efficiency.\n */\nexport function getEntitySymbol(entityString: string): EntitySymbol {\n return Symbol.for(entityString) as EntitySymbol;\n}\n\n/**\n * Get the underlying entity string of an entity symbol.\n */\nexport function getEntityString(entity: EntitySymbol): Entity {\n return Symbol.keyFor(entity) as Entity;\n}\n"],"mappings":"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","names":["Type","UpdateType","OptionalTypes","transformIterator","uuid","mapObject","filter","map","Subject","createIndexer","component","valueToEntities","getEntitiesWithValue","value","entities","getValueKey","getEntityString","add","entity","valueKey","entitiesWithValue","remove","getComponentEntities","getComponentValue","getEntitySymbol","subscription","map","pipe","isComponentUpdate","update","component","toUpdate","entity","value","getComponentValue","toUpdateStream","pipe","map","isIndexer","c","isFullComponentValue","key","getComponentName","component","defineComponent","world","schema","options","id","uuid","values","mapObject","update$","Subject","metadata","transformIterator","getEntityString","createIndexer","setComponent","entity","value","entitySymbol","getEntitySymbol","prevValue","getComponentValue","key","val","updateComponent","initialValue","currentValue","removeComponent","hasComponent","schemaKeys","OptionalTypes","getComponentValueStrict","componentValueEquals","a","b","equals","withValue","getEntitiesWithValue","isIndexer","isFullComponentValue","entities","getComponentEntities","overridableComponent","nonce","overrides","overriddenEntityValues","addOverride","update","setOverriddenComponentValue","removeOverride","affectedEntity","relevantOverrides","o","lastOverride","getOverriddenComponentValue","originalValue","overriddenValue","valueProxyHandler","target","prop","partialValues","valuesProxy","overriddenComponent","filter","e","map","getLocalCacheId","uniqueWorldIdentifier","clearLocalCache","createLocalCache","cacheId","numUpdates","creation","encodedCache","cache","state","entityId","updateSub","encoded","m","createEntity","world","components","options","entity","component","value","setComponent","getEntitySymbol","entityString","getEntityString"]}