ecspresso 0.4.2 → 0.5.0

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.
@@ -1,4 +1,4 @@
1
- import type { Entity, FilteredEntity } from "./types";
1
+ import type { Entity, FilteredEntity, RemoveEntityOptions } from "./types";
2
2
  export default class EntityManager<ComponentTypes> {
3
3
  private nextId;
4
4
  private entities;
@@ -11,6 +11,10 @@ export default class EntityManager<ComponentTypes> {
11
11
  * Callbacks registered for component removals
12
12
  */
13
13
  private removedCallbacks;
14
+ /**
15
+ * Hierarchy manager for parent-child relationships
16
+ */
17
+ private hierarchyManager;
14
18
  createEntity(): Entity<ComponentTypes>;
15
19
  addComponent<ComponentName extends keyof ComponentTypes>(entityOrId: number | Entity<ComponentTypes>, componentName: ComponentName, data: ComponentTypes[ComponentName]): this;
16
20
  /**
@@ -24,7 +28,11 @@ export default class EntityManager<ComponentTypes> {
24
28
  removeComponent<ComponentName extends keyof ComponentTypes>(entityOrId: number | Entity<ComponentTypes>, componentName: ComponentName): this;
25
29
  getComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName): ComponentTypes[ComponentName] | null;
26
30
  getEntitiesWithQuery<WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never>(required?: ReadonlyArray<WithComponents>, excluded?: ReadonlyArray<WithoutComponents>): Array<FilteredEntity<ComponentTypes, WithComponents extends never ? never : WithComponents, WithoutComponents extends never ? never : WithoutComponents>>;
27
- removeEntity(entityOrId: number | Entity<ComponentTypes>): boolean;
31
+ removeEntity(entityOrId: number | Entity<ComponentTypes>, options?: RemoveEntityOptions): boolean;
32
+ /**
33
+ * Internal method to remove a single entity without cascade logic
34
+ */
35
+ private removeEntityInternal;
28
36
  getEntity(entityId: number): Entity<ComponentTypes> | undefined;
29
37
  /**
30
38
  * Register a callback when a specific component is added to any entity
@@ -38,4 +46,94 @@ export default class EntityManager<ComponentTypes> {
38
46
  * @param handler Function receiving the old component value and the entity
39
47
  */
40
48
  onComponentRemoved<ComponentName extends keyof ComponentTypes>(componentName: ComponentName, handler: (oldValue: ComponentTypes[ComponentName], entity: Entity<ComponentTypes>) => void): this;
49
+ /**
50
+ * Create an entity as a child of another entity with initial components
51
+ * @param parentId The parent entity ID
52
+ * @param components Initial components to add
53
+ * @returns The created child entity
54
+ */
55
+ spawnChild<T extends {
56
+ [K in keyof ComponentTypes]?: ComponentTypes[K];
57
+ }>(parentId: number, components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): FilteredEntity<ComponentTypes, keyof T & keyof ComponentTypes, never>;
58
+ /**
59
+ * Set the parent of an entity
60
+ * @param childId The entity to set as a child
61
+ * @param parentId The entity to set as the parent
62
+ */
63
+ setParent(childId: number, parentId: number): this;
64
+ /**
65
+ * Remove the parent relationship for an entity (orphan it)
66
+ * @param childId The entity to orphan
67
+ * @returns true if a parent was removed, false if entity had no parent
68
+ */
69
+ removeParent(childId: number): boolean;
70
+ /**
71
+ * Get the parent of an entity
72
+ * @param entityId The entity to get the parent of
73
+ * @returns The parent entity ID, or null if no parent
74
+ */
75
+ getParent(entityId: number): number | null;
76
+ /**
77
+ * Get all children of an entity in insertion order
78
+ * @param parentId The parent entity
79
+ * @returns Readonly array of child entity IDs
80
+ */
81
+ getChildren(parentId: number): readonly number[];
82
+ /**
83
+ * Get a child at a specific index
84
+ * @param parentId The parent entity
85
+ * @param index The index of the child
86
+ * @returns The child entity ID, or null if index is out of bounds
87
+ */
88
+ getChildAt(parentId: number, index: number): number | null;
89
+ /**
90
+ * Get the index of a child within its parent's children list
91
+ * @param parentId The parent entity
92
+ * @param childId The child entity to find
93
+ * @returns The index of the child, or -1 if not found
94
+ */
95
+ getChildIndex(parentId: number, childId: number): number;
96
+ /**
97
+ * Get all ancestors of an entity in order [parent, grandparent, ...]
98
+ * @param entityId The entity to get ancestors of
99
+ * @returns Readonly array of ancestor entity IDs
100
+ */
101
+ getAncestors(entityId: number): readonly number[];
102
+ /**
103
+ * Get all descendants of an entity in depth-first order
104
+ * @param entityId The entity to get descendants of
105
+ * @returns Readonly array of descendant entity IDs
106
+ */
107
+ getDescendants(entityId: number): readonly number[];
108
+ /**
109
+ * Get the root ancestor of an entity (topmost parent), or self if no parent
110
+ * @param entityId The entity to get the root of
111
+ * @returns The root entity ID
112
+ */
113
+ getRoot(entityId: number): number;
114
+ /**
115
+ * Get siblings of an entity (other children of the same parent)
116
+ * @param entityId The entity to get siblings of
117
+ * @returns Readonly array of sibling entity IDs
118
+ */
119
+ getSiblings(entityId: number): readonly number[];
120
+ /**
121
+ * Check if an entity is a descendant of another entity
122
+ * @param entityId The potential descendant
123
+ * @param ancestorId The potential ancestor
124
+ * @returns true if entityId is a descendant of ancestorId
125
+ */
126
+ isDescendantOf(entityId: number, ancestorId: number): boolean;
127
+ /**
128
+ * Check if an entity is an ancestor of another entity
129
+ * @param entityId The potential ancestor
130
+ * @param descendantId The potential descendant
131
+ * @returns true if entityId is an ancestor of descendantId
132
+ */
133
+ isAncestorOf(entityId: number, descendantId: number): boolean;
134
+ /**
135
+ * Get all root entities (entities that have children but no parent)
136
+ * @returns Readonly array of root entity IDs
137
+ */
138
+ getRootEntities(): readonly number[];
41
139
  }
@@ -8,6 +8,11 @@ export default class EventBus<EventTypes> {
8
8
  * Subscribe to an event once
9
9
  */
10
10
  once<E extends keyof EventTypes>(eventType: E, callback: (data: EventTypes[E]) => void): () => void;
11
+ /**
12
+ * Unsubscribe a specific callback from an event by reference
13
+ * @returns true if the callback was found and removed, false otherwise
14
+ */
15
+ unsubscribe<E extends keyof EventTypes>(eventType: E, callback: (data: EventTypes[E]) => void): boolean;
11
16
  /**
12
17
  * Internal method to add an event handler
13
18
  */
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Manages parent-child relationships between entities.
3
+ * Handles hierarchy storage, validation, and traversal operations.
4
+ */
5
+ export default class HierarchyManager {
6
+ /** childId -> parentId */
7
+ private parentMap;
8
+ /** parentId -> ordered childIds */
9
+ private childrenMap;
10
+ /**
11
+ * Set the parent of an entity.
12
+ * @param childId The entity to set as a child
13
+ * @param parentId The entity to set as the parent
14
+ * @throws Error if this would create a circular reference or self-parenting
15
+ */
16
+ setParent(childId: number, parentId: number): this;
17
+ /**
18
+ * Remove the parent relationship for an entity (orphan it).
19
+ * @param childId The entity to orphan
20
+ * @returns true if a parent was removed, false if entity had no parent
21
+ */
22
+ removeParent(childId: number): boolean;
23
+ /**
24
+ * Get the parent of an entity.
25
+ * @param entityId The entity to get the parent of
26
+ * @returns The parent entity ID, or null if no parent
27
+ */
28
+ getParent(entityId: number): number | null;
29
+ /**
30
+ * Get all children of an entity in insertion order.
31
+ * @param parentId The parent entity
32
+ * @returns Readonly array of child entity IDs
33
+ */
34
+ getChildren(parentId: number): readonly number[];
35
+ /**
36
+ * Get a child at a specific index.
37
+ * @param parentId The parent entity
38
+ * @param index The index of the child
39
+ * @returns The child entity ID, or null if index is out of bounds
40
+ */
41
+ getChildAt(parentId: number, index: number): number | null;
42
+ /**
43
+ * Get the index of a child within its parent's children list.
44
+ * @param parentId The parent entity
45
+ * @param childId The child entity to find
46
+ * @returns The index of the child, or -1 if not found
47
+ */
48
+ getChildIndex(parentId: number, childId: number): number;
49
+ /**
50
+ * Remove an entity from the hierarchy (called when entity is destroyed).
51
+ * Orphans any children and removes from parent's children list.
52
+ * @param entityId The entity being removed
53
+ * @returns Information about the removal (oldParent and orphanedChildren)
54
+ */
55
+ removeEntity(entityId: number): {
56
+ oldParent: number | null;
57
+ orphanedChildren: number[];
58
+ };
59
+ /**
60
+ * Get all ancestors of an entity in order [parent, grandparent, ...].
61
+ * @param entityId The entity to get ancestors of
62
+ * @returns Readonly array of ancestor entity IDs
63
+ */
64
+ getAncestors(entityId: number): readonly number[];
65
+ /**
66
+ * Get all descendants of an entity in depth-first order.
67
+ * @param entityId The entity to get descendants of
68
+ * @returns Readonly array of descendant entity IDs
69
+ */
70
+ getDescendants(entityId: number): readonly number[];
71
+ /**
72
+ * Get the root ancestor of an entity (topmost parent), or self if no parent.
73
+ * @param entityId The entity to get the root of
74
+ * @returns The root entity ID
75
+ */
76
+ getRoot(entityId: number): number;
77
+ /**
78
+ * Get siblings of an entity (other children of the same parent).
79
+ * @param entityId The entity to get siblings of
80
+ * @returns Readonly array of sibling entity IDs
81
+ */
82
+ getSiblings(entityId: number): readonly number[];
83
+ /**
84
+ * Check if an entity is a descendant of another entity.
85
+ * @param entityId The potential descendant
86
+ * @param ancestorId The potential ancestor
87
+ * @returns true if entityId is a descendant of ancestorId
88
+ */
89
+ isDescendantOf(entityId: number, ancestorId: number): boolean;
90
+ /**
91
+ * Check if an entity is an ancestor of another entity.
92
+ * @param entityId The potential ancestor
93
+ * @param descendantId The potential descendant
94
+ * @returns true if entityId is an ancestor of descendantId
95
+ */
96
+ isAncestorOf(entityId: number, descendantId: number): boolean;
97
+ /**
98
+ * Get all root entities (entities that have children but no parent).
99
+ * @returns Readonly array of root entity IDs
100
+ */
101
+ getRootEntities(): readonly number[];
102
+ /**
103
+ * Check if setting a parent would create a cycle.
104
+ * A cycle would occur if the prospective parent is a descendant of the child.
105
+ */
106
+ private wouldCreateCycle;
107
+ }
package/dist/index.d.ts CHANGED
@@ -2,13 +2,18 @@ import ECSpresso from './ecspresso';
2
2
  import { SystemBuilder } from './system-builder';
3
3
  import Bundle, { mergeBundles } from './bundle';
4
4
  export * from './types';
5
+ export * from './asset-types';
6
+ export * from './screen-types';
5
7
  export { default as EntityManager } from './entity-manager';
6
8
  export { default as EventBus } from './event-bus';
9
+ export { default as HierarchyManager } from './hierarchy-manager';
7
10
  /**
8
11
  * @internal ResourceManager is exported for testing purposes only.
9
12
  * Use ECSpresso resource methods instead: getResource(), addResource(), removeResource(), updateResource(), hasResource()
10
13
  */
11
14
  export { default as ResourceManager } from './resource-manager';
15
+ export { default as AssetManager, createAssetConfigurator } from './asset-manager';
16
+ export { default as ScreenManager, createScreenConfigurator } from './screen-manager';
12
17
  export { SystemBuilder };
13
18
  export { Bundle, mergeBundles };
14
19
  export default ECSpresso;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- class ${nextId=1;entities=new Map;componentIndices=new Map;addedCallbacks=new Map;removedCallbacks=new Map;createEntity(){let j=this.nextId++,G={id:j,components:{}};return this.entities.set(j,G),G}addComponent(j,G,H){let J=typeof j==="number"?this.entities.get(j):j;if(!J){let X=typeof j==="number"?j:j.id;throw new Error(`Cannot add component '${String(G)}': Entity with ID ${X} does not exist`)}if(J.components[G]=H,!this.componentIndices.has(G))this.componentIndices.set(G,new Set);this.componentIndices.get(G)?.add(J.id);let P=this.addedCallbacks.get(G);if(P)for(let X of P)X(H,J);return this}addComponents(j,G){let H=typeof j==="number"?this.entities.get(j):j;if(!H){let J=typeof j==="number"?j:j.id;throw new Error(`Cannot add components: Entity with ID ${J} does not exist`)}for(let J in G)this.addComponent(H,J,G[J]);return this}removeComponent(j,G){let H=typeof j==="number"?this.entities.get(j):j;if(!H){let X=typeof j==="number"?j:j.id;throw new Error(`Cannot remove component '${String(G)}': Entity with ID ${X} does not exist`)}let J=H.components[G];delete H.components[G];let P=this.removedCallbacks.get(G);if(P&&J!==void 0)for(let X of P)X(J,H);return this.componentIndices.get(G)?.delete(H.id),this}getComponent(j,G){let H=this.entities.get(j);if(!H)throw new Error(`Cannot get component '${String(G)}': Entity with ID ${j} does not exist`);return H.components[G]||null}getEntitiesWithQuery(j=[],G=[]){if(j.length===0){if(G.length===0)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((Y)=>{return G.every((Z)=>!(Z in Y.components))})}let H=j.reduce((Y,Z)=>{let _=this.componentIndices.get(Z)?.size??0,w=this.componentIndices.get(Y)?.size??1/0;return _<w?Z:Y},j[0]),J=this.componentIndices.get(H);if(!J||J.size===0)return[];let P=[],X=G.length>0;for(let Y of J){let Z=this.entities.get(Y);if(Z&&j.every((_)=>(_ in Z.components))&&(!X||G.every((_)=>!(_ in Z.components))))P.push(Z)}return P}removeEntity(j){let G=typeof j==="number"?this.entities.get(j):j;if(!G)return!1;for(let H of Object.keys(G.components)){let J=G.components[H];if(J!==void 0){let P=this.removedCallbacks.get(H);if(P)for(let X of P)X(J,G)}this.componentIndices.get(H)?.delete(G.id)}return this.entities.delete(G.id)}getEntity(j){return this.entities.get(j)}onComponentAdded(j,G){if(!this.addedCallbacks.has(j))this.addedCallbacks.set(j,new Set);return this.addedCallbacks.get(j).add(G),this}onComponentRemoved(j,G){if(!this.removedCallbacks.has(j))this.removedCallbacks.set(j,new Set);return this.removedCallbacks.get(j).add(G),this}}class A{handlers=new Map;subscribe(j,G){return this.addHandler(j,G,!1)}once(j,G){return this.addHandler(j,G,!0)}addHandler(j,G,H){if(!this.handlers.has(j))this.handlers.set(j,[]);let J={callback:G,once:H};return this.handlers.get(j).push(J),()=>{let P=this.handlers.get(j);if(P){let X=P.indexOf(J);if(X!==-1)P.splice(X,1)}}}publish(j,G){let H=this.handlers.get(j);if(!H)return;let J=[...H],P=[];for(let X of J)if(X.callback(G),X.once)P.push(X);if(P.length>0)for(let X of P){let Y=H.indexOf(X);if(Y!==-1)H.splice(Y,1)}}clear(){this.handlers.clear()}clearEvent(j){this.handlers.delete(j)}}class F{resources=new Map;resourceFactories=new Map;initializedResourceKeys=new Set;add(j,G){if(this._isFactoryFunction(G))this.resourceFactories.set(j,G);else this.resources.set(j,G),this.initializedResourceKeys.add(j);return this}_isFactoryFunction(j){if(typeof j!=="function")return!1;let G=j.toString();if(G.startsWith("class "))return!1;if(G.includes("[native code]"))return!1;if(j.prototype){let H=Object.getOwnPropertyNames(j.prototype);if(H.length>1||H.length===1&&H[0]!=="constructor")return!1}if(j.name&&j.name[0]===j.name[0].toUpperCase()&&j.name.length>1){if(G.includes("this.")||G.includes("new "))return!1}return!0}get(j,G){let H=this.resources.get(j);if(H!==void 0)return H;let J=this.resourceFactories.get(j);if(J===void 0)throw new Error(`Resource ${String(j)} not found`);let P=J(G);if(!(P instanceof Promise))this.resources.set(j,P),this.initializedResourceKeys.add(j);return P}has(j){return this.resources.has(j)||this.resourceFactories.has(j)}remove(j){let G=this.resources.delete(j),H=this.resourceFactories.delete(j);if(this.initializedResourceKeys.has(j))this.initializedResourceKeys.delete(j);return G||H}getKeys(){let j=new Set([...this.resources.keys(),...this.resourceFactories.keys()]);return Array.from(j)}needsInitialization(j){return this.resourceFactories.has(j)&&!this.initializedResourceKeys.has(j)}getPendingInitializationKeys(){return Array.from(this.resourceFactories.keys()).filter((j)=>!this.initializedResourceKeys.has(j))}async initializeResource(j,G){if(!this.resourceFactories.has(j)||this.initializedResourceKeys.has(j))return;let J=await this.resourceFactories.get(j)(G);this.resources.set(j,J),this.initializedResourceKeys.add(j),this.resourceFactories.delete(j)}async initializeResources(j,...G){if(G.length===0){let H=this.getPendingInitializationKeys();await Promise.all(H.map((J)=>this.initializeResource(J,j)));return}await Promise.all(G.map((H)=>this.initializeResource(H,j)))}}class M{_label;_ecspresso;_bundle;queries={};processFunction;detachFunction;initializeFunction;eventHandlers;_priority=0;_isRegistered=!1;constructor(j,G=null,H=null){this._label=j;this._ecspresso=G;this._bundle=H}get label(){return this._label}get bundle(){return this._bundle}get ecspresso(){return this._ecspresso}_autoRegister(){if(this._isRegistered||!this._ecspresso)return;let j=this._buildSystemObject();Q(j,this._ecspresso),this._isRegistered=!0}_buildSystemObject(){return this._createSystemObject()}_createSystemObject(){let j={label:this._label,entityQueries:this.queries,priority:this._priority};if(this.processFunction)j.process=this.processFunction;if(this.detachFunction)j.onDetach=this.detachFunction;if(this.initializeFunction)j.onInitialize=this.initializeFunction;if(this.eventHandlers)j.eventHandlers=this.eventHandlers;return j}setPriority(j){return this._priority=j,this}addQuery(j,G){let H=this;return H.queries={...this.queries,[j]:G},H}setProcess(j){return this.processFunction=j,this}registerAndContinue(){if(!this._ecspresso)throw new Error(`Cannot register system '${this._label}': SystemBuilder is not attached to an ECSpresso instance. Use Bundle.addSystem() or ECSpresso.addSystem() instead.`);return this._autoRegister(),this._ecspresso}and(){if(!this._ecspresso)throw new Error(`Cannot use and() method on system '${this._label}': SystemBuilder is not attached to an ECSpresso instance. Use Bundle.addSystem() instead.`);return this._autoRegister(),this._ecspresso}setOnDetach(j){return this.detachFunction=j,this}setOnInitialize(j){return this.initializeFunction=j,this}setEventHandlers(j){return this.eventHandlers=j,this}build(j){let G=this._createSystemObject();if(this._ecspresso)Q(G,this._ecspresso);if(j)Q(G,j);return this}}function Q(j,G){G._registerSystem(j)}function W(j,G){return new M(j,G)}function g(j,G){return new M(j,null,G)}var K="0.4.2";var f={};class U{static VERSION=K;_entityManager;_eventBus;_resourceManager;_systems=[];_sortedSystems=[];_installedBundles=new Set;constructor(){this._entityManager=new $,this._eventBus=new A,this._resourceManager=new F,this._sortedSystems=[]}static create(){return new V}addSystem(j){return W(j,this)}update(j){for(let G of this._sortedSystems){if(!G.process)continue;let H={},J=!1,P=!1;if(G.entityQueries)for(let X in G.entityQueries){P=!0;let Y=G.entityQueries[X];if(Y){if(H[X]=this._entityManager.getEntitiesWithQuery(Y.with,Y.without||[]),H[X].length)J=!0}}if(J)G.process(H,j,this);else if(!P)G.process(f,j,this)}}async initialize(){await this.initializeResources();for(let j of this._systems)await j.onInitialize?.(this)}async initializeResources(...j){await this._resourceManager.initializeResources(this,...j)}_sortSystems(){this._sortedSystems=[...this._systems].sort((j,G)=>{let H=j.priority??0;return(G.priority??0)-H})}updateSystemPriority(j,G){let H=this._systems.find((J)=>J.label===j);if(!H)return!1;return H.priority=G,this._sortSystems(),!0}removeSystem(j){let G=this._systems.findIndex((J)=>J.label===j);if(G===-1)return!1;let H=this._systems[G];if(!H)return!1;if(H.onDetach)H.onDetach(this);return this._systems.splice(G,1),this._sortSystems(),!0}_registerSystem(j){if(this._systems.push(j),this._sortSystems(),!j.eventHandlers)return;for(let G in j.eventHandlers){let H=j.eventHandlers[G]?.handler;if(H)this._eventBus.subscribe(G,(J)=>{H(J,this)})}}hasResource(j){return this._resourceManager.has(j)}getResource(j){let G=this._resourceManager.get(j,this);if(!G)throw new Error(`Resource '${String(j)}' not found. Available resources: [${this.getResourceKeys().map((H)=>String(H)).join(", ")}]`);return G}addResource(j,G){return this._resourceManager.add(j,G),this}removeResource(j){return this._resourceManager.remove(j)}updateResource(j,G){let H=this.getResource(j),J=G(H);return this._resourceManager.add(j,J),this}getResourceKeys(){return this._resourceManager.getKeys()}resourceNeedsInitialization(j){return this._resourceManager.needsInitialization(j)}hasComponent(j,G){return this._entityManager.getComponent(j,G)!==null}spawn(j){let G=this._entityManager.createEntity();return this._entityManager.addComponents(G,j),G}getEntitiesWithQuery(j,G=[]){return this._entityManager.getEntitiesWithQuery(j,G)}get installedBundles(){return Array.from(this._installedBundles)}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}_installBundle(j){if(this._installedBundles.has(j.id))return this;this._installedBundles.add(j.id),j.registerSystemsWithEcspresso(this);let G=j.getResources();for(let[H,J]of G.entries())this._resourceManager.add(H,J);return this}}class V{ecspresso;constructor(){this.ecspresso=new U}withBundle(j){return this.ecspresso._installBundle(j),this}build(){return this.ecspresso}}function z(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class D{_systems=[];_resources=new Map;_id;constructor(j){this._id=j||z()}get id(){return this._id}set id(j){this._id=j}addSystem(j){if(typeof j==="string"){let G=g(j,this);return this._systems.push(G),G}else return this._systems.push(j),j}addResource(j,G){return this._resources.set(j,G),this}getSystems(){return this._systems.map((j)=>j.build())}registerSystemsWithEcspresso(j){for(let G of this._systems)G.build(j)}getResources(){return new Map(this._resources)}getResource(j){return this._resources.get(j)}getSystemBuilders(){return[...this._systems]}hasResource(j){return this._resources.has(j)}}function E(j,...G){if(G.length===0)return new D(j);let H=new D(j);for(let J of G){for(let P of J.getSystemBuilders())H.addSystem(P);for(let[P,X]of J.getResources().entries())H.addResource(P,X)}return H}function p(j){return j}var a=U;export{E as mergeBundles,a as default,p as createQueryDefinition,M as SystemBuilder,F as ResourceManager,A as EventBus,$ as EntityManager,D as Bundle};
1
+ class H{parentMap=new Map;childrenMap=new Map;setParent(j,F){if(j===F)throw Error(`Cannot set entity ${j} as its own parent`);if(this.wouldCreateCycle(j,F))throw Error("Cannot set parent: would create circular reference");let J=this.parentMap.get(j);if(J!==void 0){let Y=this.childrenMap.get(J);if(Y){let Z=Y.indexOf(j);if(Z!==-1)Y.splice(Z,1)}}this.parentMap.set(j,F);let X=this.childrenMap.get(F);if(X)X.push(j);else this.childrenMap.set(F,[j]);return this}removeParent(j){let F=this.parentMap.get(j);if(F===void 0)return!1;let J=this.childrenMap.get(F);if(J){let X=J.indexOf(j);if(X!==-1)J.splice(X,1)}return this.parentMap.delete(j),!0}getParent(j){return this.parentMap.get(j)??null}getChildren(j){let F=this.childrenMap.get(j);return F?[...F]:[]}getChildAt(j,F){if(F<0)return null;let J=this.childrenMap.get(j);if(!J||F>=J.length)return null;return J[F]??null}getChildIndex(j,F){let J=this.childrenMap.get(j);if(!J)return-1;return J.indexOf(F)}removeEntity(j){let F=this.parentMap.get(j)??null;if(F!==null){let Y=this.childrenMap.get(F);if(Y){let Z=Y.indexOf(j);if(Z!==-1)Y.splice(Z,1)}}this.parentMap.delete(j);let J=this.childrenMap.get(j)??[],X=[...J];for(let Y of J)this.parentMap.delete(Y);return this.childrenMap.delete(j),{oldParent:F,orphanedChildren:X}}getAncestors(j){let F=[],J=this.parentMap.get(j);while(J!==void 0)F.push(J),J=this.parentMap.get(J);return F}getDescendants(j){let F=[],J=[...this.childrenMap.get(j)??[]];while(J.length>0){let X=J.shift();if(X===void 0)continue;F.push(X);let Y=this.childrenMap.get(X);if(Y)J.unshift(...Y)}return F}getRoot(j){let F=j,J=this.parentMap.get(F);while(J!==void 0)F=J,J=this.parentMap.get(F);return F}getSiblings(j){let F=this.parentMap.get(j);if(F===void 0)return[];let J=this.childrenMap.get(F);if(!J)return[];return J.filter((X)=>X!==j)}isDescendantOf(j,F){if(j===F)return!1;let J=this.parentMap.get(j);while(J!==void 0){if(J===F)return!0;J=this.parentMap.get(J)}return!1}isAncestorOf(j,F){return this.isDescendantOf(F,j)}getRootEntities(){let j=[];for(let F of this.childrenMap.keys())if(!this.parentMap.has(F))j.push(F);return j}wouldCreateCycle(j,F){let J=F;while(J!==void 0){if(J===j)return!0;J=this.parentMap.get(J)}return!1}}class U{nextId=1;entities=new Map;componentIndices=new Map;addedCallbacks=new Map;removedCallbacks=new Map;hierarchyManager=new H;createEntity(){let j=this.nextId++,F={id:j,components:{}};return this.entities.set(j,F),F}addComponent(j,F,J){let X=typeof j==="number"?this.entities.get(j):j;if(!X){let Z=typeof j==="number"?j:j.id;throw Error(`Cannot add component '${String(F)}': Entity with ID ${Z} does not exist`)}if(X.components[F]=J,!this.componentIndices.has(F))this.componentIndices.set(F,new Set);this.componentIndices.get(F)?.add(X.id);let Y=this.addedCallbacks.get(F);if(Y)for(let Z of Y)Z(J,X);return this}addComponents(j,F){let J=typeof j==="number"?this.entities.get(j):j;if(!J){let X=typeof j==="number"?j:j.id;throw Error(`Cannot add components: Entity with ID ${X} does not exist`)}for(let X in F)this.addComponent(J,X,F[X]);return this}removeComponent(j,F){let J=typeof j==="number"?this.entities.get(j):j;if(!J){let Z=typeof j==="number"?j:j.id;throw Error(`Cannot remove component '${String(F)}': Entity with ID ${Z} does not exist`)}let X=J.components[F];delete J.components[F];let Y=this.removedCallbacks.get(F);if(Y&&X!==void 0)for(let Z of Y)Z(X,J);return this.componentIndices.get(F)?.delete(J.id),this}getComponent(j,F){let J=this.entities.get(j);if(!J)throw Error(`Cannot get component '${String(F)}': Entity with ID ${j} does not exist`);return J.components[F]||null}getEntitiesWithQuery(j=[],F=[]){if(j.length===0){if(F.length===0)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((_)=>{return F.every(($)=>!($ in _.components))})}let J=j.reduce((_,$)=>{let G=this.componentIndices.get($)?.size??0,C=this.componentIndices.get(_)?.size??1/0;return G<C?$:_},j[0]),X=this.componentIndices.get(J);if(!X||X.size===0)return[];let Y=[],Z=F.length>0;for(let _ of X){let $=this.entities.get(_);if($&&j.every((G)=>(G in $.components))&&(!Z||F.every((G)=>!(G in $.components))))Y.push($)}return Y}removeEntity(j,F){let J=typeof j==="number"?this.entities.get(j):j;if(!J)return!1;if(F?.cascade??!0){let Y=this.hierarchyManager.getDescendants(J.id);for(let Z of[...Y].reverse())this.removeEntityInternal(Z)}return this.removeEntityInternal(J.id)}removeEntityInternal(j){let F=this.entities.get(j);if(!F)return!1;this.hierarchyManager.removeEntity(j);for(let J of Object.keys(F.components)){let X=F.components[J];if(X!==void 0){let Y=this.removedCallbacks.get(J);if(Y)for(let Z of Y)Z(X,F)}this.componentIndices.get(J)?.delete(F.id)}return this.entities.delete(F.id)}getEntity(j){return this.entities.get(j)}onComponentAdded(j,F){if(!this.addedCallbacks.has(j))this.addedCallbacks.set(j,new Set);return this.addedCallbacks.get(j).add(F),this}onComponentRemoved(j,F){if(!this.removedCallbacks.has(j))this.removedCallbacks.set(j,new Set);return this.removedCallbacks.get(j).add(F),this}spawnChild(j,F){let J=this.createEntity();return this.addComponents(J,F),this.setParent(J.id,j),J}setParent(j,F){return this.hierarchyManager.setParent(j,F),this}removeParent(j){return this.hierarchyManager.removeParent(j)}getParent(j){return this.hierarchyManager.getParent(j)}getChildren(j){return this.hierarchyManager.getChildren(j)}getChildAt(j,F){return this.hierarchyManager.getChildAt(j,F)}getChildIndex(j,F){return this.hierarchyManager.getChildIndex(j,F)}getAncestors(j){return this.hierarchyManager.getAncestors(j)}getDescendants(j){return this.hierarchyManager.getDescendants(j)}getRoot(j){return this.hierarchyManager.getRoot(j)}getSiblings(j){return this.hierarchyManager.getSiblings(j)}isDescendantOf(j,F){return this.hierarchyManager.isDescendantOf(j,F)}isAncestorOf(j,F){return this.hierarchyManager.isAncestorOf(j,F)}getRootEntities(){return this.hierarchyManager.getRootEntities()}}class D{handlers=new Map;subscribe(j,F){return this.addHandler(j,F,!1)}once(j,F){return this.addHandler(j,F,!0)}unsubscribe(j,F){let J=this.handlers.get(j);if(!J)return!1;let X=J.findIndex((Y)=>Y.callback===F);if(X===-1)return!1;return J.splice(X,1),!0}addHandler(j,F,J){if(!this.handlers.has(j))this.handlers.set(j,[]);let X={callback:F,once:J};return this.handlers.get(j).push(X),()=>{let Y=this.handlers.get(j);if(Y){let Z=Y.indexOf(X);if(Z!==-1)Y.splice(Z,1)}}}publish(j,F){let J=this.handlers.get(j);if(!J)return;let X=[...J],Y=[];for(let Z of X)if(Z.callback(F),Z.once)Y.push(Z);if(Y.length>0)for(let Z of Y){let _=J.indexOf(Z);if(_!==-1)J.splice(_,1)}}clear(){this.handlers.clear()}clearEvent(j){this.handlers.delete(j)}}class Q{resources=new Map;resourceFactories=new Map;initializedResourceKeys=new Set;add(j,F){if(this._isFactoryFunction(F))this.resourceFactories.set(j,F);else this.resources.set(j,F),this.initializedResourceKeys.add(j);return this}_isFactoryFunction(j){if(typeof j!=="function")return!1;let F=j.toString();if(F.startsWith("class "))return!1;if(F.includes("[native code]"))return!1;if(j.prototype){let J=Object.getOwnPropertyNames(j.prototype);if(J.length>1||J.length===1&&J[0]!=="constructor")return!1}if(j.name&&j.name[0]===j.name[0].toUpperCase()&&j.name.length>1){if(F.includes("this.")||F.includes("new "))return!1}return!0}get(j,F){let J=this.resources.get(j);if(J!==void 0)return J;let X=this.resourceFactories.get(j);if(X===void 0)throw Error(`Resource ${String(j)} not found`);let Y=X(F);if(!(Y instanceof Promise))this.resources.set(j,Y),this.initializedResourceKeys.add(j);return Y}has(j){return this.resources.has(j)||this.resourceFactories.has(j)}remove(j){let F=this.resources.delete(j),J=this.resourceFactories.delete(j);if(this.initializedResourceKeys.has(j))this.initializedResourceKeys.delete(j);return F||J}getKeys(){let j=new Set([...this.resources.keys(),...this.resourceFactories.keys()]);return Array.from(j)}needsInitialization(j){return this.resourceFactories.has(j)&&!this.initializedResourceKeys.has(j)}getPendingInitializationKeys(){return Array.from(this.resourceFactories.keys()).filter((j)=>!this.initializedResourceKeys.has(j))}async initializeResource(j,F){if(!this.resourceFactories.has(j)||this.initializedResourceKeys.has(j))return;let X=await this.resourceFactories.get(j)(F);this.resources.set(j,X),this.initializedResourceKeys.add(j),this.resourceFactories.delete(j)}async initializeResources(j,...F){if(F.length===0){let J=this.getPendingInitializationKeys();await Promise.all(J.map((X)=>this.initializeResource(X,j)));return}await Promise.all(F.map((J)=>this.initializeResource(J,j)))}}class L{assets=new Map;groups=new Map;eventBus=null;setEventBus(j){this.eventBus=j}register(j,F){if(this.assets.set(j,{definition:F,status:"pending"}),F.group){let J=this.groups.get(F.group)??new Set;J.add(j),this.groups.set(F.group,J)}}async loadEagerAssets(){let j=[];for(let[F,J]of this.assets)if(J.definition.eager&&J.status==="pending")j.push(F);await Promise.all(j.map((F)=>this.loadAsset(F)))}async loadAsset(j){let F=j,J=this.assets.get(F);if(!J)throw Error(`Asset '${F}' not found`);if(J.status==="loaded"&&J.value!==void 0)return J.value;if(J.status==="loading"&&J.loadPromise)return J.loadPromise;if(J.status==="failed")J.status="pending";J.status="loading",J.loadPromise=J.definition.loader();try{let X=await J.loadPromise;return J.value=X,J.status="loaded",J.loadPromise=void 0,this.eventBus?.publish("assetLoaded",{key:F}),this.checkGroupProgress(J.definition.group),X}catch(X){let Y=X instanceof Error?X:Error(String(X));throw J.status="failed",J.error=Y,J.loadPromise=void 0,this.eventBus?.publish("assetFailed",{key:F,error:Y}),Y}}async loadAssetGroup(j){let F=this.groups.get(j);if(!F||F.size===0)throw Error(`Asset group '${j}' not found or empty`);await Promise.all(Array.from(F).map((J)=>this.loadAsset(J)))}get(j){let F=j,J=this.assets.get(F);if(!J)throw Error(`Asset '${F}' not found`);if(J.status!=="loaded"||J.value===void 0)throw Error(`Asset '${F}' is not loaded (status: ${J.status})`);return J.value}getOrUndefined(j){let F=j,J=this.assets.get(F);if(!J||J.status!=="loaded")return;return J.value}getHandle(j){let F=j,J=this.assets.get(F);if(!J)throw Error(`Asset '${F}' not found`);let X=this;return{get status(){return J.status},get isLoaded(){return J.status==="loaded"},get(){return X.get(j)},getOrUndefined(){return X.getOrUndefined(j)}}}getStatus(j){let F=j,J=this.assets.get(F);if(!J)throw Error(`Asset '${F}' not found`);return J.status}isLoaded(j){let F=j;return this.assets.get(F)?.status==="loaded"}isGroupLoaded(j){let F=this.groups.get(j);if(!F||F.size===0)return!1;for(let J of F){let X=this.assets.get(J);if(!X||X.status!=="loaded")return!1}return!0}getGroupProgress(j){let F=this.groups.get(j);if(!F||F.size===0)return 0;let J=0;for(let X of F)if(this.assets.get(X)?.status==="loaded")J++;return J/F.size}getGroupProgressDetails(j){let F=this.groups.get(j);if(!F||F.size===0)return{loaded:0,total:0,progress:0};let J=0;for(let Y of F)if(this.assets.get(Y)?.status==="loaded")J++;let X=F.size;return{loaded:J,total:X,progress:J/X}}checkGroupProgress(j){if(!j||!this.eventBus)return;let F=this.getGroupProgressDetails(j);if(this.eventBus.publish("assetGroupProgress",{group:j,...F}),F.loaded===F.total)this.eventBus.publish("assetGroupLoaded",{group:j})}createResource(){let j=this;return{getStatus(F){return j.getStatus(F)},isLoaded(F){return j.isLoaded(F)},isGroupLoaded(F){return j.isGroupLoaded(F)},getGroupProgress(F){return j.getGroupProgress(F)},get(F){return j.get(F)},getOrUndefined(F){return j.getOrUndefined(F)},getHandle(F){return j.getHandle(F)}}}getKeys(){return Array.from(this.assets.keys())}getGroupNames(){return Array.from(this.groups.keys())}getGroupKeys(j){let F=this.groups.get(j);return F?Array.from(F):[]}}class A{manager;constructor(j){this.manager=j}add(j,F){return this.manager.register(j,{loader:F,eager:!0}),this}addWithConfig(j,F){return this.manager.register(j,F),this}addGroup(j,F){for(let[J,X]of Object.entries(F))this.manager.register(J,{loader:X,eager:!1,group:j});return this}getManager(){return this.manager}}function w(j){return new A(j??new L)}class z{screens=new Map;currentScreen=null;screenStack=[];eventBus=null;assetManager=null;ecs=null;setDependencies(j,F,J){this.eventBus=j,this.assetManager=F,this.ecs=J}register(j,F){this.screens.set(j,{definition:F})}async setScreen(j,F){let J=j,X=this.screens.get(J);if(!X)throw Error(`Screen '${J}' not found`);await this.verifyRequiredAssets(X.definition);while(this.screenStack.length>0){let Z=this.screenStack.pop();if(Z)await this.exitScreen(Z.name)}if(this.currentScreen)await this.exitScreen(this.currentScreen.name);let Y=X.definition.initialState(F);this.currentScreen={name:j,config:F,state:Y},await X.definition.onEnter?.(F,this.ecs),this.eventBus?.publish("screenEnter",{screen:J,config:F})}async pushScreen(j,F){let J=j,X=this.screens.get(J);if(!X)throw Error(`Screen '${J}' not found`);if(await this.verifyRequiredAssets(X.definition),this.currentScreen)this.screenStack.push(this.currentScreen);let Y=X.definition.initialState(F);this.currentScreen={name:j,config:F,state:Y},await X.definition.onEnter?.(F,this.ecs),this.eventBus?.publish("screenPush",{screen:J,config:F})}async popScreen(){if(this.screenStack.length===0)throw Error("Cannot pop screen: stack is empty");if(this.currentScreen){let j=this.currentScreen.name;await this.exitScreen(j),this.eventBus?.publish("screenPop",{screen:j})}this.currentScreen=this.screenStack.pop()??null}async exitScreen(j){let F=this.screens.get(j);if(F?.definition.onExit)await F.definition.onExit(this.ecs);this.eventBus?.publish("screenExit",{screen:j})}async verifyRequiredAssets(j){if(!this.assetManager)return;if(j.requiredAssets){for(let F of j.requiredAssets)if(!this.assetManager.isLoaded(F))await this.assetManager.loadAsset(F)}if(j.requiredAssetGroups){for(let F of j.requiredAssetGroups)if(!this.assetManager.isGroupLoaded(F))await this.assetManager.loadAssetGroup(F)}}getCurrentScreen(){return this.currentScreen?.name??null}getConfig(){if(!this.currentScreen)throw Error("No current screen");return this.currentScreen.config}getConfigOrNull(){return this.currentScreen?.config??null}getState(){if(!this.currentScreen)throw Error("No current screen");return this.currentScreen.state}getStateOrNull(){return this.currentScreen?.state??null}updateState(j){if(!this.currentScreen)throw Error("No current screen");let F=typeof j==="function"?j(this.currentScreen.state):j;this.currentScreen.state={...this.currentScreen.state,...F}}getStackDepth(){return this.screenStack.length}isOverlay(){return this.screenStack.length>0}isActive(j){if(this.currentScreen?.name===j)return!0;return this.screenStack.some((F)=>F.name===j)}isCurrent(j){return this.currentScreen?.name===j}createResource(){let j=this;return{get current(){return j.getCurrentScreen()},get config(){return j.getConfigOrNull()},get state(){return j.getStateOrNull()},set state(F){if(j.currentScreen)j.currentScreen.state=F},get stack(){return j.screenStack},get isOverlay(){return j.isOverlay()},get stackDepth(){return j.getStackDepth()},isActive(F){return j.isActive(F)},isCurrent(F){return j.isCurrent(F)}}}getScreenNames(){return Array.from(this.screens.keys())}hasScreen(j){return this.screens.has(j)}}class q{manager;constructor(j){this.manager=j}add(j,F){return this.manager.register(j,F),this}getManager(){return this.manager}}function E(j){return new q(j??new z)}class M{_label;_ecspresso;_bundle;queries={};processFunction;detachFunction;initializeFunction;eventHandlers;_priority=0;_isRegistered=!1;_inScreens;_excludeScreens;_requiredAssets;constructor(j,F=null,J=null){this._label=j;this._ecspresso=F;this._bundle=J}get label(){return this._label}get bundle(){return this._bundle}get ecspresso(){return this._ecspresso}_autoRegister(){if(this._isRegistered||!this._ecspresso)return;let j=this._buildSystemObject();P(j,this._ecspresso),this._isRegistered=!0}_buildSystemObject(){return this._createSystemObject()}_createSystemObject(){let j={label:this._label,entityQueries:this.queries,priority:this._priority};if(this.processFunction)j.process=this.processFunction;if(this.detachFunction)j.onDetach=this.detachFunction;if(this.initializeFunction)j.onInitialize=this.initializeFunction;if(this.eventHandlers)j.eventHandlers=this.eventHandlers;if(this._inScreens)j.inScreens=this._inScreens;if(this._excludeScreens)j.excludeScreens=this._excludeScreens;if(this._requiredAssets)j.requiredAssets=this._requiredAssets;return j}setPriority(j){return this._priority=j,this}inScreens(j){return this._inScreens=[...j],this}excludeScreens(j){return this._excludeScreens=[...j],this}requiresAssets(j){return this._requiredAssets=[...j],this}addQuery(j,F){let J=this;return J.queries={...this.queries,[j]:F},J}setProcess(j){return this.processFunction=j,this}registerAndContinue(){if(!this._ecspresso)throw Error(`Cannot register system '${this._label}': SystemBuilder is not attached to an ECSpresso instance. Use Bundle.addSystem() or ECSpresso.addSystem() instead.`);return this._autoRegister(),this._ecspresso}and(){if(this._ecspresso)return this._autoRegister(),this._ecspresso;if(this._bundle)return this._bundle;throw Error(`Cannot use and() on system '${this._label}': not attached to ECSpresso or Bundle.`)}setOnDetach(j){return this.detachFunction=j,this}setOnInitialize(j){return this.initializeFunction=j,this}setEventHandlers(j){return this.eventHandlers=j,this}build(j){let F=this._createSystemObject();if(this._ecspresso)P(F,this._ecspresso);if(j)P(F,j);return this}}function P(j,F){F._registerSystem(j)}function K(j,F){return new M(j,F)}function B(j,F){return new M(j,null,F)}var R="0.5.0";var O={};class W{static VERSION=R;_entityManager;_eventBus;_resourceManager;_systems=[];_sortedSystems=[];_installedBundles=new Set;_assetManager=null;_screenManager=null;_postUpdateHooks=[];constructor(){this._entityManager=new U,this._eventBus=new D,this._resourceManager=new Q,this._sortedSystems=[]}static create(){return new T}addSystem(j){return K(j,this)}update(j){let F=this._screenManager?.getCurrentScreen()??null;for(let J of this._sortedSystems){if(!J.process)continue;if(J.inScreens?.length){if(F===null||!J.inScreens.includes(F))continue}if(J.excludeScreens?.length){if(F!==null&&J.excludeScreens.includes(F))continue}if(J.requiredAssets?.length&&this._assetManager){let _=!0;for(let $ of J.requiredAssets)if(!this._assetManager.isLoaded($)){_=!1;break}if(!_)continue}let X={},Y=!1,Z=!1;if(J.entityQueries)for(let _ in J.entityQueries){Z=!0;let $=J.entityQueries[_];if($){if(X[_]=this._entityManager.getEntitiesWithQuery($.with,$.without||[]),X[_].length)Y=!0}}if(Y)J.process(X,j,this);else if(!Z)J.process(O,j,this)}for(let J of this._postUpdateHooks)J(this,j)}async initialize(){if(await this.initializeResources(),this._assetManager)this._assetManager.setEventBus(this._eventBus),await this._assetManager.loadEagerAssets(),this._resourceManager.add("$assets",this._assetManager.createResource());if(this._screenManager)this._screenManager.setDependencies(this._eventBus,this._assetManager,this),this._resourceManager.add("$screen",this._screenManager.createResource());for(let j of this._systems)await j.onInitialize?.(this)}async initializeResources(...j){await this._resourceManager.initializeResources(this,...j)}_sortSystems(){this._sortedSystems=[...this._systems].sort((j,F)=>{let J=j.priority??0;return(F.priority??0)-J})}updateSystemPriority(j,F){let J=this._systems.find((X)=>X.label===j);if(!J)return!1;return J.priority=F,this._sortSystems(),!0}removeSystem(j){let F=this._systems.findIndex((X)=>X.label===j);if(F===-1)return!1;let J=this._systems[F];if(!J)return!1;if(J.onDetach)J.onDetach(this);return this._systems.splice(F,1),this._sortSystems(),!0}_registerSystem(j){if(this._systems.push(j),this._sortSystems(),!j.eventHandlers)return;for(let F in j.eventHandlers){let J=j.eventHandlers[F]?.handler;if(J)this._eventBus.subscribe(F,(X)=>{J(X,this)})}}hasResource(j){return this._resourceManager.has(j)}getResource(j){let F=this._resourceManager.get(j,this);if(!F)throw Error(`Resource '${String(j)}' not found. Available resources: [${this.getResourceKeys().map((J)=>String(J)).join(", ")}]`);return F}addResource(j,F){return this._resourceManager.add(j,F),this}removeResource(j){return this._resourceManager.remove(j)}updateResource(j,F){let J=this.getResource(j),X=F(J);return this._resourceManager.add(j,X),this}getResourceKeys(){return this._resourceManager.getKeys()}resourceNeedsInitialization(j){return this._resourceManager.needsInitialization(j)}hasComponent(j,F){return this._entityManager.getComponent(j,F)!==null}spawn(j){let F=this._entityManager.createEntity();return this._entityManager.addComponents(F,j),F}getEntitiesWithQuery(j,F=[]){return this._entityManager.getEntitiesWithQuery(j,F)}removeEntity(j,F){return this._entityManager.removeEntity(j,F)}spawnChild(j,F){let J=this._entityManager.spawnChild(j,F);return this._emitHierarchyChanged(J.id,null,j),J}setParent(j,F){let J=this._entityManager.getParent(j);return this._entityManager.setParent(j,F),this._emitHierarchyChanged(j,J,F),this}removeParent(j){let F=this._entityManager.getParent(j),J=this._entityManager.removeParent(j);if(J)this._emitHierarchyChanged(j,F,null);return J}getParent(j){return this._entityManager.getParent(j)}getChildren(j){return this._entityManager.getChildren(j)}getChildAt(j,F){return this._entityManager.getChildAt(j,F)}getChildIndex(j,F){return this._entityManager.getChildIndex(j,F)}getAncestors(j){return this._entityManager.getAncestors(j)}getDescendants(j){return this._entityManager.getDescendants(j)}getRoot(j){return this._entityManager.getRoot(j)}getSiblings(j){return this._entityManager.getSiblings(j)}isDescendantOf(j,F){return this._entityManager.isDescendantOf(j,F)}isAncestorOf(j,F){return this._entityManager.isAncestorOf(j,F)}getRootEntities(){return this._entityManager.getRootEntities()}_emitHierarchyChanged(j,F,J){this._eventBus.publish("hierarchyChanged",{entityId:j,oldParent:F,newParent:J})}get installedBundles(){return Array.from(this._installedBundles)}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}on(j,F){return this._eventBus.subscribe(j,F)}off(j,F){return this._eventBus.unsubscribe(j,F)}onPostUpdate(j){return this._postUpdateHooks.push(j),()=>{let F=this._postUpdateHooks.indexOf(j);if(F!==-1)this._postUpdateHooks.splice(F,1)}}getAsset(j){if(!this._assetManager)throw Error("Asset manager not configured. Use withAssets() in builder.");return this._assetManager.get(j)}getAssetOrUndefined(j){return this._assetManager?.getOrUndefined(j)}getAssetHandle(j){if(!this._assetManager)throw Error("Asset manager not configured. Use withAssets() in builder.");return this._assetManager.getHandle(j)}isAssetLoaded(j){return this._assetManager?.isLoaded(j)??!1}async loadAsset(j){if(!this._assetManager)throw Error("Asset manager not configured. Use withAssets() in builder.");return this._assetManager.loadAsset(j)}async loadAssetGroup(j){if(!this._assetManager)throw Error("Asset manager not configured. Use withAssets() in builder.");return this._assetManager.loadAssetGroup(j)}isAssetGroupLoaded(j){return this._assetManager?.isGroupLoaded(j)??!1}getAssetGroupProgress(j){return this._assetManager?.getGroupProgress(j)??0}async setScreen(j,F){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.setScreen(j,F)}async pushScreen(j,F){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.pushScreen(j,F)}async popScreen(){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.popScreen()}getCurrentScreen(){return this._screenManager?.getCurrentScreen()??null}getScreenConfig(){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.getConfig()}getScreenConfigOrNull(){return this._screenManager?.getConfigOrNull()??null}getScreenState(){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.getState()}getScreenStateOrNull(){return this._screenManager?.getStateOrNull()??null}updateScreenState(j){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");this._screenManager.updateState(j)}isCurrentScreen(j){return this._screenManager?.isCurrent(j)??!1}isScreenActive(j){return this._screenManager?.isActive(j)??!1}getScreenStackDepth(){return this._screenManager?.getStackDepth()??0}_setAssetManager(j){this._assetManager=j}_setScreenManager(j){this._screenManager=j}_installBundle(j){if(this._installedBundles.has(j.id))return this;this._installedBundles.add(j.id),j.registerSystemsWithEcspresso(this);let F=j.getResources();for(let[J,X]of F.entries())this._resourceManager.add(J,X);if(this._assetManager){let J=j.getAssets();for(let[X,Y]of J.entries())this._assetManager.register(X,Y)}if(this._screenManager){let J=j.getScreens();for(let[X,Y]of J.entries())this._screenManager.register(X,Y)}return this}}class T{ecspresso;assetConfigurator=null;screenConfigurator=null;constructor(){this.ecspresso=new W}withBundle(j){return this.ecspresso._installBundle(j),this}withAssets(j){let F=w();return j(F),this.assetConfigurator=F,this}withScreens(j){let F=E();return j(F),this.screenConfigurator=F,this}build(){if(this.assetConfigurator)this.ecspresso._setAssetManager(this.assetConfigurator.getManager());if(this.screenConfigurator)this.ecspresso._setScreenManager(this.screenConfigurator.getManager());return this.ecspresso}}function v(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class V{_systems=[];_resources=new Map;_assets=new Map;_assetGroups=new Map;_screens=new Map;_id;constructor(j){this._id=j||v()}get id(){return this._id}set id(j){this._id=j}addSystem(j){if(typeof j==="string"){let F=B(j,this);return this._systems.push(F),F}else return this._systems.push(j),j}addResource(j,F){return this._resources.set(j,F),this}addAsset(j,F,J){return this._assets.set(j,{loader:F,eager:J?.eager??!0,group:J?.group}),this}addAssetGroup(j,F){let J=new Map;for(let[X,Y]of Object.entries(F))J.set(X,Y),this._assets.set(X,{loader:Y,eager:!1,group:j});return this._assetGroups.set(j,J),this}addScreen(j,F){return this._screens.set(j,F),this}getAssets(){return new Map(this._assets)}getScreens(){return new Map(this._screens)}_setResource(j,F){this._resources.set(j,F)}_setAsset(j,F){this._assets.set(j,F)}_setScreen(j,F){this._screens.set(j,F)}getSystems(){return this._systems.map((j)=>j.build())}registerSystemsWithEcspresso(j){for(let F of this._systems)F.build(j)}getResources(){return new Map(this._resources)}getResource(j){return this._resources.get(j)}getSystemBuilders(){return[...this._systems]}hasResource(j){return this._resources.has(j)}}function S(j,...F){if(F.length===0)return new V(j);let J=new V(j);for(let X of F){for(let Y of X.getSystemBuilders())J.addSystem(Y);for(let[Y,Z]of X.getResources().entries())J._setResource(Y,Z);for(let[Y,Z]of X.getAssets().entries())J._setAsset(Y,Z);for(let[Y,Z]of X.getScreens().entries())J._setScreen(Y,Z)}return J}function J0(j){return j}var M0=W;export{S as mergeBundles,M0 as default,E as createScreenConfigurator,J0 as createQueryDefinition,w as createAssetConfigurator,M as SystemBuilder,z as ScreenManager,Q as ResourceManager,H as HierarchyManager,D as EventBus,U as EntityManager,V as Bundle,L as AssetManager};
2
2
 
3
- //# debugId=CE8D52F1074A75E964756E2164756E21
3
+ //# debugId=B0736F43983D1AE364756E2164756E21
4
4
  //# sourceMappingURL=index.js.map