ecspresso 0.8.0 → 0.10.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.
- package/README.md +502 -729
- package/dist/bundles/renderers/renderer2D.d.ts +4 -4
- package/dist/bundles/renderers/renderer2D.js +2 -2
- package/dist/bundles/renderers/renderer2D.js.map +4 -8
- package/dist/bundles/utils/bounds.d.ts +4 -1
- package/dist/bundles/utils/bounds.js +4 -0
- package/dist/bundles/utils/bounds.js.map +10 -0
- package/dist/bundles/utils/collision.d.ts +4 -1
- package/dist/bundles/utils/collision.js +4 -0
- package/dist/bundles/utils/collision.js.map +10 -0
- package/dist/bundles/utils/input.d.ts +133 -0
- package/dist/bundles/utils/input.js +4 -0
- package/dist/bundles/utils/input.js.map +10 -0
- package/dist/bundles/utils/movement.d.ts +4 -1
- package/dist/bundles/utils/movement.js +4 -0
- package/dist/bundles/utils/movement.js.map +10 -0
- package/dist/bundles/utils/timers.d.ts +4 -1
- package/dist/bundles/utils/timers.js +2 -2
- package/dist/bundles/utils/timers.js.map +4 -6
- package/dist/bundles/utils/transform.d.ts +4 -1
- package/dist/bundles/utils/transform.js +4 -0
- package/dist/bundles/utils/transform.js.map +10 -0
- package/dist/command-buffer.d.ts +6 -0
- package/dist/ecspresso.d.ts +102 -13
- package/dist/entity-manager.d.ts +38 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +8 -8
- package/dist/reactive-query-manager.d.ts +22 -3
- package/dist/system-builder.d.ts +19 -4
- package/dist/types.d.ts +31 -5
- package/package.json +22 -2
package/dist/ecspresso.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import AssetManager from "./asset-manager";
|
|
|
4
4
|
import ScreenManager from "./screen-manager";
|
|
5
5
|
import { type ReactiveQueryDefinition } from "./reactive-query-manager";
|
|
6
6
|
import CommandBuffer from "./command-buffer";
|
|
7
|
-
import type { System, FilteredEntity, Entity, RemoveEntityOptions, HierarchyEntry, HierarchyIteratorOptions } from "./types";
|
|
7
|
+
import type { System, SystemPhase, FilteredEntity, Entity, RemoveEntityOptions, HierarchyEntry, HierarchyIteratorOptions } from "./types";
|
|
8
8
|
import type Bundle from "./bundle";
|
|
9
9
|
import type { BundlesAreCompatible } from "./type-utils";
|
|
10
10
|
import type { AssetHandle, AssetConfigurator } from "./asset-types";
|
|
@@ -36,8 +36,8 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
36
36
|
private _commandBuffer;
|
|
37
37
|
/** Registered systems that will be updated in order*/
|
|
38
38
|
private _systems;
|
|
39
|
-
/**
|
|
40
|
-
private
|
|
39
|
+
/** Systems grouped by execution phase, each sorted by priority */
|
|
40
|
+
private _phaseSystems;
|
|
41
41
|
/** Track installed bundles to prevent duplicates*/
|
|
42
42
|
private _installedBundles;
|
|
43
43
|
/** Disabled system groups */
|
|
@@ -50,6 +50,20 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
50
50
|
private _reactiveQueryManager;
|
|
51
51
|
/** Post-update hooks to be called after all systems in update() */
|
|
52
52
|
private _postUpdateHooks;
|
|
53
|
+
/** Global tick counter, incremented at the end of each update() */
|
|
54
|
+
private _currentTick;
|
|
55
|
+
/** Per-system last-seen change sequence for change detection */
|
|
56
|
+
private _systemLastSeqs;
|
|
57
|
+
/** Change threshold used for public getEntitiesWithQuery and between-system resolution */
|
|
58
|
+
private _changeThreshold;
|
|
59
|
+
/** Fixed timestep interval in seconds (default: 1/60) */
|
|
60
|
+
private _fixedDt;
|
|
61
|
+
/** Accumulated time for fixed update steps */
|
|
62
|
+
private _fixedAccumulator;
|
|
63
|
+
/** Interpolation alpha between fixed steps (accumulator / fixedDt) */
|
|
64
|
+
private _interpolationAlpha;
|
|
65
|
+
/** Maximum fixed update steps per frame (spiral-of-death protection) */
|
|
66
|
+
private _maxFixedSteps;
|
|
53
67
|
/**
|
|
54
68
|
* Creates a new ECSpresso instance.
|
|
55
69
|
*/
|
|
@@ -81,10 +95,17 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
81
95
|
*/
|
|
82
96
|
addSystem(label: string): import("./system-builder").SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes, {}>;
|
|
83
97
|
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
98
|
+
* Update all systems across execution phases.
|
|
99
|
+
* Phases run in order: preUpdate -> fixedUpdate -> update -> postUpdate -> render.
|
|
100
|
+
* The fixedUpdate phase uses a time accumulator for deterministic fixed-timestep simulation.
|
|
101
|
+
* @param deltaTime Time elapsed since the last update (in seconds)
|
|
102
|
+
*/
|
|
87
103
|
update(deltaTime: number): void;
|
|
104
|
+
/**
|
|
105
|
+
* Execute all systems in a single phase.
|
|
106
|
+
* @private
|
|
107
|
+
*/
|
|
108
|
+
private _executePhase;
|
|
88
109
|
/**
|
|
89
110
|
* Initialize all resources and systems
|
|
90
111
|
* This method:
|
|
@@ -108,11 +129,12 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
108
129
|
*/
|
|
109
130
|
initializeResources<K extends keyof ResourceTypes>(...keys: K[]): Promise<void>;
|
|
110
131
|
/**
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
132
|
+
* Rebuild per-phase system arrays from the flat _systems list.
|
|
133
|
+
* Each phase array is sorted by priority (higher first), with
|
|
134
|
+
* registration order as tiebreaker.
|
|
135
|
+
* @private
|
|
136
|
+
*/
|
|
137
|
+
private _rebuildPhaseSystems;
|
|
116
138
|
/**
|
|
117
139
|
* Update the priority of a system
|
|
118
140
|
* @param label The unique label of the system to update
|
|
@@ -120,6 +142,24 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
120
142
|
* @returns true if the system was found and updated, false otherwise
|
|
121
143
|
*/
|
|
122
144
|
updateSystemPriority(label: string, priority: number): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Move a system to a different execution phase at runtime.
|
|
147
|
+
* @param label The unique label of the system to move
|
|
148
|
+
* @param phase The target phase
|
|
149
|
+
* @returns true if the system was found and updated, false otherwise
|
|
150
|
+
*/
|
|
151
|
+
updateSystemPhase(label: string, phase: SystemPhase): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* The interpolation alpha between fixed update steps.
|
|
154
|
+
* Ranges from 0 to <1, representing how far into the next
|
|
155
|
+
* fixed step the current frame is. Use in the render phase
|
|
156
|
+
* for smooth visual interpolation.
|
|
157
|
+
*/
|
|
158
|
+
get interpolationAlpha(): number;
|
|
159
|
+
/**
|
|
160
|
+
* The configured fixed timestep interval in seconds.
|
|
161
|
+
*/
|
|
162
|
+
get fixedDt(): number;
|
|
123
163
|
/**
|
|
124
164
|
* Disable a system group. Systems in this group will be skipped during update().
|
|
125
165
|
* @param groupName The name of the group to disable
|
|
@@ -222,7 +262,24 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
222
262
|
/**
|
|
223
263
|
* Get all entities with specific components
|
|
224
264
|
*/
|
|
225
|
-
getEntitiesWithQuery<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>): Array<FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>>;
|
|
265
|
+
getEntitiesWithQuery<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>, changedComponents?: ReadonlyArray<keyof ComponentTypes>, parentHas?: ReadonlyArray<keyof ComponentTypes>): Array<FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>>;
|
|
266
|
+
/**
|
|
267
|
+
* Get the single entity matching a query. Throws if zero or more than one match.
|
|
268
|
+
* @param withComponents Components the entity must have
|
|
269
|
+
* @param withoutComponents Components the entity must not have
|
|
270
|
+
* @returns The single matching entity
|
|
271
|
+
* @throws If zero or more than one entity matches
|
|
272
|
+
*/
|
|
273
|
+
getSingleton<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>): FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>;
|
|
274
|
+
/**
|
|
275
|
+
* Get the single entity matching a query, or undefined if none match.
|
|
276
|
+
* Throws if more than one entity matches.
|
|
277
|
+
* @param withComponents Components the entity must have
|
|
278
|
+
* @param withoutComponents Components the entity must not have
|
|
279
|
+
* @returns The single matching entity, or undefined if none match
|
|
280
|
+
* @throws If more than one entity matches
|
|
281
|
+
*/
|
|
282
|
+
tryGetSingleton<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>): FilteredEntity<ComponentTypes, WithComponents, WithoutComponents> | undefined;
|
|
226
283
|
/**
|
|
227
284
|
* Remove an entity (and optionally its descendants)
|
|
228
285
|
* @param entityOrId Entity or entity ID to remove
|
|
@@ -357,6 +414,25 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
357
414
|
* ```
|
|
358
415
|
*/
|
|
359
416
|
get commands(): CommandBuffer<ComponentTypes, EventTypes, ResourceTypes>;
|
|
417
|
+
/**
|
|
418
|
+
* The current tick number, incremented at the end of each update()
|
|
419
|
+
*/
|
|
420
|
+
get currentTick(): number;
|
|
421
|
+
/**
|
|
422
|
+
* The current change detection threshold.
|
|
423
|
+
* During system execution, this is the system's last-seen sequence.
|
|
424
|
+
* Between updates, this is the global sequence after command buffer playback.
|
|
425
|
+
* Manual change detection should compare: getChangeSeq(...) > changeThreshold
|
|
426
|
+
*/
|
|
427
|
+
get changeThreshold(): number;
|
|
428
|
+
/**
|
|
429
|
+
* Mark a component as changed on an entity.
|
|
430
|
+
* Each call increments a global monotonic sequence; systems with changed
|
|
431
|
+
* queries will see the mark exactly once (on their next execution).
|
|
432
|
+
* @param entityId The entity ID
|
|
433
|
+
* @param componentName The component that was changed
|
|
434
|
+
*/
|
|
435
|
+
markChanged<K extends keyof ComponentTypes>(entityId: number, componentName: K): void;
|
|
360
436
|
/**
|
|
361
437
|
* Register a callback when a specific component is added to any entity
|
|
362
438
|
* @param componentName The component key
|
|
@@ -376,7 +452,7 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
376
452
|
* @param name Unique name for the query
|
|
377
453
|
* @param definition Query definition with with/without arrays and onEnter/onExit callbacks
|
|
378
454
|
*/
|
|
379
|
-
addReactiveQuery<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never>(name: string, definition: ReactiveQueryDefinition<ComponentTypes, WithComponents, WithoutComponents>): void;
|
|
455
|
+
addReactiveQuery<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never, OptionalComponents extends keyof ComponentTypes = never>(name: string, definition: ReactiveQueryDefinition<ComponentTypes, WithComponents, WithoutComponents, OptionalComponents>): void;
|
|
380
456
|
/**
|
|
381
457
|
* Remove a reactive query by name.
|
|
382
458
|
* @param name Name of the query to remove
|
|
@@ -493,6 +569,11 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
493
569
|
* @internal Used by ECSpressoBuilder
|
|
494
570
|
*/
|
|
495
571
|
_setScreenManager(manager: ScreenManager<ScreenStates>): void;
|
|
572
|
+
/**
|
|
573
|
+
* Internal method to set the fixed timestep interval
|
|
574
|
+
* @internal Used by ECSpressoBuilder
|
|
575
|
+
*/
|
|
576
|
+
_setFixedDt(dt: number): void;
|
|
496
577
|
/**
|
|
497
578
|
* Internal method to install a bundle into this ECSpresso instance.
|
|
498
579
|
* Called by the ECSpressoBuilder during the build process.
|
|
@@ -521,6 +602,8 @@ export declare class ECSpressoBuilder<C extends Record<string, any> = {}, E exte
|
|
|
521
602
|
private screenConfigurator;
|
|
522
603
|
/** Pending resources to add during build */
|
|
523
604
|
private pendingResources;
|
|
605
|
+
/** Fixed timestep interval (null means use default 1/60) */
|
|
606
|
+
private _fixedDt;
|
|
524
607
|
constructor();
|
|
525
608
|
/**
|
|
526
609
|
* Add the first bundle when starting with empty types.
|
|
@@ -592,6 +675,12 @@ export declare class ECSpressoBuilder<C extends Record<string, any> = {}, E exte
|
|
|
592
675
|
* ```
|
|
593
676
|
*/
|
|
594
677
|
withScreens<NewS extends Record<string, ScreenDefinition<any, any>>>(configurator: (screens: ScreenConfigurator<{}>) => ScreenConfigurator<NewS>): ECSpressoBuilder<C, E, R, A, S & NewS>;
|
|
678
|
+
/**
|
|
679
|
+
* Configure the fixed timestep interval for the fixedUpdate phase.
|
|
680
|
+
* @param dt The fixed timestep in seconds (e.g., 1/60 for 60Hz physics)
|
|
681
|
+
* @returns This builder for method chaining
|
|
682
|
+
*/
|
|
683
|
+
withFixedTimestep(dt: number): this;
|
|
595
684
|
/**
|
|
596
685
|
* Complete the build process and return the built ECSpresso instance
|
|
597
686
|
*/
|
package/dist/entity-manager.d.ts
CHANGED
|
@@ -15,6 +15,16 @@ export default class EntityManager<ComponentTypes> {
|
|
|
15
15
|
* Hierarchy manager for parent-child relationships
|
|
16
16
|
*/
|
|
17
17
|
private hierarchyManager;
|
|
18
|
+
/**
|
|
19
|
+
* Per-entity per-component change sequence tracking.
|
|
20
|
+
* Maps entityId -> (componentName -> sequence number when last changed)
|
|
21
|
+
*/
|
|
22
|
+
private changeSeqs;
|
|
23
|
+
/**
|
|
24
|
+
* Monotonic sequence counter for change detection.
|
|
25
|
+
* Each markChanged call increments this and stamps the new value.
|
|
26
|
+
*/
|
|
27
|
+
private _changeSeq;
|
|
18
28
|
createEntity(): Entity<ComponentTypes>;
|
|
19
29
|
addComponent<ComponentName extends keyof ComponentTypes>(entityOrId: number | Entity<ComponentTypes>, componentName: ComponentName, data: ComponentTypes[ComponentName]): this;
|
|
20
30
|
/**
|
|
@@ -27,7 +37,11 @@ export default class EntityManager<ComponentTypes> {
|
|
|
27
37
|
}>(entityOrId: number | Entity<ComponentTypes>, components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): this;
|
|
28
38
|
removeComponent<ComponentName extends keyof ComponentTypes>(entityOrId: number | Entity<ComponentTypes>, componentName: ComponentName): this;
|
|
29
39
|
getComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName): ComponentTypes[ComponentName] | null;
|
|
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>>;
|
|
40
|
+
getEntitiesWithQuery<WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never>(required?: ReadonlyArray<WithComponents>, excluded?: ReadonlyArray<WithoutComponents>, changed?: ReadonlyArray<keyof ComponentTypes>, changeThreshold?: number, parentHas?: ReadonlyArray<keyof ComponentTypes>): Array<FilteredEntity<ComponentTypes, WithComponents extends never ? never : WithComponents, WithoutComponents extends never ? never : WithoutComponents>>;
|
|
41
|
+
/**
|
|
42
|
+
* Check if an entity's direct parent has all specified components
|
|
43
|
+
*/
|
|
44
|
+
private parentHasComponents;
|
|
31
45
|
removeEntity(entityOrId: number | Entity<ComponentTypes>, options?: RemoveEntityOptions): boolean;
|
|
32
46
|
/**
|
|
33
47
|
* Internal method to remove a single entity without cascade logic
|
|
@@ -48,6 +62,29 @@ export default class EntityManager<ComponentTypes> {
|
|
|
48
62
|
* @returns Unsubscribe function to remove the callback
|
|
49
63
|
*/
|
|
50
64
|
onComponentRemoved<ComponentName extends keyof ComponentTypes>(componentName: ComponentName, handler: (oldValue: ComponentTypes[ComponentName], entity: Entity<ComponentTypes>) => void): () => void;
|
|
65
|
+
/**
|
|
66
|
+
* The current monotonic change sequence value.
|
|
67
|
+
* Each markChanged call increments this before stamping.
|
|
68
|
+
*/
|
|
69
|
+
get changeSeq(): number;
|
|
70
|
+
/**
|
|
71
|
+
* Mark a component as changed on an entity, stamping the next sequence number.
|
|
72
|
+
* @param entityId The entity ID
|
|
73
|
+
* @param componentName The component that changed
|
|
74
|
+
*/
|
|
75
|
+
markChanged<K extends keyof ComponentTypes>(entityId: number, componentName: K): void;
|
|
76
|
+
/**
|
|
77
|
+
* Get the sequence number at which a component was last changed on an entity
|
|
78
|
+
* @param entityId The entity ID
|
|
79
|
+
* @param componentName The component to check
|
|
80
|
+
* @returns The sequence number when last changed, or -1 if never changed
|
|
81
|
+
*/
|
|
82
|
+
getChangeSeq<K extends keyof ComponentTypes>(entityId: number, componentName: K): number;
|
|
83
|
+
/**
|
|
84
|
+
* Clear all change sequences for an entity
|
|
85
|
+
* @param entityId The entity ID
|
|
86
|
+
*/
|
|
87
|
+
clearChangeSeqs(entityId: number): void;
|
|
51
88
|
/**
|
|
52
89
|
* Create an entity as a child of another entity with initial components
|
|
53
90
|
* @param parentId The parent entity ID
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var u=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(J,X)=>(typeof require<"u"?require:J)[X]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});class Q{parentMap=new Map;childrenMap=new Map;setParent(j,J){if(j===J)throw Error(`Cannot set entity ${j} as its own parent`);if(this.wouldCreateCycle(j,J))throw Error("Cannot set parent: would create circular reference");let X=this.parentMap.get(j);if(X!==void 0){let Z=this.childrenMap.get(X);if(Z){let _=Z.indexOf(j);if(_!==-1)Z.splice(_,1)}}this.parentMap.set(j,J);let Y=this.childrenMap.get(J);if(Y)Y.push(j);else this.childrenMap.set(J,[j]);return this}removeParent(j){let J=this.parentMap.get(j);if(J===void 0)return!1;let X=this.childrenMap.get(J);if(X){let Y=X.indexOf(j);if(Y!==-1)X.splice(Y,1)}return this.parentMap.delete(j),!0}getParent(j){return this.parentMap.get(j)??null}getChildren(j){let J=this.childrenMap.get(j);return J?[...J]:[]}getChildAt(j,J){if(J<0)return null;let X=this.childrenMap.get(j);if(!X||J>=X.length)return null;return X[J]??null}getChildIndex(j,J){let X=this.childrenMap.get(j);if(!X)return-1;return X.indexOf(J)}removeEntity(j){let J=this.parentMap.get(j)??null;if(J!==null){let Z=this.childrenMap.get(J);if(Z){let _=Z.indexOf(j);if(_!==-1)Z.splice(_,1)}}this.parentMap.delete(j);let X=this.childrenMap.get(j)??[],Y=[...X];for(let Z of X)this.parentMap.delete(Z);return this.childrenMap.delete(j),{oldParent:J,orphanedChildren:Y}}getAncestors(j){let J=[],X=this.parentMap.get(j);while(X!==void 0)J.push(X),X=this.parentMap.get(X);return J}getDescendants(j){let J=[],X=[...this.childrenMap.get(j)??[]];while(X.length>0){let Y=X.shift();if(Y===void 0)continue;J.push(Y);let Z=this.childrenMap.get(Y);if(Z)X.unshift(...Z)}return J}getRoot(j){let J=j,X=this.parentMap.get(J);while(X!==void 0)J=X,X=this.parentMap.get(J);return J}getSiblings(j){let J=this.parentMap.get(j);if(J===void 0)return[];let X=this.childrenMap.get(J);if(!X)return[];return X.filter((Y)=>Y!==j)}isDescendantOf(j,J){if(j===J)return!1;let X=this.parentMap.get(j);while(X!==void 0){if(X===J)return!0;X=this.parentMap.get(X)}return!1}isAncestorOf(j,J){return this.isDescendantOf(J,j)}getRootEntities(){let j=[];for(let J of this.childrenMap.keys())if(!this.parentMap.has(J))j.push(J);return j}wouldCreateCycle(j,J){let X=J;while(X!==void 0){if(X===j)return!0;X=this.parentMap.get(X)}return!1}forEachInHierarchy(j,J){let X=J?.roots??this.getRootEntities(),Y=[];for(let Z of X)Y.push({entityId:Z,parentId:null,depth:0});while(Y.length>0){let Z=Y.shift();if(!Z)break;j(Z.entityId,Z.parentId,Z.depth);let _=this.childrenMap.get(Z.entityId);if(_)for(let F of _)Y.push({entityId:F,parentId:Z.entityId,depth:Z.depth+1})}}*hierarchyIterator(j){let J=j?.roots??this.getRootEntities(),X=[];for(let Y of J)X.push({entityId:Y,parentId:null,depth:0});while(X.length>0){let Y=X.shift();if(!Y)break;yield Y;let Z=this.childrenMap.get(Y.entityId);if(Z)for(let _ of Z)X.push({entityId:_,parentId:Y.entityId,depth:Y.depth+1})}}}class V{nextId=1;entities=new Map;componentIndices=new Map;addedCallbacks=new Map;removedCallbacks=new Map;hierarchyManager=new Q;createEntity(){let j=this.nextId++,J={id:j,components:{}};return this.entities.set(j,J),J}addComponent(j,J,X){let Y=typeof j==="number"?this.entities.get(j):j;if(!Y){let _=typeof j==="number"?j:j.id;throw Error(`Cannot add component '${String(J)}': Entity with ID ${_} does not exist`)}if(Y.components[J]=X,!this.componentIndices.has(J))this.componentIndices.set(J,new Set);this.componentIndices.get(J)?.add(Y.id);let Z=this.addedCallbacks.get(J);if(Z)for(let _ of[...Z])_(X,Y);return this}addComponents(j,J){let X=typeof j==="number"?this.entities.get(j):j;if(!X){let Y=typeof j==="number"?j:j.id;throw Error(`Cannot add components: Entity with ID ${Y} does not exist`)}for(let Y in J)this.addComponent(X,Y,J[Y]);return this}removeComponent(j,J){let X=typeof j==="number"?this.entities.get(j):j;if(!X){let _=typeof j==="number"?j:j.id;throw Error(`Cannot remove component '${String(J)}': Entity with ID ${_} does not exist`)}let Y=X.components[J];delete X.components[J];let Z=this.removedCallbacks.get(J);if(Z&&Y!==void 0)for(let _ of[...Z])_(Y,X);return this.componentIndices.get(J)?.delete(X.id),this}getComponent(j,J){let X=this.entities.get(j);if(!X)throw Error(`Cannot get component '${String(J)}': Entity with ID ${j} does not exist`);return X.components[J]||null}getEntitiesWithQuery(j=[],J=[]){if(j.length===0){if(J.length===0)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((F)=>{return J.every(($)=>!($ in F.components))})}let X=j.reduce((F,$)=>{let U=this.componentIndices.get($)?.size??0,G=this.componentIndices.get(F)?.size??1/0;return U<G?$:F},j[0]),Y=this.componentIndices.get(X);if(!Y||Y.size===0)return[];let Z=[],_=J.length>0;for(let F of Y){let $=this.entities.get(F);if($&&j.every((U)=>(U in $.components))&&(!_||J.every((U)=>!(U in $.components))))Z.push($)}return Z}removeEntity(j,J){let X=typeof j==="number"?this.entities.get(j):j;if(!X)return!1;if(J?.cascade??!0){let Z=this.hierarchyManager.getDescendants(X.id);for(let _ of[...Z].reverse())this.removeEntityInternal(_)}return this.removeEntityInternal(X.id)}removeEntityInternal(j){let J=this.entities.get(j);if(!J)return!1;this.hierarchyManager.removeEntity(j);for(let X of Object.keys(J.components)){let Y=J.components[X];if(Y!==void 0){let Z=this.removedCallbacks.get(X);if(Z)for(let _ of[...Z])_(Y,J)}this.componentIndices.get(X)?.delete(J.id)}return this.entities.delete(J.id)}getEntity(j){return this.entities.get(j)}onComponentAdded(j,J){if(!this.addedCallbacks.has(j))this.addedCallbacks.set(j,new Set);return this.addedCallbacks.get(j).add(J),()=>{this.addedCallbacks.get(j)?.delete(J)}}onComponentRemoved(j,J){if(!this.removedCallbacks.has(j))this.removedCallbacks.set(j,new Set);return this.removedCallbacks.get(j).add(J),()=>{this.removedCallbacks.get(j)?.delete(J)}}spawnChild(j,J){let X=this.createEntity();return this.addComponents(X,J),this.setParent(X.id,j),X}setParent(j,J){return this.hierarchyManager.setParent(j,J),this}removeParent(j){return this.hierarchyManager.removeParent(j)}getParent(j){return this.hierarchyManager.getParent(j)}getChildren(j){return this.hierarchyManager.getChildren(j)}getChildAt(j,J){return this.hierarchyManager.getChildAt(j,J)}getChildIndex(j,J){return this.hierarchyManager.getChildIndex(j,J)}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,J){return this.hierarchyManager.isDescendantOf(j,J)}isAncestorOf(j,J){return this.hierarchyManager.isAncestorOf(j,J)}getRootEntities(){return this.hierarchyManager.getRootEntities()}forEachInHierarchy(j,J){this.hierarchyManager.forEachInHierarchy(j,J)}hierarchyIterator(j){return this.hierarchyManager.hierarchyIterator(j)}}class D{handlers=new Map;subscribe(j,J){return this.addHandler(j,J,!1)}once(j,J){return this.addHandler(j,J,!0)}unsubscribe(j,J){let X=this.handlers.get(j);if(!X)return!1;let Y=X.findIndex((Z)=>Z.callback===J);if(Y===-1)return!1;return X.splice(Y,1),!0}addHandler(j,J,X){if(!this.handlers.has(j))this.handlers.set(j,[]);let Y={callback:J,once:X};return this.handlers.get(j).push(Y),()=>{let Z=this.handlers.get(j);if(Z){let _=Z.indexOf(Y);if(_!==-1)Z.splice(_,1)}}}publish(j,J){let X=this.handlers.get(j);if(!X)return;let Y=[...X],Z=[];for(let _ of Y)if(_.callback(J),_.once)Z.push(_);if(Z.length>0)for(let _ of Z){let F=X.indexOf(_);if(F!==-1)X.splice(F,1)}}clear(){this.handlers.clear()}clearEvent(j){this.handlers.delete(j)}}function h(j){return typeof j==="object"&&j!==null&&"factory"in j&&typeof j.factory==="function"}function C(j,J){let X=[],Y=new Set,Z=new Set;function _(F,$=[]){if(Y.has(F))return;if(Z.has(F))throw Error(`Circular resource dependency: ${[...$,F].join(" -> ")}`);Z.add(F);for(let U of J(F))if(j.includes(U))_(U,[...$,F]);Z.delete(F),Y.add(F),X.push(F)}for(let F of j)_(F);return X}class L{resources=new Map;resourceFactories=new Map;resourceDependencies=new Map;resourceDisposers=new Map;initializedResourceKeys=new Set;add(j,J){if(h(J)){if(this.resourceFactories.set(j,J.factory),this.resourceDependencies.set(j,J.dependsOn??[]),J.onDispose)this.resourceDisposers.set(j,J.onDispose)}else if(this._isFactoryFunction(J))this.resourceFactories.set(j,J),this.resourceDependencies.set(j,[]);else this.resources.set(j,J),this.initializedResourceKeys.add(j),this.resourceDependencies.set(j,[]);return this}_isFactoryFunction(j){if(typeof j!=="function")return!1;let J=j.toString();if(J.startsWith("class "))return!1;if(J.includes("[native code]"))return!1;if(j.prototype){let X=Object.getOwnPropertyNames(j.prototype);if(X.length>1||X.length===1&&X[0]!=="constructor")return!1}if(j.name&&j.name[0]===j.name[0].toUpperCase()&&j.name.length>1){if(J.includes("this.")||J.includes("new "))return!1}return!0}get(j,J){let X=this.resources.get(j);if(X!==void 0)return X;let Y=this.resourceFactories.get(j);if(Y===void 0)throw Error(`Resource ${String(j)} not found`);let Z=Y(J);if(!(Z instanceof Promise))this.resources.set(j,Z),this.initializedResourceKeys.add(j);return Z}has(j){return this.resources.has(j)||this.resourceFactories.has(j)}remove(j){let J=this.resources.delete(j),X=this.resourceFactories.delete(j);return this.resourceDependencies.delete(j),this.resourceDisposers.delete(j),this.initializedResourceKeys.delete(j),J||X}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,J){if(!this.resourceFactories.has(j)||this.initializedResourceKeys.has(j))return;let Y=await this.resourceFactories.get(j)(J);this.resources.set(j,Y),this.initializedResourceKeys.add(j),this.resourceFactories.delete(j)}async initializeResources(j,...J){let X=J.length===0?this.getPendingInitializationKeys():J.map((Z)=>Z);if(X.length===0)return;let Y=C(X,(Z)=>this.resourceDependencies.get(Z)??[]);for(let Z of Y)await this.initializeResource(Z,j)}getDependencies(j){return this.resourceDependencies.get(j)??[]}async disposeResource(j,J){let X=j;if(!this.resources.has(X)&&!this.resourceFactories.has(X))return!1;if(this.initializedResourceKeys.has(X)){let Y=this.resourceDisposers.get(X),Z=this.resources.get(X);if(Y&&Z!==void 0)await Y(Z,J)}return this.resources.delete(X),this.resourceFactories.delete(X),this.resourceDependencies.delete(X),this.resourceDisposers.delete(X),this.initializedResourceKeys.delete(X),!0}async disposeResources(j){let J=Array.from(this.initializedResourceKeys);if(J.length===0)return;let X=C(J,(Y)=>this.resourceDependencies.get(Y)??[]).reverse();for(let Y of X)await this.disposeResource(Y,j)}}class w{assets=new Map;groups=new Map;eventBus=null;setEventBus(j){this.eventBus=j}register(j,J){if(this.assets.set(j,{definition:J,status:"pending"}),J.group){let X=this.groups.get(J.group)??new Set;X.add(j),this.groups.set(J.group,X)}}async loadEagerAssets(){let j=[];for(let[J,X]of this.assets)if(X.definition.eager&&X.status==="pending")j.push(J);await Promise.all(j.map((J)=>this.loadAsset(J)))}async loadAsset(j){let J=j,X=this.assets.get(J);if(!X)throw Error(`Asset '${J}' not found`);if(X.status==="loaded"&&X.value!==void 0)return X.value;if(X.status==="loading"&&X.loadPromise)return X.loadPromise;if(X.status==="failed")X.status="pending";X.status="loading",X.loadPromise=X.definition.loader();try{let Y=await X.loadPromise;return X.value=Y,X.status="loaded",X.loadPromise=void 0,this.eventBus?.publish("assetLoaded",{key:J}),this.checkGroupProgress(X.definition.group),Y}catch(Y){let Z=Y instanceof Error?Y:Error(String(Y));throw X.status="failed",X.error=Z,X.loadPromise=void 0,this.eventBus?.publish("assetFailed",{key:J,error:Z}),Z}}async loadAssetGroup(j){let J=this.groups.get(j);if(!J||J.size===0)throw Error(`Asset group '${j}' not found or empty`);await Promise.all(Array.from(J).map((X)=>this.loadAsset(X)))}get(j){let J=j,X=this.assets.get(J);if(!X)throw Error(`Asset '${J}' not found`);if(X.status!=="loaded"||X.value===void 0)throw Error(`Asset '${J}' is not loaded (status: ${X.status})`);return X.value}getOrUndefined(j){let J=j,X=this.assets.get(J);if(!X||X.status!=="loaded")return;return X.value}getHandle(j){let J=j,X=this.assets.get(J);if(!X)throw Error(`Asset '${J}' not found`);let Y=this;return{get status(){return X.status},get isLoaded(){return X.status==="loaded"},get(){return Y.get(j)},getOrUndefined(){return Y.getOrUndefined(j)}}}getStatus(j){let J=j,X=this.assets.get(J);if(!X)throw Error(`Asset '${J}' not found`);return X.status}isLoaded(j){let J=j;return this.assets.get(J)?.status==="loaded"}isGroupLoaded(j){let J=this.groups.get(j);if(!J||J.size===0)return!1;for(let X of J){let Y=this.assets.get(X);if(!Y||Y.status!=="loaded")return!1}return!0}getGroupProgress(j){let J=this.groups.get(j);if(!J||J.size===0)return 0;let X=0;for(let Y of J)if(this.assets.get(Y)?.status==="loaded")X++;return X/J.size}getGroupProgressDetails(j){let J=this.groups.get(j);if(!J||J.size===0)return{loaded:0,total:0,progress:0};let X=0;for(let Z of J)if(this.assets.get(Z)?.status==="loaded")X++;let Y=J.size;return{loaded:X,total:Y,progress:X/Y}}checkGroupProgress(j){if(!j||!this.eventBus)return;let J=this.getGroupProgressDetails(j);if(this.eventBus.publish("assetGroupProgress",{group:j,...J}),J.loaded===J.total)this.eventBus.publish("assetGroupLoaded",{group:j})}createResource(){let j=this;return{getStatus(J){return j.getStatus(J)},isLoaded(J){return j.isLoaded(J)},isGroupLoaded(J){return j.isGroupLoaded(J)},getGroupProgress(J){return j.getGroupProgress(J)},get(J){return j.get(J)},getOrUndefined(J){return j.getOrUndefined(J)},getHandle(J){return j.getHandle(J)}}}getKeys(){return Array.from(this.assets.keys())}getGroupNames(){return Array.from(this.groups.keys())}getGroupKeys(j){let J=this.groups.get(j);return J?Array.from(J):[]}}class q{manager;constructor(j){this.manager=j}add(j,J){return this.manager.register(j,{loader:J,eager:!0}),this}addWithConfig(j,J){return this.manager.register(j,J),this}addGroup(j,J){for(let[X,Y]of Object.entries(J))this.manager.register(X,{loader:Y,eager:!1,group:j});return this}getManager(){return this.manager}}function R(j){return new q(j??new w)}class M{screens=new Map;currentScreen=null;screenStack=[];eventBus=null;assetManager=null;ecs=null;setDependencies(j,J,X){this.eventBus=j,this.assetManager=J,this.ecs=X}register(j,J){this.screens.set(j,{definition:J})}async setScreen(j,J){let X=j,Y=this.screens.get(X);if(!Y)throw Error(`Screen '${X}' not found`);await this.verifyRequiredAssets(Y.definition);while(this.screenStack.length>0){let _=this.screenStack.pop();if(_)await this.exitScreen(_.name)}if(this.currentScreen)await this.exitScreen(this.currentScreen.name);let Z=Y.definition.initialState(J);this.currentScreen={name:j,config:J,state:Z},await Y.definition.onEnter?.(J,this.ecs),this.eventBus?.publish("screenEnter",{screen:X,config:J})}async pushScreen(j,J){let X=j,Y=this.screens.get(X);if(!Y)throw Error(`Screen '${X}' not found`);if(await this.verifyRequiredAssets(Y.definition),this.currentScreen)this.screenStack.push(this.currentScreen);let Z=Y.definition.initialState(J);this.currentScreen={name:j,config:J,state:Z},await Y.definition.onEnter?.(J,this.ecs),this.eventBus?.publish("screenPush",{screen:X,config:J})}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 J=this.screens.get(j);if(J?.definition.onExit)await J.definition.onExit(this.ecs);this.eventBus?.publish("screenExit",{screen:j})}async verifyRequiredAssets(j){if(!this.assetManager)return;if(j.requiredAssets){for(let J of j.requiredAssets)if(!this.assetManager.isLoaded(J))await this.assetManager.loadAsset(J)}if(j.requiredAssetGroups){for(let J of j.requiredAssetGroups)if(!this.assetManager.isGroupLoaded(J))await this.assetManager.loadAssetGroup(J)}}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 J=typeof j==="function"?j(this.currentScreen.state):j;this.currentScreen.state={...this.currentScreen.state,...J}}getStackDepth(){return this.screenStack.length}isOverlay(){return this.screenStack.length>0}isActive(j){if(this.currentScreen?.name===j)return!0;return this.screenStack.some((J)=>J.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(J){if(j.currentScreen)j.currentScreen.state=J},get stack(){return j.screenStack},get isOverlay(){return j.isOverlay()},get stackDepth(){return j.getStackDepth()},isActive(J){return j.isActive(J)},isCurrent(J){return j.isCurrent(J)}}}getScreenNames(){return Array.from(this.screens.keys())}hasScreen(j){return this.screens.has(j)}}class S{manager;constructor(j){this.manager=j}add(j,J){return this.manager.register(j,J),this}getManager(){return this.manager}}function T(j){return new S(j??new M)}class K{queries=new Map;entityManager;constructor(j){this.entityManager=j}addQuery(j,J){let X={definition:J,matchingEntities:new Set};this.queries.set(j,X);let Y=this.entityManager.getEntitiesWithQuery(J.with,J.without??[]);for(let Z of Y)X.matchingEntities.add(Z.id),J.onEnter?.(Z)}removeQuery(j){return this.queries.delete(j)}entityMatchesQuery(j,J){for(let X of J.with)if(!(X in j.components))return!1;if(J.without){for(let X of J.without)if(X in j.components)return!1}return!0}onComponentAdded(j,J){for(let[X,Y]of this.queries){let Z=Y.matchingEntities.has(j.id),_=this.entityMatchesQuery(j,Y.definition);if(!Z&&_)Y.matchingEntities.add(j.id),Y.definition.onEnter?.(j);else if(Z&&!_)Y.matchingEntities.delete(j.id),Y.definition.onExit?.(j.id)}}onComponentRemoved(j,J){for(let[X,Y]of this.queries){let Z=Y.matchingEntities.has(j.id),_=this.entityMatchesQuery(j,Y.definition);if(Z&&!_)Y.matchingEntities.delete(j.id),Y.definition.onExit?.(j.id);else if(!Z&&_)Y.matchingEntities.add(j.id),Y.definition.onEnter?.(j)}}onEntityRemoved(j){for(let[J,X]of this.queries)if(X.matchingEntities.has(j))X.matchingEntities.delete(j),X.definition.onExit?.(j)}recheckEntity(j){for(let[J,X]of this.queries){let Y=X.matchingEntities.has(j.id),Z=this.entityMatchesQuery(j,X.definition);if(!Y&&Z)X.matchingEntities.add(j.id),X.definition.onEnter?.(j);else if(Y&&!Z)X.matchingEntities.delete(j.id),X.definition.onExit?.(j.id)}}}class z{commands=[];removeEntity(j,J){this.commands.push((X)=>{X.removeEntity(j,J)})}addComponent(j,J,X){this.commands.push((Y)=>{Y.entityManager.addComponent(j,J,X)})}removeComponent(j,J){this.commands.push((X)=>{X.entityManager.removeComponent(j,J)})}spawn(j){this.commands.push((J)=>{J.spawn(j)})}spawnChild(j,J){this.commands.push((X)=>{X.spawnChild(j,J)})}addComponents(j,J){this.commands.push((X)=>{X.entityManager.addComponents(j,J)})}setParent(j,J){this.commands.push((X)=>{X.setParent(j,J)})}removeParent(j){this.commands.push((J)=>{J.removeParent(j)})}playback(j){for(let J of this.commands)try{J(j)}catch(X){console.warn("CommandBuffer: Command failed during playback:",X)}this.commands=[]}clear(){this.commands=[]}get length(){return this.commands.length}}class B{_label;_ecspresso;_bundle;queries={};processFunction;detachFunction;initializeFunction;eventHandlers;_priority=0;_isRegistered=!1;_groups=[];_inScreens;_excludeScreens;_requiredAssets;constructor(j,J=null,X=null){this._label=j;this._ecspresso=J;this._bundle=X}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();x(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._groups.length>0)j.groups=[...this._groups];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}inGroup(j){if(!this._groups.includes(j))this._groups.push(j);return this}inScreens(j){return this._inScreens=[...j],this}excludeScreens(j){return this._excludeScreens=[...j],this}requiresAssets(j){return this._requiredAssets=[...j],this}addQuery(j,J){let X=this;return X.queries={...this.queries,[j]:J},X}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 J=this._createSystemObject();if(this._ecspresso)x(J,this._ecspresso);if(j)x(J,j);return this}}function x(j,J){J._registerSystem(j)}function v(j,J){return new B(j,J)}function O(j,J){return new B(j,null,J)}var f="0.8.0";var g={};class P{static VERSION=f;_entityManager;_eventBus;_resourceManager;_commandBuffer;_systems=[];_sortedSystems=[];_installedBundles=new Set;_disabledGroups=new Set;_assetManager=null;_screenManager=null;_reactiveQueryManager;_postUpdateHooks=[];constructor(){this._entityManager=new V,this._eventBus=new D,this._resourceManager=new L,this._reactiveQueryManager=new K(this._entityManager),this._commandBuffer=new z,this._sortedSystems=[],this._setupReactiveQueryHooks()}_setupReactiveQueryHooks(){let j=0,J=new Set,X=()=>{for(let $ of J){let U=this._entityManager.getEntity($);if(U)this._reactiveQueryManager.recheckEntity(U)}J.clear()},Y=this._entityManager.addComponent.bind(this._entityManager);this._entityManager.addComponent=($,U,G)=>{let H=Y($,U,G),W=typeof $==="number"?$:$.id;if(j>0)J.add(W);else{let E=this._entityManager.getEntity(W);if(E)this._reactiveQueryManager.onComponentAdded(E,U)}return H};let Z=this._entityManager.addComponents.bind(this._entityManager);this._entityManager.addComponents=($,U)=>{j++;let G=Z($,U);if(j--,j===0)X();return G};let _=this._entityManager.removeComponent.bind(this._entityManager);this._entityManager.removeComponent=($,U)=>{let G=typeof $==="number"?$:$.id,H=this._entityManager.getEntity(G),W=_($,U);if(H)this._reactiveQueryManager.onComponentRemoved(H,U);return W};let F=this._entityManager.removeEntity.bind(this._entityManager);this._entityManager.removeEntity=($,U)=>{let G=typeof $==="number"?$:$.id;if(this._entityManager.getEntity(G)){if(U?.cascade??!0){let E=this._entityManager.getDescendants(G);for(let b of E)this._reactiveQueryManager.onEntityRemoved(b)}this._reactiveQueryManager.onEntityRemoved(G)}return F($,U)}}static create(){return new N}addSystem(j){return v(j,this)}update(j){let J=this._screenManager?.getCurrentScreen()??null;for(let X of this._sortedSystems){if(!X.process)continue;if(X.groups?.length){let F=!1;for(let $ of X.groups)if(this._disabledGroups.has($)){F=!0;break}if(F)continue}if(X.inScreens?.length){if(J===null||!X.inScreens.includes(J))continue}if(X.excludeScreens?.length){if(J!==null&&X.excludeScreens.includes(J))continue}if(X.requiredAssets?.length&&this._assetManager){let F=!0;for(let $ of X.requiredAssets)if(!this._assetManager.isLoaded($)){F=!1;break}if(!F)continue}let Y={},Z=!1,_=!1;if(X.entityQueries)for(let F in X.entityQueries){_=!0;let $=X.entityQueries[F];if($){if(Y[F]=this._entityManager.getEntitiesWithQuery($.with,$.without||[]),Y[F].length)Z=!0}}if(Z)X.process(Y,j,this);else if(!_)X.process(g,j,this)}for(let X of this._postUpdateHooks)X(this,j);this._commandBuffer.playback(this)}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,J)=>{let X=j.priority??0;return(J.priority??0)-X})}updateSystemPriority(j,J){let X=this._systems.find((Y)=>Y.label===j);if(!X)return!1;return X.priority=J,this._sortSystems(),!0}disableSystemGroup(j){this._disabledGroups.add(j)}enableSystemGroup(j){this._disabledGroups.delete(j)}isSystemGroupEnabled(j){return!this._disabledGroups.has(j)}getSystemsInGroup(j){return this._systems.filter((J)=>J.groups?.includes(j)).map((J)=>J.label)}removeSystem(j){let J=this._systems.findIndex((Y)=>Y.label===j);if(J===-1)return!1;let X=this._systems[J];if(!X)return!1;if(X.onDetach)X.onDetach(this);return this._systems.splice(J,1),this._sortSystems(),!0}_registerSystem(j){if(this._systems.push(j),this._sortSystems(),!j.eventHandlers)return;for(let J in j.eventHandlers){let X=j.eventHandlers[J]?.handler;if(X)this._eventBus.subscribe(J,(Y)=>{X(Y,this)})}}hasResource(j){return this._resourceManager.has(j)}getResource(j){let J=this._resourceManager.get(j,this);if(!J)throw Error(`Resource '${String(j)}' not found. Available resources: [${this.getResourceKeys().map((X)=>String(X)).join(", ")}]`);return J}addResource(j,J){return this._resourceManager.add(j,J),this}removeResource(j){return this._resourceManager.remove(j)}async disposeResource(j){return this._resourceManager.disposeResource(j,this)}async disposeResources(){return this._resourceManager.disposeResources(this)}updateResource(j,J){let X=this.getResource(j),Y=J(X);return this._resourceManager.add(j,Y),this}getResourceKeys(){return this._resourceManager.getKeys()}resourceNeedsInitialization(j){return this._resourceManager.needsInitialization(j)}hasComponent(j,J){return this._entityManager.getComponent(j,J)!==null}spawn(j){let J=this._entityManager.createEntity();return this._entityManager.addComponents(J,j),J}getEntitiesWithQuery(j,J=[]){return this._entityManager.getEntitiesWithQuery(j,J)}removeEntity(j,J){return this._entityManager.removeEntity(j,J)}spawnChild(j,J){let X=this._entityManager.spawnChild(j,J);return this._emitHierarchyChanged(X.id,null,j),X}setParent(j,J){let X=this._entityManager.getParent(j);return this._entityManager.setParent(j,J),this._emitHierarchyChanged(j,X,J),this}removeParent(j){let J=this._entityManager.getParent(j),X=this._entityManager.removeParent(j);if(X)this._emitHierarchyChanged(j,J,null);return X}getParent(j){return this._entityManager.getParent(j)}getChildren(j){return this._entityManager.getChildren(j)}getChildAt(j,J){return this._entityManager.getChildAt(j,J)}getChildIndex(j,J){return this._entityManager.getChildIndex(j,J)}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,J){return this._entityManager.isDescendantOf(j,J)}isAncestorOf(j,J){return this._entityManager.isAncestorOf(j,J)}getRootEntities(){return this._entityManager.getRootEntities()}forEachInHierarchy(j,J){this._entityManager.forEachInHierarchy(j,J)}hierarchyIterator(j){return this._entityManager.hierarchyIterator(j)}_emitHierarchyChanged(j,J,X){this._eventBus.publish("hierarchyChanged",{entityId:j,oldParent:J,newParent:X})}get installedBundles(){return Array.from(this._installedBundles)}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}get commands(){return this._commandBuffer}onComponentAdded(j,J){return this._entityManager.onComponentAdded(j,J)}onComponentRemoved(j,J){return this._entityManager.onComponentRemoved(j,J)}addReactiveQuery(j,J){this._reactiveQueryManager.addQuery(j,J)}removeReactiveQuery(j){return this._reactiveQueryManager.removeQuery(j)}on(j,J){return this._eventBus.subscribe(j,J)}off(j,J){return this._eventBus.unsubscribe(j,J)}onPostUpdate(j){return this._postUpdateHooks.push(j),()=>{let J=this._postUpdateHooks.indexOf(j);if(J!==-1)this._postUpdateHooks.splice(J,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,J){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.setScreen(j,J)}async pushScreen(j,J){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.pushScreen(j,J)}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 J=j.getResources();for(let[X,Y]of J.entries())this._resourceManager.add(X,Y);if(this._assetManager){let X=j.getAssets();for(let[Y,Z]of X.entries())this._assetManager.register(Y,Z)}if(this._screenManager){let X=j.getScreens();for(let[Y,Z]of X.entries())this._screenManager.register(Y,Z)}return this}}class N{ecspresso;assetConfigurator=null;screenConfigurator=null;pendingResources=[];constructor(){this.ecspresso=new P}withBundle(j){return this.ecspresso._installBundle(j),this}withResource(j,J){return this.pendingResources.push({key:j,value:J}),this}withAssets(j){let J=R();return j(J),this.assetConfigurator=J,this}withScreens(j){let J=T();return j(J),this.screenConfigurator=J,this}build(){for(let{key:j,value:J}of this.pendingResources)this.ecspresso.addResource(j,J);if(this.assetConfigurator)this.ecspresso._setAssetManager(this.assetConfigurator.getManager());if(this.screenConfigurator)this.ecspresso._setScreenManager(this.screenConfigurator.getManager());return this.ecspresso}}function I(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class A{_systems=[];_resources=new Map;_assets=new Map;_assetGroups=new Map;_screens=new Map;_id;constructor(j){this._id=j||I()}get id(){return this._id}set id(j){this._id=j}addSystem(j){if(typeof j==="string"){let J=O(j,this);return this._systems.push(J),J}else return this._systems.push(j),j}addResource(j,J){return this._resources.set(j,J),this}addAsset(j,J,X){return this._assets.set(j,{loader:J,eager:X?.eager??!0,group:X?.group}),this}addAssetGroup(j,J){let X=new Map;for(let[Y,Z]of Object.entries(J))X.set(Y,Z),this._assets.set(Y,{loader:Z,eager:!1,group:j});return this._assetGroups.set(j,X),this}addScreen(j,J){return this._screens.set(j,J),this}getAssets(){return new Map(this._assets)}getScreens(){return new Map(this._screens)}_setResource(j,J){this._resources.set(j,J)}_setAsset(j,J){this._assets.set(j,J)}_setScreen(j,J){this._screens.set(j,J)}getSystems(){return this._systems.map((j)=>j.build())}registerSystemsWithEcspresso(j){for(let J of this._systems)J.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 p(j,...J){if(J.length===0)return new A(j);let X=new A(j);for(let Y of J){for(let Z of Y.getSystemBuilders())X.addSystem(Z);for(let[Z,_]of Y.getResources().entries())X._setResource(Z,_);for(let[Z,_]of Y.getAssets().entries())X._setAsset(Z,_);for(let[Z,_]of Y.getScreens().entries())X._setScreen(Z,_)}return X}function zj(j){return j}var fj=P;export{p as mergeBundles,fj as default,T as createScreenConfigurator,zj as createQueryDefinition,R as createAssetConfigurator,B as SystemBuilder,M as ScreenManager,L as ResourceManager,Q as HierarchyManager,D as EventBus,V as EntityManager,z as CommandBuffer,A as Bundle,w as AssetManager};
|
|
1
|
+
var c=((j)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(j,{get:(J,X)=>(typeof require<"u"?require:J)[X]}):j)(function(j){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+j+'" is not supported')});class z{parentMap=new Map;childrenMap=new Map;setParent(j,J){if(j===J)throw Error(`Cannot set entity ${j} as its own parent`);if(this.wouldCreateCycle(j,J))throw Error("Cannot set parent: would create circular reference");let X=this.parentMap.get(j);if(X!==void 0){let Z=this.childrenMap.get(X);if(Z){let $=Z.indexOf(j);if($!==-1)Z.splice($,1)}}this.parentMap.set(j,J);let Y=this.childrenMap.get(J);if(Y)Y.push(j);else this.childrenMap.set(J,[j]);return this}removeParent(j){let J=this.parentMap.get(j);if(J===void 0)return!1;let X=this.childrenMap.get(J);if(X){let Y=X.indexOf(j);if(Y!==-1)X.splice(Y,1)}return this.parentMap.delete(j),!0}getParent(j){return this.parentMap.get(j)??null}getChildren(j){let J=this.childrenMap.get(j);return J?[...J]:[]}getChildAt(j,J){if(J<0)return null;let X=this.childrenMap.get(j);if(!X||J>=X.length)return null;return X[J]??null}getChildIndex(j,J){let X=this.childrenMap.get(j);if(!X)return-1;return X.indexOf(J)}removeEntity(j){let J=this.parentMap.get(j)??null;if(J!==null){let Z=this.childrenMap.get(J);if(Z){let $=Z.indexOf(j);if($!==-1)Z.splice($,1)}}this.parentMap.delete(j);let X=this.childrenMap.get(j)??[],Y=[...X];for(let Z of X)this.parentMap.delete(Z);return this.childrenMap.delete(j),{oldParent:J,orphanedChildren:Y}}getAncestors(j){let J=[],X=this.parentMap.get(j);while(X!==void 0)J.push(X),X=this.parentMap.get(X);return J}getDescendants(j){let J=[],X=[...this.childrenMap.get(j)??[]];while(X.length>0){let Y=X.shift();if(Y===void 0)continue;J.push(Y);let Z=this.childrenMap.get(Y);if(Z)X.unshift(...Z)}return J}getRoot(j){let J=j,X=this.parentMap.get(J);while(X!==void 0)J=X,X=this.parentMap.get(J);return J}getSiblings(j){let J=this.parentMap.get(j);if(J===void 0)return[];let X=this.childrenMap.get(J);if(!X)return[];return X.filter((Y)=>Y!==j)}isDescendantOf(j,J){if(j===J)return!1;let X=this.parentMap.get(j);while(X!==void 0){if(X===J)return!0;X=this.parentMap.get(X)}return!1}isAncestorOf(j,J){return this.isDescendantOf(J,j)}getRootEntities(){let j=[];for(let J of this.childrenMap.keys())if(!this.parentMap.has(J))j.push(J);return j}wouldCreateCycle(j,J){let X=J;while(X!==void 0){if(X===j)return!0;X=this.parentMap.get(X)}return!1}forEachInHierarchy(j,J){let X=J?.roots??this.getRootEntities(),Y=[];for(let Z of X)Y.push({entityId:Z,parentId:null,depth:0});while(Y.length>0){let Z=Y.shift();if(!Z)break;j(Z.entityId,Z.parentId,Z.depth);let $=this.childrenMap.get(Z.entityId);if($)for(let G of $)Y.push({entityId:G,parentId:Z.entityId,depth:Z.depth+1})}}*hierarchyIterator(j){let J=j?.roots??this.getRootEntities(),X=[];for(let Y of J)X.push({entityId:Y,parentId:null,depth:0});while(X.length>0){let Y=X.shift();if(!Y)break;yield Y;let Z=this.childrenMap.get(Y.entityId);if(Z)for(let $ of Z)X.push({entityId:$,parentId:Y.entityId,depth:Y.depth+1})}}}class A{nextId=1;entities=new Map;componentIndices=new Map;addedCallbacks=new Map;removedCallbacks=new Map;hierarchyManager=new z;changeSeqs=new Map;_changeSeq=0;createEntity(){let j=this.nextId++,J={id:j,components:{}};return this.entities.set(j,J),J}addComponent(j,J,X){let Y=typeof j==="number"?this.entities.get(j):j;if(!Y){let $=typeof j==="number"?j:j.id;throw Error(`Cannot add component '${String(J)}': Entity with ID ${$} does not exist`)}if(Y.components[J]=X,!this.componentIndices.has(J))this.componentIndices.set(J,new Set);this.componentIndices.get(J)?.add(Y.id);let Z=this.addedCallbacks.get(J);if(Z)for(let $ of[...Z])$(X,Y);return this}addComponents(j,J){let X=typeof j==="number"?this.entities.get(j):j;if(!X){let Y=typeof j==="number"?j:j.id;throw Error(`Cannot add components: Entity with ID ${Y} does not exist`)}for(let Y in J)this.addComponent(X,Y,J[Y]);return this}removeComponent(j,J){let X=typeof j==="number"?this.entities.get(j):j;if(!X){let $=typeof j==="number"?j:j.id;throw Error(`Cannot remove component '${String(J)}': Entity with ID ${$} does not exist`)}let Y=X.components[J];delete X.components[J];let Z=this.removedCallbacks.get(J);if(Z&&Y!==void 0)for(let $ of[...Z])$(Y,X);return this.componentIndices.get(J)?.delete(X.id),this}getComponent(j,J){let X=this.entities.get(j);if(!X)throw Error(`Cannot get component '${String(J)}': Entity with ID ${j} does not exist`);return X.components[J]||null}getEntitiesWithQuery(j=[],J=[],X,Y,Z){let $=X!==void 0&&X.length>0&&Y!==void 0,G=Z!==void 0&&Z.length>0;if(j.length===0){if(J.length===0&&!$&&!G)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((_)=>{if(J.length>0&&!J.every((W)=>!(W in _.components)))return!1;if($){let W=this.changeSeqs.get(_.id);if(!W)return!1;if(!X.some((L)=>(W.get(L)??-1)>Y))return!1}if(G&&!this.parentHasComponents(_.id,Z))return!1;return!0})}let Q=j.reduce((_,W)=>{let L=this.componentIndices.get(W)?.size??0,D=this.componentIndices.get(_)?.size??1/0;return L<D?W:_},j[0]),F=this.componentIndices.get(Q);if(!F||F.size===0)return[];let U=[],V=J.length>0;for(let _ of F){let W=this.entities.get(_);if(W&&j.every((L)=>(L in W.components))&&(!V||J.every((L)=>!(L in W.components)))){if($){let L=this.changeSeqs.get(_);if(!L||!X.some((D)=>(L.get(D)??-1)>Y))continue}if(G&&!this.parentHasComponents(_,Z))continue;U.push(W)}}return U}parentHasComponents(j,J){let X=this.hierarchyManager.getParent(j);if(X===null)return!1;let Y=this.entities.get(X);if(!Y)return!1;for(let Z of J)if(!(Z in Y.components))return!1;return!0}removeEntity(j,J){let X=typeof j==="number"?this.entities.get(j):j;if(!X)return!1;if(J?.cascade??!0){let Z=this.hierarchyManager.getDescendants(X.id);for(let $ of[...Z].reverse())this.removeEntityInternal($)}return this.removeEntityInternal(X.id)}removeEntityInternal(j){let J=this.entities.get(j);if(!J)return!1;this.hierarchyManager.removeEntity(j);for(let X of Object.keys(J.components)){let Y=J.components[X];if(Y!==void 0){let Z=this.removedCallbacks.get(X);if(Z)for(let $ of[...Z])$(Y,J)}this.componentIndices.get(X)?.delete(J.id)}return this.changeSeqs.delete(J.id),this.entities.delete(J.id)}getEntity(j){return this.entities.get(j)}onComponentAdded(j,J){if(!this.addedCallbacks.has(j))this.addedCallbacks.set(j,new Set);return this.addedCallbacks.get(j).add(J),()=>{this.addedCallbacks.get(j)?.delete(J)}}onComponentRemoved(j,J){if(!this.removedCallbacks.has(j))this.removedCallbacks.set(j,new Set);return this.removedCallbacks.get(j).add(J),()=>{this.removedCallbacks.get(j)?.delete(J)}}get changeSeq(){return this._changeSeq}markChanged(j,J){let X=++this._changeSeq,Y=this.changeSeqs.get(j);if(!Y)Y=new Map,this.changeSeqs.set(j,Y);Y.set(J,X)}getChangeSeq(j,J){return this.changeSeqs.get(j)?.get(J)??-1}clearChangeSeqs(j){this.changeSeqs.delete(j)}spawnChild(j,J){let X=this.createEntity();return this.addComponents(X,J),this.setParent(X.id,j),X}setParent(j,J){return this.hierarchyManager.setParent(j,J),this}removeParent(j){return this.hierarchyManager.removeParent(j)}getParent(j){return this.hierarchyManager.getParent(j)}getChildren(j){return this.hierarchyManager.getChildren(j)}getChildAt(j,J){return this.hierarchyManager.getChildAt(j,J)}getChildIndex(j,J){return this.hierarchyManager.getChildIndex(j,J)}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,J){return this.hierarchyManager.isDescendantOf(j,J)}isAncestorOf(j,J){return this.hierarchyManager.isAncestorOf(j,J)}getRootEntities(){return this.hierarchyManager.getRootEntities()}forEachInHierarchy(j,J){this.hierarchyManager.forEachInHierarchy(j,J)}hierarchyIterator(j){return this.hierarchyManager.hierarchyIterator(j)}}class H{handlers=new Map;subscribe(j,J){return this.addHandler(j,J,!1)}once(j,J){return this.addHandler(j,J,!0)}unsubscribe(j,J){let X=this.handlers.get(j);if(!X)return!1;let Y=X.findIndex((Z)=>Z.callback===J);if(Y===-1)return!1;return X.splice(Y,1),!0}addHandler(j,J,X){if(!this.handlers.has(j))this.handlers.set(j,[]);let Y={callback:J,once:X};return this.handlers.get(j).push(Y),()=>{let Z=this.handlers.get(j);if(Z){let $=Z.indexOf(Y);if($!==-1)Z.splice($,1)}}}publish(j,J){let X=this.handlers.get(j);if(!X)return;let Y=[...X],Z=[];for(let $ of Y)if($.callback(J),$.once)Z.push($);if(Z.length>0)for(let $ of Z){let G=X.indexOf($);if(G!==-1)X.splice(G,1)}}clear(){this.handlers.clear()}clearEvent(j){this.handlers.delete(j)}}function I(j){return typeof j==="object"&&j!==null&&"factory"in j&&typeof j.factory==="function"}function v(j,J){let X=[],Y=new Set,Z=new Set;function $(G,Q=[]){if(Y.has(G))return;if(Z.has(G))throw Error(`Circular resource dependency: ${[...Q,G].join(" -> ")}`);Z.add(G);for(let F of J(G))if(j.includes(F))$(F,[...Q,G]);Z.delete(G),Y.add(G),X.push(G)}for(let G of j)$(G);return X}class P{resources=new Map;resourceFactories=new Map;resourceDependencies=new Map;resourceDisposers=new Map;initializedResourceKeys=new Set;add(j,J){if(I(J)){if(this.resourceFactories.set(j,J.factory),this.resourceDependencies.set(j,J.dependsOn??[]),J.onDispose)this.resourceDisposers.set(j,J.onDispose)}else if(this._isFactoryFunction(J))this.resourceFactories.set(j,J),this.resourceDependencies.set(j,[]);else this.resources.set(j,J),this.initializedResourceKeys.add(j),this.resourceDependencies.set(j,[]);return this}_isFactoryFunction(j){if(typeof j!=="function")return!1;let J=j.toString();if(J.startsWith("class "))return!1;if(J.includes("[native code]"))return!1;if(j.prototype){let X=Object.getOwnPropertyNames(j.prototype);if(X.length>1||X.length===1&&X[0]!=="constructor")return!1}if(j.name&&j.name[0]===j.name[0].toUpperCase()&&j.name.length>1){if(J.includes("this.")||J.includes("new "))return!1}return!0}get(j,J){let X=this.resources.get(j);if(X!==void 0)return X;let Y=this.resourceFactories.get(j);if(Y===void 0)throw Error(`Resource ${String(j)} not found`);let Z=Y(J);if(!(Z instanceof Promise))this.resources.set(j,Z),this.initializedResourceKeys.add(j);return Z}has(j){return this.resources.has(j)||this.resourceFactories.has(j)}remove(j){let J=this.resources.delete(j),X=this.resourceFactories.delete(j);return this.resourceDependencies.delete(j),this.resourceDisposers.delete(j),this.initializedResourceKeys.delete(j),J||X}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,J){if(!this.resourceFactories.has(j)||this.initializedResourceKeys.has(j))return;let Y=await this.resourceFactories.get(j)(J);this.resources.set(j,Y),this.initializedResourceKeys.add(j),this.resourceFactories.delete(j)}async initializeResources(j,...J){let X=J.length===0?this.getPendingInitializationKeys():J.map((Z)=>Z);if(X.length===0)return;let Y=v(X,(Z)=>this.resourceDependencies.get(Z)??[]);for(let Z of Y)await this.initializeResource(Z,j)}getDependencies(j){return this.resourceDependencies.get(j)??[]}async disposeResource(j,J){let X=j;if(!this.resources.has(X)&&!this.resourceFactories.has(X))return!1;if(this.initializedResourceKeys.has(X)){let Y=this.resourceDisposers.get(X),Z=this.resources.get(X);if(Y&&Z!==void 0)await Y(Z,J)}return this.resources.delete(X),this.resourceFactories.delete(X),this.resourceDependencies.delete(X),this.resourceDisposers.delete(X),this.initializedResourceKeys.delete(X),!0}async disposeResources(j){let J=Array.from(this.initializedResourceKeys);if(J.length===0)return;let X=v(J,(Y)=>this.resourceDependencies.get(Y)??[]).reverse();for(let Y of X)await this.disposeResource(Y,j)}}class E{assets=new Map;groups=new Map;eventBus=null;setEventBus(j){this.eventBus=j}register(j,J){if(this.assets.set(j,{definition:J,status:"pending"}),J.group){let X=this.groups.get(J.group)??new Set;X.add(j),this.groups.set(J.group,X)}}async loadEagerAssets(){let j=[];for(let[J,X]of this.assets)if(X.definition.eager&&X.status==="pending")j.push(J);await Promise.all(j.map((J)=>this.loadAsset(J)))}async loadAsset(j){let J=j,X=this.assets.get(J);if(!X)throw Error(`Asset '${J}' not found`);if(X.status==="loaded"&&X.value!==void 0)return X.value;if(X.status==="loading"&&X.loadPromise)return X.loadPromise;if(X.status==="failed")X.status="pending";X.status="loading",X.loadPromise=X.definition.loader();try{let Y=await X.loadPromise;return X.value=Y,X.status="loaded",X.loadPromise=void 0,this.eventBus?.publish("assetLoaded",{key:J}),this.checkGroupProgress(X.definition.group),Y}catch(Y){let Z=Y instanceof Error?Y:Error(String(Y));throw X.status="failed",X.error=Z,X.loadPromise=void 0,this.eventBus?.publish("assetFailed",{key:J,error:Z}),Z}}async loadAssetGroup(j){let J=this.groups.get(j);if(!J||J.size===0)throw Error(`Asset group '${j}' not found or empty`);await Promise.all(Array.from(J).map((X)=>this.loadAsset(X)))}get(j){let J=j,X=this.assets.get(J);if(!X)throw Error(`Asset '${J}' not found`);if(X.status!=="loaded"||X.value===void 0)throw Error(`Asset '${J}' is not loaded (status: ${X.status})`);return X.value}getOrUndefined(j){let J=j,X=this.assets.get(J);if(!X||X.status!=="loaded")return;return X.value}getHandle(j){let J=j,X=this.assets.get(J);if(!X)throw Error(`Asset '${J}' not found`);let Y=this;return{get status(){return X.status},get isLoaded(){return X.status==="loaded"},get(){return Y.get(j)},getOrUndefined(){return Y.getOrUndefined(j)}}}getStatus(j){let J=j,X=this.assets.get(J);if(!X)throw Error(`Asset '${J}' not found`);return X.status}isLoaded(j){let J=j;return this.assets.get(J)?.status==="loaded"}isGroupLoaded(j){let J=this.groups.get(j);if(!J||J.size===0)return!1;for(let X of J){let Y=this.assets.get(X);if(!Y||Y.status!=="loaded")return!1}return!0}getGroupProgress(j){let J=this.groups.get(j);if(!J||J.size===0)return 0;let X=0;for(let Y of J)if(this.assets.get(Y)?.status==="loaded")X++;return X/J.size}getGroupProgressDetails(j){let J=this.groups.get(j);if(!J||J.size===0)return{loaded:0,total:0,progress:0};let X=0;for(let Z of J)if(this.assets.get(Z)?.status==="loaded")X++;let Y=J.size;return{loaded:X,total:Y,progress:X/Y}}checkGroupProgress(j){if(!j||!this.eventBus)return;let J=this.getGroupProgressDetails(j);if(this.eventBus.publish("assetGroupProgress",{group:j,...J}),J.loaded===J.total)this.eventBus.publish("assetGroupLoaded",{group:j})}createResource(){let j=this;return{getStatus(J){return j.getStatus(J)},isLoaded(J){return j.isLoaded(J)},isGroupLoaded(J){return j.isGroupLoaded(J)},getGroupProgress(J){return j.getGroupProgress(J)},get(J){return j.get(J)},getOrUndefined(J){return j.getOrUndefined(J)},getHandle(J){return j.getHandle(J)}}}getKeys(){return Array.from(this.assets.keys())}getGroupNames(){return Array.from(this.groups.keys())}getGroupKeys(j){let J=this.groups.get(j);return J?Array.from(J):[]}}class O{manager;constructor(j){this.manager=j}add(j,J){return this.manager.register(j,{loader:J,eager:!0}),this}addWithConfig(j,J){return this.manager.register(j,J),this}addGroup(j,J){for(let[X,Y]of Object.entries(J))this.manager.register(X,{loader:Y,eager:!1,group:j});return this}getManager(){return this.manager}}function T(j){return new O(j??new E)}class R{screens=new Map;currentScreen=null;screenStack=[];eventBus=null;assetManager=null;ecs=null;setDependencies(j,J,X){this.eventBus=j,this.assetManager=J,this.ecs=X}register(j,J){this.screens.set(j,{definition:J})}async setScreen(j,J){let X=j,Y=this.screens.get(X);if(!Y)throw Error(`Screen '${X}' not found`);await this.verifyRequiredAssets(Y.definition);while(this.screenStack.length>0){let $=this.screenStack.pop();if($)await this.exitScreen($.name)}if(this.currentScreen)await this.exitScreen(this.currentScreen.name);let Z=Y.definition.initialState(J);this.currentScreen={name:j,config:J,state:Z},await Y.definition.onEnter?.(J,this.ecs),this.eventBus?.publish("screenEnter",{screen:X,config:J})}async pushScreen(j,J){let X=j,Y=this.screens.get(X);if(!Y)throw Error(`Screen '${X}' not found`);if(await this.verifyRequiredAssets(Y.definition),this.currentScreen)this.screenStack.push(this.currentScreen);let Z=Y.definition.initialState(J);this.currentScreen={name:j,config:J,state:Z},await Y.definition.onEnter?.(J,this.ecs),this.eventBus?.publish("screenPush",{screen:X,config:J})}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 J=this.screens.get(j);if(J?.definition.onExit)await J.definition.onExit(this.ecs);this.eventBus?.publish("screenExit",{screen:j})}async verifyRequiredAssets(j){if(!this.assetManager)return;if(j.requiredAssets){for(let J of j.requiredAssets)if(!this.assetManager.isLoaded(J))await this.assetManager.loadAsset(J)}if(j.requiredAssetGroups){for(let J of j.requiredAssetGroups)if(!this.assetManager.isGroupLoaded(J))await this.assetManager.loadAssetGroup(J)}}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 J=typeof j==="function"?j(this.currentScreen.state):j;this.currentScreen.state={...this.currentScreen.state,...J}}getStackDepth(){return this.screenStack.length}isOverlay(){return this.screenStack.length>0}isActive(j){if(this.currentScreen?.name===j)return!0;return this.screenStack.some((J)=>J.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(J){if(j.currentScreen)j.currentScreen.state=J},get stack(){return j.screenStack},get isOverlay(){return j.isOverlay()},get stackDepth(){return j.getStackDepth()},isActive(J){return j.isActive(J)},isCurrent(J){return j.isCurrent(J)}}}getScreenNames(){return Array.from(this.screens.keys())}hasScreen(j){return this.screens.has(j)}}class S{manager;constructor(j){this.manager=j}add(j,J){return this.manager.register(j,J),this}getManager(){return this.manager}}function q(j){return new S(j??new R)}class x{queries=new Map;entityManager;_hasParentHasQueries=!1;constructor(j){this.entityManager=j}get hasParentHasQueries(){return this._hasParentHasQueries}addQuery(j,J){let X={definition:J,matchingEntities:new Set};if(this.queries.set(j,X),J.parentHas?.length)this._hasParentHasQueries=!0;let Y=this.entityManager.getEntitiesWithQuery(J.with,J.without??[]);for(let Z of Y)if(this.entityMatchesQuery(Z,X.definition))X.matchingEntities.add(Z.id),X.definition.onEnter?.(Z)}removeQuery(j){let J=this.queries.delete(j);if(J)this._recalcParentHasFlag();return J}entityMatchesQuery(j,J){for(let X of J.with)if(!(X in j.components))return!1;if(J.without){for(let X of J.without)if(X in j.components)return!1}if(J.parentHas?.length){let X=this.entityManager.getParent(j.id);if(X===null)return!1;let Y=this.entityManager.getEntity(X);if(!Y)return!1;for(let Z of J.parentHas)if(!(Z in Y.components))return!1}return!0}onComponentAdded(j,J){for(let[X,Y]of this.queries){let Z=Y.matchingEntities.has(j.id),$=this.entityMatchesQuery(j,Y.definition);if(!Z&&$)Y.matchingEntities.add(j.id),Y.definition.onEnter?.(j);else if(Z&&!$)Y.matchingEntities.delete(j.id),Y.definition.onExit?.(j.id)}if(this._hasParentHasQueries)this._recheckChildren(j.id)}onComponentRemoved(j,J){for(let[X,Y]of this.queries){let Z=Y.matchingEntities.has(j.id),$=this.entityMatchesQuery(j,Y.definition);if(Z&&!$)Y.matchingEntities.delete(j.id),Y.definition.onExit?.(j.id);else if(!Z&&$)Y.matchingEntities.add(j.id),Y.definition.onEnter?.(j)}if(this._hasParentHasQueries)this._recheckChildren(j.id)}onEntityRemoved(j){for(let[J,X]of this.queries)if(X.matchingEntities.has(j))X.matchingEntities.delete(j),X.definition.onExit?.(j)}recheckEntity(j){for(let[J,X]of this.queries){let Y=X.matchingEntities.has(j.id),Z=this.entityMatchesQuery(j,X.definition);if(!Y&&Z)X.matchingEntities.add(j.id),X.definition.onEnter?.(j);else if(Y&&!Z)X.matchingEntities.delete(j.id),X.definition.onExit?.(j.id)}}_recheckChildren(j){let J=this.entityManager.getChildren(j);for(let X of J){let Y=this.entityManager.getEntity(X);if(Y)this.recheckEntity(Y)}}_recalcParentHasFlag(){this._hasParentHasQueries=!1;for(let[,j]of this.queries)if(j.definition.parentHas?.length){this._hasParentHasQueries=!0;return}}}class M{commands=[];removeEntity(j,J){this.commands.push((X)=>{X.removeEntity(j,J)})}addComponent(j,J,X){this.commands.push((Y)=>{Y.entityManager.addComponent(j,J,X)})}removeComponent(j,J){this.commands.push((X)=>{X.entityManager.removeComponent(j,J)})}spawn(j){this.commands.push((J)=>{J.spawn(j)})}spawnChild(j,J){this.commands.push((X)=>{X.spawnChild(j,J)})}addComponents(j,J){this.commands.push((X)=>{X.entityManager.addComponents(j,J)})}setParent(j,J){this.commands.push((X)=>{X.setParent(j,J)})}markChanged(j,J){this.commands.push((X)=>{X.markChanged(j,J)})}removeParent(j){this.commands.push((J)=>{J.removeParent(j)})}playback(j){for(let J of this.commands)try{J(j)}catch(X){console.warn("CommandBuffer: Command failed during playback:",X)}this.commands=[]}clear(){this.commands=[]}get length(){return this.commands.length}}class w{_label;_ecspresso;_bundle;queries={};processFunction;detachFunction;initializeFunction;eventHandlers;_priority=0;_phase="update";_isRegistered=!1;_groups=[];_inScreens;_excludeScreens;_requiredAssets;constructor(j,J=null,X=null){this._label=j;this._ecspresso=J;this._bundle=X}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();C(j,this._ecspresso),this._isRegistered=!0}_buildSystemObject(){return this._createSystemObject()}_createSystemObject(){let j={label:this._label,entityQueries:this.queries,priority:this._priority,phase:this._phase};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._groups.length>0)j.groups=[...this._groups];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}inPhase(j){return this._phase=j,this}inGroup(j){if(!this._groups.includes(j))this._groups.push(j);return this}inScreens(j){return this._inScreens=[...j],this}excludeScreens(j){return this._excludeScreens=[...j],this}requiresAssets(j){return this._requiredAssets=[...j],this}addQuery(j,J){let X=this;return X.queries={...this.queries,[j]:J},X}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 J=this._createSystemObject();if(this._ecspresso)C(J,this._ecspresso);if(j)C(J,j);return this}}function C(j,J){J._registerSystem(j)}function f(j,J){return new w(j,J)}function b(j,J){return new w(j,null,J)}var N="0.10.0";var k=["preUpdate","fixedUpdate","update","postUpdate","render"],p={};class K{static VERSION=N;_entityManager;_eventBus;_resourceManager;_commandBuffer;_systems=[];_phaseSystems={preUpdate:[],fixedUpdate:[],update:[],postUpdate:[],render:[]};_installedBundles=new Set;_disabledGroups=new Set;_assetManager=null;_screenManager=null;_reactiveQueryManager;_postUpdateHooks=[];_currentTick=0;_systemLastSeqs=new Map;_changeThreshold=0;_fixedDt=0.016666666666666666;_fixedAccumulator=0;_interpolationAlpha=0;_maxFixedSteps=8;constructor(){this._entityManager=new A,this._eventBus=new H,this._resourceManager=new P,this._reactiveQueryManager=new x(this._entityManager),this._commandBuffer=new M,this._setupReactiveQueryHooks()}_setupReactiveQueryHooks(){let j=0,J=new Set,X=()=>{for(let U of J){let V=this._entityManager.getEntity(U);if(V)this._reactiveQueryManager.recheckEntity(V)}J.clear()},Y=this._entityManager.addComponent.bind(this._entityManager);this._entityManager.addComponent=(U,V,_)=>{let W=Y(U,V,_),L=typeof U==="number"?U:U.id;if(this._entityManager.markChanged(L,V),j>0)J.add(L);else{let D=this._entityManager.getEntity(L);if(D)this._reactiveQueryManager.onComponentAdded(D,V)}return W};let Z=this._entityManager.addComponents.bind(this._entityManager);this._entityManager.addComponents=(U,V)=>{j++;let _=Z(U,V);if(j--,j===0)X();return _};let $=this._entityManager.removeComponent.bind(this._entityManager);this._entityManager.removeComponent=(U,V)=>{let _=typeof U==="number"?U:U.id,W=this._entityManager.getEntity(_),L=$(U,V);if(W)this._reactiveQueryManager.onComponentRemoved(W,V);return L};let G=this._entityManager.setParent.bind(this._entityManager);this._entityManager.setParent=(U,V)=>{let _=G(U,V);if(this._reactiveQueryManager.hasParentHasQueries){let W=this._entityManager.getEntity(U);if(W)this._reactiveQueryManager.recheckEntity(W)}return _};let Q=this._entityManager.removeParent.bind(this._entityManager);this._entityManager.removeParent=(U)=>{let V=Q(U);if(this._reactiveQueryManager.hasParentHasQueries){let _=this._entityManager.getEntity(U);if(_)this._reactiveQueryManager.recheckEntity(_)}return V};let F=this._entityManager.removeEntity.bind(this._entityManager);this._entityManager.removeEntity=(U,V)=>{let _=typeof U==="number"?U:U.id;if(this._entityManager.getEntity(_)){if(V?.cascade??!0){let D=this._entityManager.getDescendants(_);for(let h of D)this._reactiveQueryManager.onEntityRemoved(h)}this._reactiveQueryManager.onEntityRemoved(_)}return F(U,V)}}static create(){return new g}addSystem(j){return f(j,this)}update(j){let J=this._screenManager?.getCurrentScreen()??null;this._executePhase(this._phaseSystems.preUpdate,j,J),this._commandBuffer.playback(this),this._fixedAccumulator+=j;let X=0;while(this._fixedAccumulator>=this._fixedDt&&X<this._maxFixedSteps)this._executePhase(this._phaseSystems.fixedUpdate,this._fixedDt,J),this._commandBuffer.playback(this),this._fixedAccumulator-=this._fixedDt,X++;if(this._fixedAccumulator>=this._fixedDt)this._fixedAccumulator=0;this._interpolationAlpha=this._fixedAccumulator/this._fixedDt,this._executePhase(this._phaseSystems.update,j,J),this._commandBuffer.playback(this),this._executePhase(this._phaseSystems.postUpdate,j,J),this._commandBuffer.playback(this);for(let Y of this._postUpdateHooks)Y(this,j);this._executePhase(this._phaseSystems.render,j,J),this._commandBuffer.playback(this),this._changeThreshold=this._entityManager.changeSeq,this._currentTick++}_executePhase(j,J,X){for(let Y of j){if(!Y.process)continue;if(Y.groups?.length){let F=!1;for(let U of Y.groups)if(this._disabledGroups.has(U)){F=!0;break}if(F)continue}if(Y.inScreens?.length){if(X===null||!Y.inScreens.includes(X))continue}if(Y.excludeScreens?.length){if(X!==null&&Y.excludeScreens.includes(X))continue}if(Y.requiredAssets?.length&&this._assetManager){let F=!0;for(let U of Y.requiredAssets)if(!this._assetManager.isLoaded(U)){F=!1;break}if(!F)continue}let Z=this._systemLastSeqs.get(Y)??0;this._changeThreshold=Z;let $={},G=!1,Q=!1;if(Y.entityQueries)for(let F in Y.entityQueries){Q=!0;let U=Y.entityQueries[F];if(U){if($[F]=this._entityManager.getEntitiesWithQuery(U.with,U.without||[],U.changed,U.changed?this._changeThreshold:void 0,U.parentHas),$[F].length)G=!0}}if(G)Y.process($,J,this);else if(!Q)Y.process(p,J,this);this._systemLastSeqs.set(Y,this._entityManager.changeSeq)}}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)}_rebuildPhaseSystems(){for(let j of k)this._phaseSystems[j]=[];for(let j of this._systems){let J=j.phase??"update";this._phaseSystems[J].push(j)}for(let j of k)this._phaseSystems[j].sort((J,X)=>{let Y=J.priority??0;return(X.priority??0)-Y})}updateSystemPriority(j,J){let X=this._systems.find((Y)=>Y.label===j);if(!X)return!1;return X.priority=J,this._rebuildPhaseSystems(),!0}updateSystemPhase(j,J){let X=this._systems.find((Y)=>Y.label===j);if(!X)return!1;return X.phase=J,this._rebuildPhaseSystems(),!0}get interpolationAlpha(){return this._interpolationAlpha}get fixedDt(){return this._fixedDt}disableSystemGroup(j){this._disabledGroups.add(j)}enableSystemGroup(j){this._disabledGroups.delete(j)}isSystemGroupEnabled(j){return!this._disabledGroups.has(j)}getSystemsInGroup(j){return this._systems.filter((J)=>J.groups?.includes(j)).map((J)=>J.label)}removeSystem(j){let J=this._systems.findIndex((Y)=>Y.label===j);if(J===-1)return!1;let X=this._systems[J];if(!X)return!1;if(X.onDetach)X.onDetach(this);return this._systems.splice(J,1),this._systemLastSeqs.delete(X),this._rebuildPhaseSystems(),!0}_registerSystem(j){if(this._systems.push(j),this._systemLastSeqs.set(j,this._changeThreshold),this._rebuildPhaseSystems(),!j.eventHandlers)return;for(let J in j.eventHandlers){let X=j.eventHandlers[J]?.handler;if(X)this._eventBus.subscribe(J,(Y)=>{X(Y,this)})}}hasResource(j){return this._resourceManager.has(j)}getResource(j){let J=this._resourceManager.get(j,this);if(!J)throw Error(`Resource '${String(j)}' not found. Available resources: [${this.getResourceKeys().map((X)=>String(X)).join(", ")}]`);return J}addResource(j,J){return this._resourceManager.add(j,J),this}removeResource(j){return this._resourceManager.remove(j)}async disposeResource(j){return this._resourceManager.disposeResource(j,this)}async disposeResources(){return this._resourceManager.disposeResources(this)}updateResource(j,J){let X=this.getResource(j),Y=J(X);return this._resourceManager.add(j,Y),this}getResourceKeys(){return this._resourceManager.getKeys()}resourceNeedsInitialization(j){return this._resourceManager.needsInitialization(j)}hasComponent(j,J){return this._entityManager.getComponent(j,J)!==null}spawn(j){let J=this._entityManager.createEntity();return this._entityManager.addComponents(J,j),J}getEntitiesWithQuery(j,J=[],X,Y){return this._entityManager.getEntitiesWithQuery(j,J,X,X?this._changeThreshold:void 0,Y)}getSingleton(j,J=[]){let X=this._entityManager.getEntitiesWithQuery(j,J);if(X.length===0)throw Error(`getSingleton: no entity matches query with=[${String(j)}] without=[${String(J)}]`);if(X.length>1)throw Error(`getSingleton: expected 1 entity but found ${X.length} matching query with=[${String(j)}] without=[${String(J)}]`);return X[0]}tryGetSingleton(j,J=[]){let X=this._entityManager.getEntitiesWithQuery(j,J);if(X.length===0)return;if(X.length>1)throw Error(`tryGetSingleton: expected 0 or 1 entity but found ${X.length} matching query with=[${String(j)}] without=[${String(J)}]`);return X[0]}removeEntity(j,J){return this._entityManager.removeEntity(j,J)}spawnChild(j,J){let X=this._entityManager.spawnChild(j,J);return this._emitHierarchyChanged(X.id,null,j),X}setParent(j,J){let X=this._entityManager.getParent(j);return this._entityManager.setParent(j,J),this._emitHierarchyChanged(j,X,J),this}removeParent(j){let J=this._entityManager.getParent(j),X=this._entityManager.removeParent(j);if(X)this._emitHierarchyChanged(j,J,null);return X}getParent(j){return this._entityManager.getParent(j)}getChildren(j){return this._entityManager.getChildren(j)}getChildAt(j,J){return this._entityManager.getChildAt(j,J)}getChildIndex(j,J){return this._entityManager.getChildIndex(j,J)}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,J){return this._entityManager.isDescendantOf(j,J)}isAncestorOf(j,J){return this._entityManager.isAncestorOf(j,J)}getRootEntities(){return this._entityManager.getRootEntities()}forEachInHierarchy(j,J){this._entityManager.forEachInHierarchy(j,J)}hierarchyIterator(j){return this._entityManager.hierarchyIterator(j)}_emitHierarchyChanged(j,J,X){this._eventBus.publish("hierarchyChanged",{entityId:j,oldParent:J,newParent:X})}get installedBundles(){return Array.from(this._installedBundles)}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}get commands(){return this._commandBuffer}get currentTick(){return this._currentTick}get changeThreshold(){return this._changeThreshold}markChanged(j,J){this._entityManager.markChanged(j,J)}onComponentAdded(j,J){return this._entityManager.onComponentAdded(j,J)}onComponentRemoved(j,J){return this._entityManager.onComponentRemoved(j,J)}addReactiveQuery(j,J){this._reactiveQueryManager.addQuery(j,J)}removeReactiveQuery(j){return this._reactiveQueryManager.removeQuery(j)}on(j,J){return this._eventBus.subscribe(j,J)}off(j,J){return this._eventBus.unsubscribe(j,J)}onPostUpdate(j){return this._postUpdateHooks.push(j),()=>{let J=this._postUpdateHooks.indexOf(j);if(J!==-1)this._postUpdateHooks.splice(J,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,J){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.setScreen(j,J)}async pushScreen(j,J){if(!this._screenManager)throw Error("Screen manager not configured. Use withScreens() in builder.");return this._screenManager.pushScreen(j,J)}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}_setFixedDt(j){this._fixedDt=j}_installBundle(j){if(this._installedBundles.has(j.id))return this;this._installedBundles.add(j.id),j.registerSystemsWithEcspresso(this);let J=j.getResources();for(let[X,Y]of J.entries())this._resourceManager.add(X,Y);if(this._assetManager){let X=j.getAssets();for(let[Y,Z]of X.entries())this._assetManager.register(Y,Z)}if(this._screenManager){let X=j.getScreens();for(let[Y,Z]of X.entries())this._screenManager.register(Y,Z)}return this}}class g{ecspresso;assetConfigurator=null;screenConfigurator=null;pendingResources=[];_fixedDt=null;constructor(){this.ecspresso=new K}withBundle(j){return this.ecspresso._installBundle(j),this}withResource(j,J){return this.pendingResources.push({key:j,value:J}),this}withAssets(j){let J=T();return j(J),this.assetConfigurator=J,this}withScreens(j){let J=q();return j(J),this.screenConfigurator=J,this}withFixedTimestep(j){return this._fixedDt=j,this}build(){for(let{key:j,value:J}of this.pendingResources)this.ecspresso.addResource(j,J);if(this.assetConfigurator)this.ecspresso._setAssetManager(this.assetConfigurator.getManager());if(this.screenConfigurator)this.ecspresso._setScreenManager(this.screenConfigurator.getManager());if(this._fixedDt!==null)this.ecspresso._setFixedDt(this._fixedDt);return this.ecspresso}}function m(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class B{_systems=[];_resources=new Map;_assets=new Map;_assetGroups=new Map;_screens=new Map;_id;constructor(j){this._id=j||m()}get id(){return this._id}set id(j){this._id=j}addSystem(j){if(typeof j==="string"){let J=b(j,this);return this._systems.push(J),J}else return this._systems.push(j),j}addResource(j,J){return this._resources.set(j,J),this}addAsset(j,J,X){return this._assets.set(j,{loader:J,eager:X?.eager??!0,group:X?.group}),this}addAssetGroup(j,J){let X=new Map;for(let[Y,Z]of Object.entries(J))X.set(Y,Z),this._assets.set(Y,{loader:Z,eager:!1,group:j});return this._assetGroups.set(j,X),this}addScreen(j,J){return this._screens.set(j,J),this}getAssets(){return new Map(this._assets)}getScreens(){return new Map(this._screens)}_setResource(j,J){this._resources.set(j,J)}_setAsset(j,J){this._assets.set(j,J)}_setScreen(j,J){this._screens.set(j,J)}getSystems(){return this._systems.map((j)=>j.build())}registerSystemsWithEcspresso(j){for(let J of this._systems)J.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 l(j,...J){if(J.length===0)return new B(j);let X=new B(j);for(let Y of J){for(let Z of Y.getSystemBuilders())X.addSystem(Z);for(let[Z,$]of Y.getResources().entries())X._setResource(Z,$);for(let[Z,$]of Y.getAssets().entries())X._setAsset(Z,$);for(let[Z,$]of Y.getScreens().entries())X._setScreen(Z,$)}return X}function Mj(j){return j}var kj=K;export{l as mergeBundles,kj as default,q as createScreenConfigurator,Mj as createQueryDefinition,T as createAssetConfigurator,w as SystemBuilder,R as ScreenManager,P as ResourceManager,z as HierarchyManager,H as EventBus,A as EntityManager,M as CommandBuffer,B as Bundle,E as AssetManager};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=D54EBCF6A31F22DB64756E2164756E21
|
|
4
4
|
//# sourceMappingURL=index.js.map
|