@latticexyz/recs 2.2.18-318924725246340b208d3fbee8793314686f1759 → 2.2.18-41fe36dd2756fe87bfe141e15b6d102f4b070ab1

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/System.ts","../src/Query.ts","../src/types.ts","../src/World.ts"],"sourcesContent":["import { concat, EMPTY, from, Observable } from \"rxjs\";\nimport { getComponentEntities, removeComponent, setComponent } from \"./Component\";\nimport { UpdateType } from \"./constants\";\nimport { defineEnterQuery, defineExitQuery, defineQuery, defineUpdateQuery } from \"./Query\";\nimport { Component, ComponentUpdate, ComponentValue, Entity, QueryFragment, Schema, World } from \"./types\";\nimport { toUpdateStream } from \"./utils\";\n\n/**\n * Create a system that is called on every update of the given observable.\n *\n * @remarks\n * Advantage of using this function over directly subscribing to the RxJS observable is that the system is registered in the `world` and\n * disposed when the `world` is disposed (eg. during a hot reload in development).\n *\n * @param world {@link World} object this system should be registered in.\n * @param observable$ Observable to react to.\n * @param system System function to run on updates of the `observable$`. System function gets passed the update events from the `observable$`.\n */\nexport function defineRxSystem<T>(world: World, observable$: Observable<T>, system: (event: T) => void) {\n const subscription = observable$.subscribe(system);\n world.registerDisposer(() => subscription?.unsubscribe());\n}\n\n/**\n * Create a system that is called on every event of the given {@link defineUpdateQuery update query}.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Update query to react to.\n * @param system System function to run when the result of the given update query changes.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities matching the query when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineUpdateSystem(\n world: World,\n query: QueryFragment[],\n system: (update: ComponentUpdate) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n defineRxSystem(world, defineUpdateQuery(query, options), system);\n}\n\n/**\n * Create a system that is called on every event of the given {@link defineEnterQuery enter query}.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Enter query to react to.\n * @param system System function to run when the result of the given enter query changes.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities matching the query when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineEnterSystem(\n world: World,\n query: QueryFragment[],\n system: (update: ComponentUpdate) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n defineRxSystem(world, defineEnterQuery(query, options), system);\n}\n\n/**\n * Create a system that is called on every event of the given {@link defineExitQuery exit query}.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Exit query to react to.\n * @param system System function to run when the result of the given exit query changes.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities matching the query when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineExitSystem(\n world: World,\n query: QueryFragment[],\n system: (update: ComponentUpdate) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n defineRxSystem(world, defineExitQuery(query, options), system);\n}\n\n/**\n * Create a system that is called on every event of the given {@link defineQuery query}.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Query to react to.\n * @param system System function to run when the result of the given query changes.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities matching the query when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineSystem(\n world: World,\n query: QueryFragment[],\n system: (update: ComponentUpdate & { type: UpdateType }) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n defineRxSystem(world, defineQuery(query, options).update$, system);\n}\n\n/**\n * Create a system that is called every time the given component is updated.\n *\n * @param world {@link World} object this system should be registered in.\n * @param component Component to whose updates to react.\n * @param system System function to run when the given component is updated.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities in the component when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineComponentSystem<S extends Schema>(\n world: World,\n component: Component<S>,\n system: (update: ComponentUpdate<S>) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n const initial$ = options?.runOnInit ? from(getComponentEntities(component)).pipe(toUpdateStream(component)) : EMPTY;\n defineRxSystem(world, concat(initial$, component.update$), system);\n}\n\n/**\n * Create a system to synchronize updates to one component with another component.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Result of `component` is added to all entites matching this query.\n * @param component Function returning the component to be added to all entities matching the given query.\n * @param value Function returning the component value to be added to all entities matching the given query.\n */\nexport function defineSyncSystem<T extends Schema>(\n world: World,\n query: QueryFragment[],\n component: (entity: Entity) => Component<T>,\n value: (entity: Entity) => ComponentValue<T>,\n options: { update?: boolean; runOnInit?: boolean } = { update: false, runOnInit: true },\n) {\n defineSystem(\n world,\n query,\n ({ entity, type }) => {\n if (type === UpdateType.Enter) setComponent(component(entity), entity, value(entity));\n if (type === UpdateType.Exit) removeComponent(component(entity), entity);\n if (options?.update && type === UpdateType.Update) setComponent(component(entity), entity, value(entity));\n },\n options,\n );\n}\n","import { filterNullish } from \"@latticexyz/utils\";\nimport { observable, ObservableSet } from \"mobx\";\nimport { concat, concatMap, filter, from, map, merge, Observable, of, share } from \"rxjs\";\nimport {\n componentValueEquals,\n getComponentEntities,\n getComponentValue,\n getEntitiesWithValue,\n hasComponent,\n} from \"./Component\";\nimport { UpdateType, Type } from \"./constants\";\nimport {\n Component,\n ComponentUpdate,\n ComponentValue,\n Entity,\n EntityQueryFragment,\n HasQueryFragment,\n HasValueQueryFragment,\n NotQueryFragment,\n NotValueQueryFragment,\n ProxyExpandQueryFragment,\n ProxyReadQueryFragment,\n QueryFragment,\n QueryFragmentType,\n Schema,\n SettingQueryFragment,\n} from \"./types\";\nimport { toUpdateStream } from \"./utils\";\n\n/**\n * Create a {@link HasQueryFragment}.\n *\n * @remarks\n * The {@link HasQueryFragment} filters for entities that have the given component,\n * independent from the component value.\n *\n * @example\n * Query for all entities with a `Position`.\n * ```\n * runQuery([Has(Position)]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function Has<T extends Schema>(component: Component<T>): HasQueryFragment<T> {\n return { type: QueryFragmentType.Has, component };\n}\n\n/**\n * Create a {@link NotQueryFragment}.\n *\n * @remarks\n * The {@link NotQueryFragment} filters for entities that don't have the given component,\n * independent from the component value.\n *\n * @example\n * Query for all entities with a `Position` that are not `Movable`.\n * ```\n * runQuery([Has(Position), Not(Movable)]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function Not<T extends Schema>(component: Component<T>): NotQueryFragment<T> {\n return { type: QueryFragmentType.Not, component };\n}\n\n/**\n * Create a {@link HasValueQueryFragment}.\n *\n * @remarks\n * The {@link HasValueQueryFragment} filters for entities that have the given component\n * with the given component value.\n *\n * @example\n * Query for all entities at Position (0,0).\n * ```\n * runQuery([HasValue(Position, { x: 0, y: 0 })]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @param value Only include entities with this (partial) component value from the result.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function HasValue<T extends Schema>(\n component: Component<T>,\n value: Partial<ComponentValue<T>>,\n): HasValueQueryFragment<T> {\n return { type: QueryFragmentType.HasValue, component, value };\n}\n\n/**\n * Create a {@link NotValueQueryFragment}.\n *\n * @remarks\n * The {@link NotValueQueryFragment} filters for entities that don't have the given component\n * with the given component value.\n *\n * @example\n * Query for all entities that have a `Position`, except for those at `Position` (0,0).\n * ```\n * runQuery([Has(Position), NotValue(Position, { x: 0, y: 0 })]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @param value Exclude entities with this (partial) component value from the result.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function NotValue<T extends Schema>(\n component: Component<T>,\n value: Partial<ComponentValue<T>>,\n): NotValueQueryFragment<T> {\n return { type: QueryFragmentType.NotValue, component, value };\n}\n\n/**\n * Create a {@link ProxyReadQueryFragment}.\n *\n * @remarks\n * The {@link ProxyReadQueryFragment} activates the \"proxy read mode\" for the rest of the query.\n * This means that for all remaining fragments in the query not only the entities themselves are checked, but also\n * their \"ancestors\" up to the given `depth` on the relationship chain defined by the given `component`.\n *\n * @example\n * Query for all entities that have a `Position` and are (directly or indirectly) owned by an entity with `Name` \"Alice\".\n * ```\n * runQuery([Has(Position), ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(Name, { name: \"Alice\" })]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @param depth Max depth in the relationship chain to traverse.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function ProxyRead(component: Component<{ value: Type.Entity }>, depth: number): ProxyReadQueryFragment {\n return { type: QueryFragmentType.ProxyRead, component, depth };\n}\n\n/**\n * Create a {@link ProxyExpandQueryFragment}.\n *\n * @remarks\n * The {@link ProxyExpandQueryFragment} activates the \"proxy expand mode\" for the rest of the query.\n * This means that for all remaining fragments in the query not only the matching entities themselves are included in the intermediate set,\n * but also all their \"children\" down to the given `depth` on the relationship chain defined by the given `component`.\n *\n * @example\n * Query for all entities (directly or indirectly) owned by an entity with `Name` \"Alice\".\n * ```\n * runQuery([ProxyExpand(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(Name, { name: \"Alice\" })]);\n * ```\n *\n * @param component Component to apply this query fragment to.\n * @param depth Max depth in the relationship chain to traverse.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function ProxyExpand(component: Component<{ value: Type.Entity }>, depth: number): ProxyExpandQueryFragment {\n return { type: QueryFragmentType.ProxyExpand, component, depth };\n}\n\n/**\n * Helper function to check whether a given entity passes a given query fragment.\n *\n * @param entity Entity to check.\n * @param fragment Query fragment to check.\n * @returns True if the entity passes the query fragment, else false.\n */\nfunction passesQueryFragment<T extends Schema>(entity: Entity, fragment: EntityQueryFragment<T>): boolean {\n if (fragment.type === QueryFragmentType.Has) {\n // Entity must have the given component\n return hasComponent(fragment.component, entity);\n }\n\n if (fragment.type === QueryFragmentType.HasValue) {\n // Entity must have the given component value\n return componentValueEquals(fragment.value, getComponentValue(fragment.component, entity));\n }\n\n if (fragment.type === QueryFragmentType.Not) {\n // Entity must not have the given component\n return !hasComponent(fragment.component, entity);\n }\n\n if (fragment.type === QueryFragmentType.NotValue) {\n // Entity must not have the given component value\n return !componentValueEquals(fragment.value, getComponentValue(fragment.component, entity));\n }\n\n throw new Error(\"Unknown query fragment\");\n}\n\n/**\n * Helper function to check whether a query fragment is \"positive\" (ie `Has` or `HasValue`)\n *\n * @param fragment Query fragment to check.\n * @returns True if the query fragment is positive, else false.\n */\nfunction isPositiveFragment<T extends Schema>(\n fragment: QueryFragment<T>,\n): fragment is HasQueryFragment<T> | HasValueQueryFragment<T> {\n return fragment.type === QueryFragmentType.Has || fragment.type == QueryFragmentType.HasValue;\n}\n\n/**\n * Helper function to check whether a query fragment is \"negative\" (ie `Not` or `NotValue`)\n *\n * @param fragment Query fragment to check.\n * @returns True if the query fragment is negative, else false.\n */\nfunction isNegativeFragment<T extends Schema>(\n fragment: QueryFragment<T>,\n): fragment is NotQueryFragment<T> | NotValueQueryFragment<T> {\n return fragment.type === QueryFragmentType.Not || fragment.type == QueryFragmentType.NotValue;\n}\n\n/**\n * Helper function to check whether a query fragment is a setting fragment (ie `ProxyExpand` or `ProxyRead`)\n *\n * @param fragment Query fragment to check.\n * @returns True if the query fragment is a setting fragment, else false.\n */\nfunction isSettingFragment<T extends Schema>(fragment: QueryFragment<T>): fragment is SettingQueryFragment {\n return fragment.type === QueryFragmentType.ProxyExpand || fragment.type == QueryFragmentType.ProxyRead;\n}\n\n/**\n * Helper function to check whether the result of a query pass check is a breaking state.\n *\n * @remarks\n * For positive fragments (Has/HasValue) we need to find any passing entity up the proxy chain\n * so as soon as passes is true, we can early return. For negative fragments (Not/NotValue) every entity\n * up the proxy chain must pass, so we can early return if we find one that doesn't pass.\n *\n * @param passes Boolean result of previous query pass check.\n * @param fragment Fragment that was used in the query pass check.\n * @returns True if the result is breaking pass state, else false.\n */\nfunction isBreakingPassState(passes: boolean, fragment: EntityQueryFragment<Schema>) {\n return (passes && isPositiveFragment(fragment)) || (!passes && isNegativeFragment(fragment));\n}\n\n/**\n * Helper function to check whether an entity passes a query fragment when taking into account a {@link ProxyReadQueryFragment}.\n *\n * @param entity {@link Entity} of the entity to check.\n * @param fragment Query fragment to check.\n * @param proxyRead {@link ProxyReadQueryFragment} to take into account.\n * @returns True if the entity passes the query fragment, else false.\n */\nfunction passesQueryFragmentProxy<T extends Schema>(\n entity: Entity,\n fragment: EntityQueryFragment<T>,\n proxyRead: ProxyReadQueryFragment,\n): boolean | null {\n let proxyEntity = entity;\n let passes = false;\n for (let i = 0; i < proxyRead.depth; i++) {\n const value = getComponentValue(proxyRead.component, proxyEntity);\n // If the current entity does not have the proxy component, abort\n if (!value) return null;\n\n const entity = value.value;\n if (!entity) return null;\n\n // Move up the proxy chain\n proxyEntity = entity;\n passes = passesQueryFragment(proxyEntity, fragment);\n\n if (isBreakingPassState(passes, fragment)) {\n return passes;\n }\n }\n return passes;\n}\n\n/**\n * Recursively compute all direct and indirect child entities up to the specified depth\n * down the relationship chain defined by the given component.\n *\n * @param entity Entity to get all child entities for up to the specified depth\n * @param component Component to use for the relationship chain.\n * @param depth Depth up to which the recursion should be applied.\n * @returns Set of entities that are child entities of the given entity via the given component.\n */\nexport function getChildEntities(\n entity: Entity,\n component: Component<{ value: Type.Entity }>,\n depth: number,\n): Set<Entity> {\n if (depth === 0) return new Set();\n\n const directChildEntities = getEntitiesWithValue(component, { value: entity });\n if (depth === 1) return directChildEntities;\n\n const indirectChildEntities = [...directChildEntities]\n .map((childEntity) => [...getChildEntities(childEntity, component, depth - 1)])\n .flat();\n\n return new Set([...directChildEntities, ...indirectChildEntities]);\n}\n\n/**\n * Execute a list of query fragments to receive a Set of matching entities.\n *\n * @remarks\n * The query fragments are executed from left to right and are concatenated with a logical `AND`.\n * For performance reasons, the most restrictive query fragment should be first in the list of query fragments,\n * in order to reduce the number of entities the next query fragment needs to be checked for.\n * If no proxy fragments are used, every entity in the resulting set passes every query fragment.\n * If setting fragments are used, the order of the query fragments influences the result, since settings only apply to\n * fragments after the setting fragment.\n *\n * @param fragments Query fragments to execute.\n * @param initialSet Optional: provide a Set of entities to execute the query on. If none is given, all existing entities are used for the query.\n * @returns Set of entities matching the query fragments.\n */\nexport function runQuery(fragments: QueryFragment[], initialSet?: Set<Entity>): Set<Entity> {\n let entities: Set<Entity> | undefined = initialSet ? new Set([...initialSet]) : undefined; // Copy to a fresh set because it will be modified in place\n let proxyRead: ProxyReadQueryFragment | undefined = undefined;\n let proxyExpand: ProxyExpandQueryFragment | undefined = undefined;\n\n // Process fragments\n for (let i = 0; i < fragments.length; i++) {\n const fragment = fragments[i];\n if (isSettingFragment(fragment)) {\n // Store setting fragments for subsequent query fragments\n if (fragment.type === QueryFragmentType.ProxyRead) proxyRead = fragment;\n if (fragment.type === QueryFragmentType.ProxyExpand) proxyExpand = fragment;\n } else if (!entities) {\n // Handle entity query fragments\n // First regular fragment must be Has or HasValue\n if (isNegativeFragment(fragment)) {\n throw new Error(\"First EntityQueryFragment must be Has or HasValue\");\n }\n\n // Create the first interim result\n entities =\n fragment.type === QueryFragmentType.Has\n ? new Set([...getComponentEntities(fragment.component)])\n : getEntitiesWithValue(fragment.component, fragment.value);\n\n // Add entity's children up to the specified depth if proxy expand is active\n if (proxyExpand && proxyExpand.depth > 0) {\n for (const entity of [...entities]) {\n for (const childEntity of getChildEntities(entity, proxyExpand.component, proxyExpand.depth)) {\n entities.add(childEntity);\n }\n }\n }\n } else {\n // There already is an interim result, apply the current fragment\n for (const entity of [...entities]) {\n // Branch 1: Simple / check if the current entity passes the query fragment\n let passes = passesQueryFragment(entity, fragment);\n\n // Branch 2: Proxy upwards / check if proxy entity passes the query\n if (proxyRead && proxyRead.depth > 0 && !isBreakingPassState(passes, fragment)) {\n passes = passesQueryFragmentProxy(entity, fragment, proxyRead) ?? passes;\n }\n\n // If the entity didn't pass the query fragment, remove it from the interim set\n if (!passes) entities.delete(entity);\n\n // Branch 3: Proxy downwards / run the query fragments on child entities if proxy expand is active\n if (proxyExpand && proxyExpand.depth > 0) {\n const childEntities = getChildEntities(entity, proxyExpand.component, proxyExpand.depth);\n for (const childEntity of childEntities) {\n // Add the child entity if it passes the direct check\n // or if a proxy read is active and it passes the proxy read check\n if (\n passesQueryFragment(childEntity, fragment) ||\n (proxyRead && proxyRead.depth > 0 && passesQueryFragmentProxy(childEntity, fragment, proxyRead))\n )\n entities.add(childEntity);\n }\n }\n }\n }\n }\n\n return entities ?? new Set<Entity>();\n}\n\n/**\n * Create a query object including an update$ stream and a Set of entities currently matching the query.\n *\n * @remarks\n * `update$` stream needs to be subscribed to in order for the logic inside the stream to be executed and therefore\n * in order for the `matching` set to be updated.\n *\n * `defineQuery` should be strongly preferred over `runQuery` if the query is used for systems or other\n * use cases that repeatedly require the query result or updates to the query result. `defineQuery` does not\n * reevaluate the entire query if an accessed component changes, but only performs the minimal set of checks\n * on the updated entity to evaluate wether the entity still matches the query, resulting in significant performance\n * advantages over `runQuery`.\n *\n * The query fragments are executed from left to right and are concatenated with a logical `AND`.\n * For performance reasons, the most restrictive query fragment should be first in the list of query fragments,\n * in order to reduce the number of entities the next query fragment needs to be checked for.\n * If no proxy fragments are used, every entity in the resulting set passes every query fragment.\n * If setting fragments are used, the order of the query fragments influences the result, since settings only apply to\n * fragments after the setting fragment.\n *\n * @param fragments Query fragments to execute.\n * @param options Optional: {\n * runOnInit: if true, the query is executed once with `runQuery` to build an iniital Set of matching entities. If false only updates after the query was created are considered.\n * initialSet: if given, this set is passed to `runOnInit` when building the initial Set of matching entities.\n * }\n * @returns Query object: {\n * update$: RxJS stream of updates to the query result. The update contains the component update that caused the query update, as well as the {@link UpdateType update type}.\n * matching: Mobx observable set of entities currently matching the query.\n * }.\n */\nexport function defineQuery(\n fragments: QueryFragment[],\n options?: { runOnInit?: boolean; initialSet?: Set<Entity> },\n): {\n update$: Observable<ComponentUpdate & { type: UpdateType }>;\n matching: ObservableSet<Entity>;\n} {\n const initialSet =\n options?.runOnInit || options?.initialSet ? runQuery(fragments, options.initialSet) : new Set<Entity>();\n\n const matching = observable(initialSet);\n const initial$ = from(matching).pipe(toUpdateStream(fragments[0].component));\n\n const containsProxy =\n fragments.findIndex((v) => [QueryFragmentType.ProxyExpand, QueryFragmentType.ProxyRead].includes(v.type)) !== -1;\n\n const internal$ = merge(...fragments.map((f) => f.component.update$)) // Combine all component update streams accessed accessed in this query\n .pipe(\n containsProxy // Query contains proxies\n ? concatMap((update) => {\n // If the query contains proxy read or expand fragments, entities up or down the proxy chain might match due to this update.\n // We have to run the entire query again and compare the result.\n // TODO: We might be able to make this more efficient by first computing the set of entities that are potentially touched by this update\n // and then only rerun the query on this set.\n const newMatchingSet = runQuery(fragments, options?.initialSet);\n const updates: (ComponentUpdate & { type: UpdateType })[] = [];\n\n for (const previouslyMatchingEntity of matching) {\n // Entity matched before but doesn't match now\n if (!newMatchingSet.has(previouslyMatchingEntity)) {\n matching.delete(previouslyMatchingEntity);\n updates.push({\n entity: previouslyMatchingEntity,\n type: UpdateType.Exit,\n component: update.component,\n value: [undefined, undefined],\n });\n }\n }\n\n for (const matchingEntity of newMatchingSet) {\n if (matching.has(matchingEntity)) {\n // Entity matched before and still matches\n updates.push({\n entity: matchingEntity,\n type: UpdateType.Update,\n component: update.component,\n value: [getComponentValue(update.component, matchingEntity), undefined],\n });\n } else {\n // Entity didn't match before but matches now\n matching.add(matchingEntity);\n updates.push({\n entity: matchingEntity,\n type: UpdateType.Enter,\n component: update.component,\n value: [getComponentValue(update.component, matchingEntity), undefined],\n });\n }\n }\n\n return of(...updates);\n })\n : // Query does not contain proxies\n map((update) => {\n if (matching.has(update.entity)) {\n // If this entity matched the query before, check if it still matches it\n // Find fragments accessign this component (linear search is fine since the number fragments is likely small)\n const relevantFragments = fragments.filter((f) => f.component.id === update.component.id);\n const pass = relevantFragments.every((f) => passesQueryFragment(update.entity, f as EntityQueryFragment)); // We early return if the query contains proxies\n\n if (pass) {\n // Entity passed before and still passes, forward update\n return { ...update, type: UpdateType.Update };\n } else {\n // Entity passed before but not anymore, forward update and exit\n matching.delete(update.entity);\n return { ...update, type: UpdateType.Exit };\n }\n }\n\n // This entity didn't match before, check all fragments\n const pass = fragments.every((f) => passesQueryFragment(update.entity, f as EntityQueryFragment)); // We early return if the query contains proxies\n if (pass) {\n // Entity didn't pass before but passes now, forward update end enter\n matching.add(update.entity);\n return { ...update, type: UpdateType.Enter };\n }\n }),\n filterNullish(),\n );\n\n return {\n matching,\n update$: concat(initial$, internal$).pipe(share()),\n };\n}\n\n/**\n * Define a query object that only passes update events of type {@link UpdateType}.Update to the `update$` stream.\n * See {@link defineQuery} for details.\n *\n * @param fragments Query fragments\n * @returns Stream of component updates of entities that had already matched the query\n */\nexport function defineUpdateQuery(\n fragments: QueryFragment[],\n options?: { runOnInit?: boolean },\n): Observable<ComponentUpdate & { type: UpdateType }> {\n return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Update));\n}\n\n/**\n * Define a query object that only passes update events of type {@link UpdateType}.Enter to the `update$` stream.\n * See {@link defineQuery} for details.\n *\n * @param fragments Query fragments\n * @returns Stream of component updates of entities matching the query for the first time\n */\nexport function defineEnterQuery(\n fragments: QueryFragment[],\n options?: { runOnInit?: boolean },\n): Observable<ComponentUpdate> {\n return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Enter));\n}\n\n/**\n * Define a query object that only passes update events of type {@link UpdateType}.Exit to the `update$` stream.\n * See {@link defineQuery} for details.\n *\n * @param fragments Query fragments\n * @returns Stream of component updates of entities not matching the query anymore for the first time\n */\nexport function defineExitQuery(\n fragments: QueryFragment[],\n options?: { runOnInit?: boolean },\n): Observable<ComponentUpdate> {\n return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Exit));\n}\n","import { Subject } from \"rxjs\";\nimport { Type } from \"./constants\";\nimport { Opaque } from \"type-fest\";\n\n/**\n * Entities are represented as symbols internally for memory efficiency.\n * To get the entity's string representation, use `getEntityString(entitySymbol)`\n */\nexport type EntitySymbol = Opaque<symbol, \"EntitySymbol\">;\n\nexport type Entity = Opaque<string, \"Entity\">;\n\n/**\n * Used to define the schema of a {@link Component}.\n * Uses {@link Type} enum to be able to access the component type in JavaScript as well as have TypeScript type checks.\n */\nexport type Schema = {\n [key: string]: Type;\n};\n\n/**\n * Used to add arbitrary metadata to components.\n */\nexport type Metadata =\n | {\n [key: string]: unknown;\n }\n | undefined;\n\n/**\n * Mapping between JavaScript {@link Type} enum and corresponding TypeScript type.\n */\nexport type ValueType<T = unknown> = {\n [Type.Boolean]: boolean;\n [Type.Number]: number;\n [Type.BigInt]: bigint;\n [Type.String]: string;\n [Type.NumberArray]: number[];\n [Type.BigIntArray]: bigint[];\n [Type.StringArray]: string[];\n [Type.Entity]: Entity;\n [Type.EntityArray]: Entity[];\n [Type.OptionalNumber]: number | undefined;\n [Type.OptionalBigInt]: bigint | undefined;\n [Type.OptionalBigIntArray]: bigint[] | undefined;\n [Type.OptionalString]: string | undefined;\n [Type.OptionalNumberArray]: number[] | undefined;\n [Type.OptionalStringArray]: string[] | undefined;\n [Type.OptionalEntity]: Entity | undefined;\n [Type.OptionalEntityArray]: Entity[] | undefined;\n [Type.T]: T;\n [Type.OptionalT]: T | undefined;\n};\n\n/**\n * Used to infer the TypeScript type of a component value corresponding to a given {@link Schema}.\n */\nexport type ComponentValue<S extends Schema = Schema, T = unknown> = {\n [key in keyof S]: ValueType<T>[S[key]];\n};\n\n/**\n * Type of a component update corresponding to a given {@link Schema}.\n */\nexport type ComponentUpdate<S extends Schema = Schema, T = unknown> = {\n entity: Entity;\n value: [ComponentValue<S, T> | undefined, ComponentValue<S, T> | undefined];\n component: Component<S, Metadata, T>;\n};\n\n/**\n * Type of component returned by {@link defineComponent}.\n */\nexport interface Component<S extends Schema = Schema, M extends Metadata = Metadata, T = unknown> {\n id: string;\n values: { [key in keyof S]: Map<EntitySymbol, ValueType<T>[S[key]]> };\n schema: S;\n metadata: M;\n entities: () => IterableIterator<Entity>;\n world: World;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n update$: Subject<ComponentUpdate<S, T>> & { observers: any };\n}\n\n/**\n * Type of indexer returned by {@link createIndexer}.\n */\nexport type Indexer<S extends Schema, M extends Metadata = Metadata, T = unknown> = Component<S, M, T> & {\n getEntitiesWithValue: (value: ComponentValue<S, T>) => Set<Entity>;\n};\n\nexport type Components = {\n [key: string]: Component;\n};\n\nexport interface ComponentWithStream<S extends Schema, T = unknown> extends Component<S, Metadata, T> {\n stream$: Subject<{ entity: Entity; value: ComponentValue<S, T> | undefined }>;\n}\n\nexport type AnyComponentValue = ComponentValue<Schema>;\n\nexport type AnyComponent = Component<Schema>;\n\n/**\n * Type of World returned by {@link createWorld}.\n */\nexport type World = {\n registerEntity: (options?: { id?: string; idSuffix?: string }) => Entity;\n registerComponent: (component: Component) => void;\n components: Component[];\n getEntities: () => IterableIterator<Entity>;\n dispose: () => void;\n registerDisposer: (disposer: () => void) => void;\n hasEntity: (entity: Entity) => boolean;\n deleteEntity: (entity: Entity) => void;\n entitySymbols: Set<EntitySymbol>;\n};\n\nexport enum QueryFragmentType {\n Has,\n HasValue,\n Not,\n NotValue,\n ProxyRead,\n ProxyExpand,\n}\n\nexport type HasQueryFragment<T extends Schema> = {\n type: QueryFragmentType.Has;\n component: Component<T>;\n};\n\nexport type HasValueQueryFragment<T extends Schema> = {\n type: QueryFragmentType.HasValue;\n component: Component<T>;\n value: Partial<ComponentValue<T>>;\n};\n\nexport type NotQueryFragment<T extends Schema> = {\n type: QueryFragmentType.Not;\n component: Component<T>;\n};\n\nexport type NotValueQueryFragment<T extends Schema> = {\n type: QueryFragmentType.NotValue;\n component: Component<T>;\n value: Partial<ComponentValue<T>>;\n};\n\nexport type ProxyReadQueryFragment = {\n type: QueryFragmentType.ProxyRead;\n component: Component<{ value: Type.Entity }>;\n depth: number;\n};\n\nexport type ProxyExpandQueryFragment = {\n type: QueryFragmentType.ProxyExpand;\n component: Component<{ value: Type.Entity }>;\n depth: number;\n};\n\nexport type QueryFragment<T extends Schema = Schema> =\n | HasQueryFragment<T>\n | HasValueQueryFragment<T>\n | NotQueryFragment<T>\n | NotValueQueryFragment<T>\n | ProxyReadQueryFragment\n | ProxyExpandQueryFragment;\n\nexport type EntityQueryFragment<T extends Schema = Schema> =\n | HasQueryFragment<T>\n | HasValueQueryFragment<T>\n | NotQueryFragment<T>\n | NotValueQueryFragment<T>;\n\nexport type SettingQueryFragment = ProxyReadQueryFragment | ProxyExpandQueryFragment;\n\nexport type QueryFragments = QueryFragment<Schema>[];\n\nexport type SchemaOf<C extends Component<Schema>> = C extends Component<infer S> ? S : never;\n\nexport type Override<S extends Schema, T = unknown> = {\n entity: Entity;\n value: Partial<ComponentValue<S, T>> | null;\n};\n\n/**\n * Type of overridable component returned by {@link overridableComponent}.\n */\nexport type OverridableComponent<S extends Schema = Schema, M extends Metadata = Metadata, T = unknown> = Component<\n S,\n M,\n T\n> & {\n addOverride: (overrideId: string, update: Override<S, T>) => void;\n removeOverride: (overrideId: string) => void;\n};\n\nexport type OptionalType =\n | Type.OptionalNumber\n | Type.OptionalBigInt\n | Type.OptionalString\n | Type.OptionalEntity\n | Type.OptionalNumberArray\n | Type.OptionalBigIntArray\n | Type.OptionalStringArray\n | Type.OptionalEntityArray;\n\nexport function isOptionalType(t: Type): t is OptionalType {\n return [\n Type.OptionalNumber,\n Type.OptionalBigInt,\n Type.OptionalString,\n Type.OptionalEntity,\n Type.OptionalEntityArray,\n Type.OptionalNumberArray,\n Type.OptionalBigIntArray,\n Type.OptionalStringArray,\n ].includes(t);\n}\n\nexport type ArrayType =\n | Type.NumberArray\n | Type.OptionalNumberArray\n | Type.BigIntArray\n | Type.OptionalBigIntArray\n | Type.StringArray\n | Type.OptionalStringArray\n | Type.EntityArray\n | Type.OptionalEntityArray;\n\nexport function isArrayType(t: Type): t is ArrayType {\n return [\n Type.NumberArray,\n Type.OptionalNumberArray,\n Type.BigIntArray,\n Type.OptionalBigIntArray,\n Type.StringArray,\n Type.OptionalStringArray,\n Type.EntityArray,\n Type.OptionalEntityArray,\n ].includes(t);\n}\n\nexport type NumberType = Type.Number | Type.OptionalNumber;\nexport function isNumberType(t: Type): t is NumberType {\n return [Type.Number, Type.OptionalNumber].includes(t);\n}\n\nexport type EntityType = Type.Entity | Type.OptionalEntity;\nexport function isEntityType(t: Type): t is EntityType {\n return [Type.Entity, Type.OptionalEntity].includes(t);\n}\n\nexport type Layer = {\n world: World;\n components: Record<string, Component<Schema>>;\n};\n\nexport type Layers = Record<string, Layer>;\n","import { transformIterator } from \"@latticexyz/utils\";\nimport { hasComponent, removeComponent } from \"./Component\";\nimport { getEntityString, getEntitySymbol } from \"./Entity\";\nimport { Component, Entity, EntitySymbol, World } from \"./types\";\n\n/**\n * Create a new World.\n *\n * @remarks\n * A World is the central object of an ECS application, where all {@link defineComponent Components},\n * {@link registerEntity Entities} and {@link defineSystem Systems} are registerd.\n *\n * @returns A new World\n */\nexport function createWorld() {\n const entitySymbols = new Set<EntitySymbol>();\n const components: Component[] = [];\n let disposers: [string, () => void][] = [];\n\n function registerEntity({ id, idSuffix }: { id?: string; idSuffix?: string } = {}) {\n const entity = (id || entitySymbols.size + (idSuffix ? \"-\" + idSuffix : \"\")) as Entity;\n const entitySymbol = getEntitySymbol(entity);\n\n // Register entity\n entitySymbols.add(entitySymbol);\n\n return entity;\n }\n\n function getEntities() {\n return transformIterator(entitySymbols.values(), getEntityString);\n }\n\n function registerComponent(component: Component) {\n components.push(component);\n }\n\n function dispose(namespace?: string) {\n for (const [, disposer] of disposers.filter((d) => !namespace || d[0] === namespace)) {\n disposer();\n }\n disposers = disposers.filter((d) => namespace && d[0] !== namespace);\n }\n\n function registerDisposer(disposer: () => void, namespace = \"\") {\n disposers.push([namespace, disposer]);\n }\n\n function hasEntity(entity: Entity): boolean {\n const entitySymbol = getEntitySymbol(entity);\n return entitySymbols.has(entitySymbol);\n }\n\n function deleteEntity(entity: Entity) {\n for (const component of components) {\n if (hasComponent(component, entity)) removeComponent(component, entity);\n }\n entitySymbols.delete(getEntitySymbol(entity));\n }\n\n return {\n registerEntity,\n components,\n registerComponent,\n dispose,\n registerDisposer,\n hasEntity,\n getEntities,\n entitySymbols,\n deleteEntity,\n } satisfies World;\n}\n\n/**\n * Create a new namespace from an existing World.\n * The `dispose` method of a namespaced World only calls disposers registered on this namespace.\n *\n * @param world World to create a new namespace for.\n * @param namespace String descriptor of the new namespace.\n * @returns World with a new namespace.\n */\nexport function namespaceWorld(world: ReturnType<typeof createWorld>, namespace: string) {\n return {\n ...world,\n registerDisposer: (disposer: () => void) => world.registerDisposer(disposer, namespace),\n dispose: () => world.dispose(namespace),\n };\n}\n\n/**\n * Get all components that have a value for the given entity.\n *\n * @dev Design decision: don't store a list of components for each entity but compute it dynamically when needed\n * because there are less components than entities and maintaining a list of components per entity is a large overhead.\n *\n * @param world World object the given entity is registered on.\n * @param entity {@link Entity} to get the list of components for.\n * @returns Array of components that have a value for the given entity.\n */\nexport function getEntityComponents(world: World, entity: Entity): Component[] {\n return world.components.filter((component) => hasComponent(component, entity));\n}\n"],"mappings":"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","names":["concat","from","QueryFragmentType","entity","pass","from","concat"]}
1
+ {"version":3,"sources":["../src/System.ts","../src/Query.ts","../src/types.ts","../src/World.ts"],"sourcesContent":["import { concat, EMPTY, from, Observable } from \"rxjs\";\nimport { getComponentEntities, removeComponent, setComponent } from \"./Component\";\nimport { UpdateType } from \"./constants\";\nimport { defineEnterQuery, defineExitQuery, defineQuery, defineUpdateQuery } from \"./Query\";\nimport { Component, ComponentUpdate, ComponentValue, Entity, QueryFragment, Schema, World } from \"./types\";\nimport { toUpdateStream } from \"./utils\";\n\n/**\n * Create a system that is called on every update of the given observable.\n *\n * @remarks\n * Advantage of using this function over directly subscribing to the RxJS observable is that the system is registered in the `world` and\n * disposed when the `world` is disposed (eg. during a hot reload in development).\n *\n * @param world {@link World} object this system should be registered in.\n * @param observable$ Observable to react to.\n * @param system System function to run on updates of the `observable$`. System function gets passed the update events from the `observable$`.\n */\nexport function defineRxSystem<T>(world: World, observable$: Observable<T>, system: (event: T) => void) {\n const subscription = observable$.subscribe(system);\n world.registerDisposer(() => subscription?.unsubscribe());\n}\n\n/**\n * Create a system that is called on every event of the given {@link defineUpdateQuery update query}.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Update query to react to.\n * @param system System function to run when the result of the given update query changes.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities matching the query when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineUpdateSystem(\n world: World,\n query: QueryFragment[],\n system: (update: ComponentUpdate) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n defineRxSystem(world, defineUpdateQuery(query, options), system);\n}\n\n/**\n * Create a system that is called on every event of the given {@link defineEnterQuery enter query}.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Enter query to react to.\n * @param system System function to run when the result of the given enter query changes.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities matching the query when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineEnterSystem(\n world: World,\n query: QueryFragment[],\n system: (update: ComponentUpdate) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n defineRxSystem(world, defineEnterQuery(query, options), system);\n}\n\n/**\n * Create a system that is called on every event of the given {@link defineExitQuery exit query}.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Exit query to react to.\n * @param system System function to run when the result of the given exit query changes.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities matching the query when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineExitSystem(\n world: World,\n query: QueryFragment[],\n system: (update: ComponentUpdate) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n defineRxSystem(world, defineExitQuery(query, options), system);\n}\n\n/**\n * Create a system that is called on every event of the given {@link defineQuery query}.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Query to react to.\n * @param system System function to run when the result of the given query changes.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities matching the query when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineSystem(\n world: World,\n query: QueryFragment[],\n system: (update: ComponentUpdate & { type: UpdateType }) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n defineRxSystem(world, defineQuery(query, options).update$, system);\n}\n\n/**\n * Create a system that is called every time the given component is updated.\n *\n * @param world {@link World} object this system should be registered in.\n * @param component Component to whose updates to react.\n * @param system System function to run when the given component is updated.\n * @param options Optional: {\n * runOnInit: if true, run this system for all entities in the component when the system is created.\n * Else only run on updates after the system is created. Default true.\n * }\n */\nexport function defineComponentSystem<S extends Schema>(\n world: World,\n component: Component<S>,\n system: (update: ComponentUpdate<S>) => void,\n options: { runOnInit?: boolean } = { runOnInit: true },\n) {\n const initial$ = options?.runOnInit ? from(getComponentEntities(component)).pipe(toUpdateStream(component)) : EMPTY;\n defineRxSystem(world, concat(initial$, component.update$), system);\n}\n\n/**\n * Create a system to synchronize updates to one component with another component.\n *\n * @param world {@link World} object this system should be registered in.\n * @param query Result of `component` is added to all entites matching this query.\n * @param component Function returning the component to be added to all entities matching the given query.\n * @param value Function returning the component value to be added to all entities matching the given query.\n */\nexport function defineSyncSystem<T extends Schema>(\n world: World,\n query: QueryFragment[],\n component: (entity: Entity) => Component<T>,\n value: (entity: Entity) => ComponentValue<T>,\n options: { update?: boolean; runOnInit?: boolean } = { update: false, runOnInit: true },\n) {\n defineSystem(\n world,\n query,\n ({ entity, type }) => {\n if (type === UpdateType.Enter) setComponent(component(entity), entity, value(entity));\n if (type === UpdateType.Exit) removeComponent(component(entity), entity);\n if (options?.update && type === UpdateType.Update) setComponent(component(entity), entity, value(entity));\n },\n options,\n );\n}\n","import { filterNullish } from \"@latticexyz/utils\";\nimport { observable, ObservableSet } from \"mobx\";\nimport { concat, concatMap, filter, from, map, merge, Observable, of, share } from \"rxjs\";\nimport {\n componentValueEquals,\n getComponentEntities,\n getComponentValue,\n getEntitiesWithValue,\n hasComponent,\n} from \"./Component\";\nimport { UpdateType, Type } from \"./constants\";\nimport {\n Component,\n ComponentUpdate,\n ComponentValue,\n Entity,\n EntityQueryFragment,\n HasQueryFragment,\n HasValueQueryFragment,\n NotQueryFragment,\n NotValueQueryFragment,\n ProxyExpandQueryFragment,\n ProxyReadQueryFragment,\n QueryFragment,\n QueryFragmentType,\n Schema,\n SettingQueryFragment,\n} from \"./types\";\nimport { toUpdateStream } from \"./utils\";\n\n/**\n * Create a {@link HasQueryFragment}.\n *\n * @remarks\n * The {@link HasQueryFragment} filters for entities that have the given component,\n * independent from the component value.\n *\n * @example\n * Query for all entities with a `Position`.\n * ```\n * runQuery([Has(Position)]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function Has<T extends Schema>(component: Component<T>): HasQueryFragment<T> {\n return { type: QueryFragmentType.Has, component };\n}\n\n/**\n * Create a {@link NotQueryFragment}.\n *\n * @remarks\n * The {@link NotQueryFragment} filters for entities that don't have the given component,\n * independent from the component value.\n *\n * @example\n * Query for all entities with a `Position` that are not `Movable`.\n * ```\n * runQuery([Has(Position), Not(Movable)]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function Not<T extends Schema>(component: Component<T>): NotQueryFragment<T> {\n return { type: QueryFragmentType.Not, component };\n}\n\n/**\n * Create a {@link HasValueQueryFragment}.\n *\n * @remarks\n * The {@link HasValueQueryFragment} filters for entities that have the given component\n * with the given component value.\n *\n * @example\n * Query for all entities at Position (0,0).\n * ```\n * runQuery([HasValue(Position, { x: 0, y: 0 })]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @param value Only include entities with this (partial) component value from the result.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function HasValue<T extends Schema>(\n component: Component<T>,\n value: Partial<ComponentValue<T>>,\n): HasValueQueryFragment<T> {\n return { type: QueryFragmentType.HasValue, component, value };\n}\n\n/**\n * Create a {@link NotValueQueryFragment}.\n *\n * @remarks\n * The {@link NotValueQueryFragment} filters for entities that don't have the given component\n * with the given component value.\n *\n * @example\n * Query for all entities that have a `Position`, except for those at `Position` (0,0).\n * ```\n * runQuery([Has(Position), NotValue(Position, { x: 0, y: 0 })]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @param value Exclude entities with this (partial) component value from the result.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function NotValue<T extends Schema>(\n component: Component<T>,\n value: Partial<ComponentValue<T>>,\n): NotValueQueryFragment<T> {\n return { type: QueryFragmentType.NotValue, component, value };\n}\n\n/**\n * Create a {@link ProxyReadQueryFragment}.\n *\n * @remarks\n * The {@link ProxyReadQueryFragment} activates the \"proxy read mode\" for the rest of the query.\n * This means that for all remaining fragments in the query not only the entities themselves are checked, but also\n * their \"ancestors\" up to the given `depth` on the relationship chain defined by the given `component`.\n *\n * @example\n * Query for all entities that have a `Position` and are (directly or indirectly) owned by an entity with `Name` \"Alice\".\n * ```\n * runQuery([Has(Position), ProxyRead(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(Name, { name: \"Alice\" })]);\n * ```\n *\n * @param component Component this query fragment refers to.\n * @param depth Max depth in the relationship chain to traverse.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function ProxyRead(component: Component<{ value: Type.Entity }>, depth: number): ProxyReadQueryFragment {\n return { type: QueryFragmentType.ProxyRead, component, depth };\n}\n\n/**\n * Create a {@link ProxyExpandQueryFragment}.\n *\n * @remarks\n * The {@link ProxyExpandQueryFragment} activates the \"proxy expand mode\" for the rest of the query.\n * This means that for all remaining fragments in the query not only the matching entities themselves are included in the intermediate set,\n * but also all their \"children\" down to the given `depth` on the relationship chain defined by the given `component`.\n *\n * @example\n * Query for all entities (directly or indirectly) owned by an entity with `Name` \"Alice\".\n * ```\n * runQuery([ProxyExpand(OwnedByEntity, Number.MAX_SAFE_INTEGER), HasValue(Name, { name: \"Alice\" })]);\n * ```\n *\n * @param component Component to apply this query fragment to.\n * @param depth Max depth in the relationship chain to traverse.\n * @returns query fragment to be used in {@link runQuery} or {@link defineQuery}.\n */\nexport function ProxyExpand(component: Component<{ value: Type.Entity }>, depth: number): ProxyExpandQueryFragment {\n return { type: QueryFragmentType.ProxyExpand, component, depth };\n}\n\n/**\n * Helper function to check whether a given entity passes a given query fragment.\n *\n * @param entity Entity to check.\n * @param fragment Query fragment to check.\n * @returns True if the entity passes the query fragment, else false.\n */\nfunction passesQueryFragment<T extends Schema>(entity: Entity, fragment: EntityQueryFragment<T>): boolean {\n if (fragment.type === QueryFragmentType.Has) {\n // Entity must have the given component\n return hasComponent(fragment.component, entity);\n }\n\n if (fragment.type === QueryFragmentType.HasValue) {\n // Entity must have the given component value\n return componentValueEquals(fragment.value, getComponentValue(fragment.component, entity));\n }\n\n if (fragment.type === QueryFragmentType.Not) {\n // Entity must not have the given component\n return !hasComponent(fragment.component, entity);\n }\n\n if (fragment.type === QueryFragmentType.NotValue) {\n // Entity must not have the given component value\n return !componentValueEquals(fragment.value, getComponentValue(fragment.component, entity));\n }\n\n throw new Error(\"Unknown query fragment\");\n}\n\n/**\n * Helper function to check whether a query fragment is \"positive\" (ie `Has` or `HasValue`)\n *\n * @param fragment Query fragment to check.\n * @returns True if the query fragment is positive, else false.\n */\nfunction isPositiveFragment<T extends Schema>(\n fragment: QueryFragment<T>,\n): fragment is HasQueryFragment<T> | HasValueQueryFragment<T> {\n return fragment.type === QueryFragmentType.Has || fragment.type == QueryFragmentType.HasValue;\n}\n\n/**\n * Helper function to check whether a query fragment is \"negative\" (ie `Not` or `NotValue`)\n *\n * @param fragment Query fragment to check.\n * @returns True if the query fragment is negative, else false.\n */\nfunction isNegativeFragment<T extends Schema>(\n fragment: QueryFragment<T>,\n): fragment is NotQueryFragment<T> | NotValueQueryFragment<T> {\n return fragment.type === QueryFragmentType.Not || fragment.type == QueryFragmentType.NotValue;\n}\n\n/**\n * Helper function to check whether a query fragment is a setting fragment (ie `ProxyExpand` or `ProxyRead`)\n *\n * @param fragment Query fragment to check.\n * @returns True if the query fragment is a setting fragment, else false.\n */\nfunction isSettingFragment<T extends Schema>(fragment: QueryFragment<T>): fragment is SettingQueryFragment {\n return fragment.type === QueryFragmentType.ProxyExpand || fragment.type == QueryFragmentType.ProxyRead;\n}\n\n/**\n * Helper function to check whether the result of a query pass check is a breaking state.\n *\n * @remarks\n * For positive fragments (Has/HasValue) we need to find any passing entity up the proxy chain\n * so as soon as passes is true, we can early return. For negative fragments (Not/NotValue) every entity\n * up the proxy chain must pass, so we can early return if we find one that doesn't pass.\n *\n * @param passes Boolean result of previous query pass check.\n * @param fragment Fragment that was used in the query pass check.\n * @returns True if the result is breaking pass state, else false.\n */\nfunction isBreakingPassState(passes: boolean, fragment: EntityQueryFragment<Schema>) {\n return (passes && isPositiveFragment(fragment)) || (!passes && isNegativeFragment(fragment));\n}\n\n/**\n * Helper function to check whether an entity passes a query fragment when taking into account a {@link ProxyReadQueryFragment}.\n *\n * @param entity {@link Entity} of the entity to check.\n * @param fragment Query fragment to check.\n * @param proxyRead {@link ProxyReadQueryFragment} to take into account.\n * @returns True if the entity passes the query fragment, else false.\n */\nfunction passesQueryFragmentProxy<T extends Schema>(\n entity: Entity,\n fragment: EntityQueryFragment<T>,\n proxyRead: ProxyReadQueryFragment,\n): boolean | null {\n let proxyEntity = entity;\n let passes = false;\n for (let i = 0; i < proxyRead.depth; i++) {\n const value = getComponentValue(proxyRead.component, proxyEntity);\n // If the current entity does not have the proxy component, abort\n if (!value) return null;\n\n const entity = value.value;\n if (!entity) return null;\n\n // Move up the proxy chain\n proxyEntity = entity;\n passes = passesQueryFragment(proxyEntity, fragment);\n\n if (isBreakingPassState(passes, fragment)) {\n return passes;\n }\n }\n return passes;\n}\n\n/**\n * Recursively compute all direct and indirect child entities up to the specified depth\n * down the relationship chain defined by the given component.\n *\n * @param entity Entity to get all child entities for up to the specified depth\n * @param component Component to use for the relationship chain.\n * @param depth Depth up to which the recursion should be applied.\n * @returns Set of entities that are child entities of the given entity via the given component.\n */\nexport function getChildEntities(\n entity: Entity,\n component: Component<{ value: Type.Entity }>,\n depth: number,\n): Set<Entity> {\n if (depth === 0) return new Set();\n\n const directChildEntities = getEntitiesWithValue(component, { value: entity });\n if (depth === 1) return directChildEntities;\n\n const indirectChildEntities = [...directChildEntities]\n .map((childEntity) => [...getChildEntities(childEntity, component, depth - 1)])\n .flat();\n\n return new Set([...directChildEntities, ...indirectChildEntities]);\n}\n\n/**\n * Execute a list of query fragments to receive a Set of matching entities.\n *\n * @remarks\n * The query fragments are executed from left to right and are concatenated with a logical `AND`.\n * For performance reasons, the most restrictive query fragment should be first in the list of query fragments,\n * in order to reduce the number of entities the next query fragment needs to be checked for.\n * If no proxy fragments are used, every entity in the resulting set passes every query fragment.\n * If setting fragments are used, the order of the query fragments influences the result, since settings only apply to\n * fragments after the setting fragment.\n *\n * @param fragments Query fragments to execute.\n * @param initialSet Optional: provide a Set of entities to execute the query on. If none is given, all existing entities are used for the query.\n * @returns Set of entities matching the query fragments.\n */\nexport function runQuery(fragments: QueryFragment[], initialSet?: Set<Entity>): Set<Entity> {\n let entities: Set<Entity> | undefined = initialSet ? new Set([...initialSet]) : undefined; // Copy to a fresh set because it will be modified in place\n let proxyRead: ProxyReadQueryFragment | undefined = undefined;\n let proxyExpand: ProxyExpandQueryFragment | undefined = undefined;\n\n // Process fragments\n for (let i = 0; i < fragments.length; i++) {\n const fragment = fragments[i];\n if (isSettingFragment(fragment)) {\n // Store setting fragments for subsequent query fragments\n if (fragment.type === QueryFragmentType.ProxyRead) proxyRead = fragment;\n if (fragment.type === QueryFragmentType.ProxyExpand) proxyExpand = fragment;\n } else if (!entities) {\n // Handle entity query fragments\n // First regular fragment must be Has or HasValue\n if (isNegativeFragment(fragment)) {\n throw new Error(\"First EntityQueryFragment must be Has or HasValue\");\n }\n\n // Create the first interim result\n entities =\n fragment.type === QueryFragmentType.Has\n ? new Set([...getComponentEntities(fragment.component)])\n : getEntitiesWithValue(fragment.component, fragment.value);\n\n // Add entity's children up to the specified depth if proxy expand is active\n if (proxyExpand && proxyExpand.depth > 0) {\n for (const entity of [...entities]) {\n for (const childEntity of getChildEntities(entity, proxyExpand.component, proxyExpand.depth)) {\n entities.add(childEntity);\n }\n }\n }\n } else {\n // There already is an interim result, apply the current fragment\n for (const entity of [...entities]) {\n // Branch 1: Simple / check if the current entity passes the query fragment\n let passes = passesQueryFragment(entity, fragment);\n\n // Branch 2: Proxy upwards / check if proxy entity passes the query\n if (proxyRead && proxyRead.depth > 0 && !isBreakingPassState(passes, fragment)) {\n passes = passesQueryFragmentProxy(entity, fragment, proxyRead) ?? passes;\n }\n\n // If the entity didn't pass the query fragment, remove it from the interim set\n if (!passes) entities.delete(entity);\n\n // Branch 3: Proxy downwards / run the query fragments on child entities if proxy expand is active\n if (proxyExpand && proxyExpand.depth > 0) {\n const childEntities = getChildEntities(entity, proxyExpand.component, proxyExpand.depth);\n for (const childEntity of childEntities) {\n // Add the child entity if it passes the direct check\n // or if a proxy read is active and it passes the proxy read check\n if (\n passesQueryFragment(childEntity, fragment) ||\n (proxyRead && proxyRead.depth > 0 && passesQueryFragmentProxy(childEntity, fragment, proxyRead))\n )\n entities.add(childEntity);\n }\n }\n }\n }\n }\n\n return entities ?? new Set<Entity>();\n}\n\n/**\n * Create a query object including an update$ stream and a Set of entities currently matching the query.\n *\n * @remarks\n * `update$` stream needs to be subscribed to in order for the logic inside the stream to be executed and therefore\n * in order for the `matching` set to be updated.\n *\n * `defineQuery` should be strongly preferred over `runQuery` if the query is used for systems or other\n * use cases that repeatedly require the query result or updates to the query result. `defineQuery` does not\n * reevaluate the entire query if an accessed component changes, but only performs the minimal set of checks\n * on the updated entity to evaluate wether the entity still matches the query, resulting in significant performance\n * advantages over `runQuery`.\n *\n * The query fragments are executed from left to right and are concatenated with a logical `AND`.\n * For performance reasons, the most restrictive query fragment should be first in the list of query fragments,\n * in order to reduce the number of entities the next query fragment needs to be checked for.\n * If no proxy fragments are used, every entity in the resulting set passes every query fragment.\n * If setting fragments are used, the order of the query fragments influences the result, since settings only apply to\n * fragments after the setting fragment.\n *\n * @param fragments Query fragments to execute.\n * @param options Optional: {\n * runOnInit: if true, the query is executed once with `runQuery` to build an iniital Set of matching entities. If false only updates after the query was created are considered.\n * initialSet: if given, this set is passed to `runOnInit` when building the initial Set of matching entities.\n * }\n * @returns Query object: {\n * update$: RxJS stream of updates to the query result. The update contains the component update that caused the query update, as well as the {@link UpdateType update type}.\n * matching: Mobx observable set of entities currently matching the query.\n * }.\n */\nexport function defineQuery(\n fragments: QueryFragment[],\n options?: { runOnInit?: boolean; initialSet?: Set<Entity> },\n): {\n update$: Observable<ComponentUpdate & { type: UpdateType }>;\n matching: ObservableSet<Entity>;\n} {\n const initialSet =\n options?.runOnInit || options?.initialSet ? runQuery(fragments, options.initialSet) : new Set<Entity>();\n\n const matching = observable(initialSet);\n const initial$ = from(matching).pipe(toUpdateStream(fragments[0].component));\n\n const containsProxy =\n fragments.findIndex((v) => [QueryFragmentType.ProxyExpand, QueryFragmentType.ProxyRead].includes(v.type)) !== -1;\n\n const internal$ = merge(...fragments.map((f) => f.component.update$)) // Combine all component update streams accessed accessed in this query\n .pipe(\n containsProxy // Query contains proxies\n ? concatMap((update) => {\n // If the query contains proxy read or expand fragments, entities up or down the proxy chain might match due to this update.\n // We have to run the entire query again and compare the result.\n // TODO: We might be able to make this more efficient by first computing the set of entities that are potentially touched by this update\n // and then only rerun the query on this set.\n const newMatchingSet = runQuery(fragments, options?.initialSet);\n const updates: (ComponentUpdate & { type: UpdateType })[] = [];\n\n for (const previouslyMatchingEntity of matching) {\n // Entity matched before but doesn't match now\n if (!newMatchingSet.has(previouslyMatchingEntity)) {\n matching.delete(previouslyMatchingEntity);\n updates.push({\n entity: previouslyMatchingEntity,\n type: UpdateType.Exit,\n component: update.component,\n value: [undefined, undefined],\n });\n }\n }\n\n for (const matchingEntity of newMatchingSet) {\n if (matching.has(matchingEntity)) {\n // Entity matched before and still matches\n updates.push({\n entity: matchingEntity,\n type: UpdateType.Update,\n component: update.component,\n value: [getComponentValue(update.component, matchingEntity), undefined],\n });\n } else {\n // Entity didn't match before but matches now\n matching.add(matchingEntity);\n updates.push({\n entity: matchingEntity,\n type: UpdateType.Enter,\n component: update.component,\n value: [getComponentValue(update.component, matchingEntity), undefined],\n });\n }\n }\n\n return of(...updates);\n })\n : // Query does not contain proxies\n map((update) => {\n if (matching.has(update.entity)) {\n // If this entity matched the query before, check if it still matches it\n // Find fragments accessign this component (linear search is fine since the number fragments is likely small)\n const relevantFragments = fragments.filter((f) => f.component.id === update.component.id);\n const pass = relevantFragments.every((f) => passesQueryFragment(update.entity, f as EntityQueryFragment)); // We early return if the query contains proxies\n\n if (pass) {\n // Entity passed before and still passes, forward update\n return { ...update, type: UpdateType.Update };\n } else {\n // Entity passed before but not anymore, forward update and exit\n matching.delete(update.entity);\n return { ...update, type: UpdateType.Exit };\n }\n }\n\n // This entity didn't match before, check all fragments\n const pass = fragments.every((f) => passesQueryFragment(update.entity, f as EntityQueryFragment)); // We early return if the query contains proxies\n if (pass) {\n // Entity didn't pass before but passes now, forward update end enter\n matching.add(update.entity);\n return { ...update, type: UpdateType.Enter };\n }\n }),\n filterNullish(),\n );\n\n return {\n matching,\n update$: concat(initial$, internal$).pipe(share()),\n };\n}\n\n/**\n * Define a query object that only passes update events of type {@link UpdateType}.Update to the `update$` stream.\n * See {@link defineQuery} for details.\n *\n * @param fragments Query fragments\n * @returns Stream of component updates of entities that had already matched the query\n */\nexport function defineUpdateQuery(\n fragments: QueryFragment[],\n options?: { runOnInit?: boolean },\n): Observable<ComponentUpdate & { type: UpdateType }> {\n return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Update));\n}\n\n/**\n * Define a query object that only passes update events of type {@link UpdateType}.Enter to the `update$` stream.\n * See {@link defineQuery} for details.\n *\n * @param fragments Query fragments\n * @returns Stream of component updates of entities matching the query for the first time\n */\nexport function defineEnterQuery(\n fragments: QueryFragment[],\n options?: { runOnInit?: boolean },\n): Observable<ComponentUpdate> {\n return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Enter));\n}\n\n/**\n * Define a query object that only passes update events of type {@link UpdateType}.Exit to the `update$` stream.\n * See {@link defineQuery} for details.\n *\n * @param fragments Query fragments\n * @returns Stream of component updates of entities not matching the query anymore for the first time\n */\nexport function defineExitQuery(\n fragments: QueryFragment[],\n options?: { runOnInit?: boolean },\n): Observable<ComponentUpdate> {\n return defineQuery(fragments, options).update$.pipe(filter((e) => e.type === UpdateType.Exit));\n}\n","import { Subject } from \"rxjs\";\nimport { Type } from \"./constants\";\nimport { Opaque } from \"type-fest\";\n\n/**\n * Entities are represented as symbols internally for memory efficiency.\n * To get the entity's string representation, use `getEntityString(entitySymbol)`\n */\nexport type EntitySymbol = Opaque<symbol, \"EntitySymbol\">;\n\nexport type Entity = Opaque<string, \"Entity\">;\n\n/**\n * Used to define the schema of a {@link Component}.\n * Uses {@link Type} enum to be able to access the component type in JavaScript as well as have TypeScript type checks.\n */\nexport type Schema = {\n [key: string]: Type;\n};\n\n/**\n * Used to add arbitrary metadata to components.\n */\nexport type Metadata =\n | {\n [key: string]: unknown;\n }\n | undefined;\n\n/**\n * Mapping between JavaScript {@link Type} enum and corresponding TypeScript type.\n */\nexport type ValueType<T = unknown> = {\n [Type.Boolean]: boolean;\n [Type.Number]: number;\n [Type.BigInt]: bigint;\n [Type.String]: string;\n [Type.NumberArray]: number[];\n [Type.BigIntArray]: bigint[];\n [Type.StringArray]: string[];\n [Type.Entity]: Entity;\n [Type.EntityArray]: Entity[];\n [Type.OptionalNumber]: number | undefined;\n [Type.OptionalBigInt]: bigint | undefined;\n [Type.OptionalBigIntArray]: bigint[] | undefined;\n [Type.OptionalString]: string | undefined;\n [Type.OptionalNumberArray]: number[] | undefined;\n [Type.OptionalStringArray]: string[] | undefined;\n [Type.OptionalEntity]: Entity | undefined;\n [Type.OptionalEntityArray]: Entity[] | undefined;\n [Type.T]: T;\n [Type.OptionalT]: T | undefined;\n};\n\n/**\n * Used to infer the TypeScript type of a component value corresponding to a given {@link Schema}.\n */\nexport type ComponentValue<S extends Schema = Schema, T = unknown> = {\n [key in keyof S]: ValueType<T>[S[key]];\n};\n\n/**\n * Type of a component update corresponding to a given {@link Schema}.\n */\nexport type ComponentUpdate<S extends Schema = Schema, T = unknown> = {\n entity: Entity;\n value: [ComponentValue<S, T> | undefined, ComponentValue<S, T> | undefined];\n component: Component<S, Metadata, T>;\n};\n\n/**\n * Type of component returned by {@link defineComponent}.\n */\nexport interface Component<S extends Schema = Schema, M extends Metadata = Metadata, T = unknown> {\n id: string;\n values: { [key in keyof S]: Map<EntitySymbol, ValueType<T>[S[key]]> };\n schema: S;\n metadata: M;\n entities: () => IterableIterator<Entity>;\n world: World;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n update$: Subject<ComponentUpdate<S, T>> & { observers: any };\n}\n\n/**\n * Type of indexer returned by {@link createIndexer}.\n */\nexport type Indexer<S extends Schema, M extends Metadata = Metadata, T = unknown> = Component<S, M, T> & {\n getEntitiesWithValue: (value: ComponentValue<S, T>) => Set<Entity>;\n};\n\nexport type Components = {\n [key: string]: Component;\n};\n\nexport interface ComponentWithStream<S extends Schema, T = unknown> extends Component<S, Metadata, T> {\n stream$: Subject<{ entity: Entity; value: ComponentValue<S, T> | undefined }>;\n}\n\nexport type AnyComponentValue = ComponentValue<Schema>;\n\nexport type AnyComponent = Component<Schema>;\n\n/**\n * Type of World returned by {@link createWorld}.\n */\nexport type World = {\n registerEntity: (options?: { id?: string; idSuffix?: string }) => Entity;\n registerComponent: (component: Component) => void;\n components: Component[];\n getEntities: () => IterableIterator<Entity>;\n dispose: () => void;\n registerDisposer: (disposer: () => void) => void;\n hasEntity: (entity: Entity) => boolean;\n deleteEntity: (entity: Entity) => void;\n entitySymbols: Set<EntitySymbol>;\n};\n\nexport enum QueryFragmentType {\n Has,\n HasValue,\n Not,\n NotValue,\n ProxyRead,\n ProxyExpand,\n}\n\nexport type HasQueryFragment<T extends Schema> = {\n type: QueryFragmentType.Has;\n component: Component<T>;\n};\n\nexport type HasValueQueryFragment<T extends Schema> = {\n type: QueryFragmentType.HasValue;\n component: Component<T>;\n value: Partial<ComponentValue<T>>;\n};\n\nexport type NotQueryFragment<T extends Schema> = {\n type: QueryFragmentType.Not;\n component: Component<T>;\n};\n\nexport type NotValueQueryFragment<T extends Schema> = {\n type: QueryFragmentType.NotValue;\n component: Component<T>;\n value: Partial<ComponentValue<T>>;\n};\n\nexport type ProxyReadQueryFragment = {\n type: QueryFragmentType.ProxyRead;\n component: Component<{ value: Type.Entity }>;\n depth: number;\n};\n\nexport type ProxyExpandQueryFragment = {\n type: QueryFragmentType.ProxyExpand;\n component: Component<{ value: Type.Entity }>;\n depth: number;\n};\n\nexport type QueryFragment<T extends Schema = Schema> =\n | HasQueryFragment<T>\n | HasValueQueryFragment<T>\n | NotQueryFragment<T>\n | NotValueQueryFragment<T>\n | ProxyReadQueryFragment\n | ProxyExpandQueryFragment;\n\nexport type EntityQueryFragment<T extends Schema = Schema> =\n | HasQueryFragment<T>\n | HasValueQueryFragment<T>\n | NotQueryFragment<T>\n | NotValueQueryFragment<T>;\n\nexport type SettingQueryFragment = ProxyReadQueryFragment | ProxyExpandQueryFragment;\n\nexport type QueryFragments = QueryFragment<Schema>[];\n\nexport type SchemaOf<C extends Component<Schema>> = C extends Component<infer S> ? S : never;\n\nexport type Override<S extends Schema, T = unknown> = {\n entity: Entity;\n value: Partial<ComponentValue<S, T>> | null;\n};\n\n/**\n * Type of overridable component returned by {@link overridableComponent}.\n */\nexport type OverridableComponent<S extends Schema = Schema, M extends Metadata = Metadata, T = unknown> = Component<\n S,\n M,\n T\n> & {\n addOverride: (overrideId: string, update: Override<S, T>) => void;\n removeOverride: (overrideId: string) => void;\n};\n\nexport type OptionalType =\n | Type.OptionalNumber\n | Type.OptionalBigInt\n | Type.OptionalString\n | Type.OptionalEntity\n | Type.OptionalNumberArray\n | Type.OptionalBigIntArray\n | Type.OptionalStringArray\n | Type.OptionalEntityArray;\n\nexport function isOptionalType(t: Type): t is OptionalType {\n return [\n Type.OptionalNumber,\n Type.OptionalBigInt,\n Type.OptionalString,\n Type.OptionalEntity,\n Type.OptionalEntityArray,\n Type.OptionalNumberArray,\n Type.OptionalBigIntArray,\n Type.OptionalStringArray,\n ].includes(t);\n}\n\nexport type ArrayType =\n | Type.NumberArray\n | Type.OptionalNumberArray\n | Type.BigIntArray\n | Type.OptionalBigIntArray\n | Type.StringArray\n | Type.OptionalStringArray\n | Type.EntityArray\n | Type.OptionalEntityArray;\n\nexport function isArrayType(t: Type): t is ArrayType {\n return [\n Type.NumberArray,\n Type.OptionalNumberArray,\n Type.BigIntArray,\n Type.OptionalBigIntArray,\n Type.StringArray,\n Type.OptionalStringArray,\n Type.EntityArray,\n Type.OptionalEntityArray,\n ].includes(t);\n}\n\nexport type NumberType = Type.Number | Type.OptionalNumber;\nexport function isNumberType(t: Type): t is NumberType {\n return [Type.Number, Type.OptionalNumber].includes(t);\n}\n\nexport type EntityType = Type.Entity | Type.OptionalEntity;\nexport function isEntityType(t: Type): t is EntityType {\n return [Type.Entity, Type.OptionalEntity].includes(t);\n}\n\nexport type Layer = {\n world: World;\n components: Record<string, Component<Schema>>;\n};\n\nexport type Layers = Record<string, Layer>;\n","import { transformIterator } from \"@latticexyz/utils\";\nimport { hasComponent, removeComponent } from \"./Component\";\nimport { getEntityString, getEntitySymbol } from \"./Entity\";\nimport { Component, Entity, EntitySymbol, World } from \"./types\";\n\n/**\n * Create a new World.\n *\n * @remarks\n * A World is the central object of an ECS application, where all {@link defineComponent Components},\n * {@link registerEntity Entities} and {@link defineSystem Systems} are registerd.\n *\n * @returns A new World\n */\nexport function createWorld() {\n const entitySymbols = new Set<EntitySymbol>();\n const components: Component[] = [];\n let disposers: [string, () => void][] = [];\n\n function registerEntity({ id, idSuffix }: { id?: string; idSuffix?: string } = {}) {\n const entity = (id || entitySymbols.size + (idSuffix ? \"-\" + idSuffix : \"\")) as Entity;\n const entitySymbol = getEntitySymbol(entity);\n\n // Register entity\n entitySymbols.add(entitySymbol);\n\n return entity;\n }\n\n function getEntities() {\n return transformIterator(entitySymbols.values(), getEntityString);\n }\n\n function registerComponent(component: Component) {\n components.push(component);\n }\n\n function dispose(namespace?: string) {\n for (const [, disposer] of disposers.filter((d) => !namespace || d[0] === namespace)) {\n disposer();\n }\n disposers = disposers.filter((d) => namespace && d[0] !== namespace);\n }\n\n function registerDisposer(disposer: () => void, namespace = \"\") {\n disposers.push([namespace, disposer]);\n }\n\n function hasEntity(entity: Entity): boolean {\n const entitySymbol = getEntitySymbol(entity);\n return entitySymbols.has(entitySymbol);\n }\n\n function deleteEntity(entity: Entity) {\n for (const component of components) {\n if (hasComponent(component, entity)) removeComponent(component, entity);\n }\n entitySymbols.delete(getEntitySymbol(entity));\n }\n\n return {\n registerEntity,\n components,\n registerComponent,\n dispose,\n registerDisposer,\n hasEntity,\n getEntities,\n entitySymbols,\n deleteEntity,\n } satisfies World;\n}\n\n/**\n * Create a new namespace from an existing World.\n * The `dispose` method of a namespaced World only calls disposers registered on this namespace.\n *\n * @param world World to create a new namespace for.\n * @param namespace String descriptor of the new namespace.\n * @returns World with a new namespace.\n */\nexport function namespaceWorld(world: ReturnType<typeof createWorld>, namespace: string) {\n return {\n ...world,\n registerDisposer: (disposer: () => void) => world.registerDisposer(disposer, namespace),\n dispose: () => world.dispose(namespace),\n };\n}\n\n/**\n * Get all components that have a value for the given entity.\n *\n * @dev Design decision: don't store a list of components for each entity but compute it dynamically when needed\n * because there are less components than entities and maintaining a list of components per entity is a large overhead.\n *\n * @param world World object the given entity is registered on.\n * @param entity {@link Entity} to get the list of components for.\n * @returns Array of components that have a value for the given entity.\n */\nexport function getEntityComponents(world: World, entity: Entity): Component[] {\n return world.components.filter((component) => hasComponent(component, entity));\n}\n"],"mappings":"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","names":["concat","EMPTY","from","filterNullish","observable","concat","concatMap","filter","from","map","merge","of","share","QueryFragmentType","isOptionalType","t","isArrayType","isNumberType","isEntityType","Has","component","Not","HasValue","value","NotValue","ProxyRead","depth","ProxyExpand","passesQueryFragment","entity","fragment","hasComponent","componentValueEquals","getComponentValue","isPositiveFragment","isNegativeFragment","isSettingFragment","isBreakingPassState","passes","passesQueryFragmentProxy","proxyRead","proxyEntity","i","getChildEntities","directChildEntities","getEntitiesWithValue","indirectChildEntities","childEntity","runQuery","fragments","initialSet","entities","proxyExpand","childEntities","getComponentEntities","defineQuery","options","matching","observable","initial$","from","toUpdateStream","containsProxy","v","internal$","merge","f","concatMap","update","newMatchingSet","updates","previouslyMatchingEntity","matchingEntity","of","map","filterNullish","concat","share","defineUpdateQuery","filter","e","defineEnterQuery","defineExitQuery","defineRxSystem","world","observable$","system","subscription","defineUpdateSystem","query","options","defineUpdateQuery","defineEnterSystem","defineEnterQuery","defineExitSystem","defineExitQuery","defineSystem","defineQuery","defineComponentSystem","component","initial$","from","getComponentEntities","toUpdateStream","EMPTY","concat","defineSyncSystem","value","entity","type","setComponent","removeComponent","transformIterator","createWorld","entitySymbols","components","disposers","registerEntity","id","idSuffix","entity","entitySymbol","getEntitySymbol","getEntities","transformIterator","getEntityString","registerComponent","component","dispose","namespace","disposer","d","registerDisposer","hasEntity","deleteEntity","hasComponent","removeComponent","namespaceWorld","world","getEntityComponents"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latticexyz/recs",
3
- "version": "2.2.18-318924725246340b208d3fbee8793314686f1759",
3
+ "version": "2.2.18-41fe36dd2756fe87bfe141e15b6d102f4b070ab1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/latticexyz/mud.git",
@@ -28,8 +28,8 @@
28
28
  "dependencies": {
29
29
  "mobx": "^6.7.0",
30
30
  "rxjs": "7.5.5",
31
- "@latticexyz/schema-type": "2.2.18-318924725246340b208d3fbee8793314686f1759",
32
- "@latticexyz/utils": "2.2.18-318924725246340b208d3fbee8793314686f1759"
31
+ "@latticexyz/schema-type": "2.2.18-41fe36dd2756fe87bfe141e15b6d102f4b070ab1",
32
+ "@latticexyz/utils": "2.2.18-41fe36dd2756fe87bfe141e15b6d102f4b070ab1"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/jest": "^27.4.1",