ecspresso 0.6.0 → 0.7.1
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 +187 -0
- package/dist/bundle.d.ts +2 -21
- package/dist/bundles/renderers/pixi.d.ts +13 -29
- package/dist/bundles/renderers/pixi.js +2 -2
- package/dist/bundles/renderers/pixi.js.map +6 -5
- package/dist/bundles/utils/bounds.d.ts +186 -0
- package/dist/bundles/utils/collision.d.ts +201 -0
- package/dist/bundles/utils/movement.d.ts +83 -0
- package/dist/bundles/utils/timers.d.ts +67 -11
- package/dist/bundles/utils/timers.js +2 -2
- package/dist/bundles/utils/timers.js.map +4 -4
- package/dist/bundles/utils/transform.d.ts +148 -0
- package/dist/command-buffer.d.ts +90 -0
- package/dist/ecspresso.d.ts +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +7 -6
- package/dist/type-utils.d.ts +9 -6
- package/package.json +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform Bundle for ECSpresso
|
|
3
|
+
*
|
|
4
|
+
* Provides hierarchical transform propagation following Bevy's Transform/GlobalTransform pattern.
|
|
5
|
+
* LocalTransform is modified by user code; WorldTransform is computed automatically.
|
|
6
|
+
*
|
|
7
|
+
* @see https://docs.rs/bevy/latest/bevy/transform/components/struct.GlobalTransform.html
|
|
8
|
+
*/
|
|
9
|
+
import Bundle from '../../bundle';
|
|
10
|
+
/**
|
|
11
|
+
* Local transform relative to parent (or world if no parent).
|
|
12
|
+
* This is the transform you modify directly.
|
|
13
|
+
*/
|
|
14
|
+
export interface LocalTransform {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
rotation: number;
|
|
18
|
+
scaleX: number;
|
|
19
|
+
scaleY: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Computed world transform (accumulated from parent chain).
|
|
23
|
+
* Read-only - managed by the transform propagation system.
|
|
24
|
+
*/
|
|
25
|
+
export interface WorldTransform {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
rotation: number;
|
|
29
|
+
scaleX: number;
|
|
30
|
+
scaleY: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Component types provided by the transform bundle.
|
|
34
|
+
* Extend your component types with this interface.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* interface GameComponents extends TransformComponentTypes {
|
|
39
|
+
* sprite: Sprite;
|
|
40
|
+
* velocity: { x: number; y: number };
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export interface TransformComponentTypes {
|
|
45
|
+
localTransform: LocalTransform;
|
|
46
|
+
worldTransform: WorldTransform;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Configuration options for the transform bundle.
|
|
50
|
+
*/
|
|
51
|
+
export interface TransformBundleOptions {
|
|
52
|
+
/** System group name (default: 'transform') */
|
|
53
|
+
systemGroup?: string;
|
|
54
|
+
/** Priority for transform propagation (default: 500, runs after physics/movement) */
|
|
55
|
+
priority?: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Default local transform values.
|
|
59
|
+
*/
|
|
60
|
+
export declare const DEFAULT_LOCAL_TRANSFORM: Readonly<LocalTransform>;
|
|
61
|
+
/**
|
|
62
|
+
* Default world transform values.
|
|
63
|
+
*/
|
|
64
|
+
export declare const DEFAULT_WORLD_TRANSFORM: Readonly<WorldTransform>;
|
|
65
|
+
/**
|
|
66
|
+
* Create a local transform component with position only.
|
|
67
|
+
* Uses default rotation (0) and scale (1, 1).
|
|
68
|
+
*
|
|
69
|
+
* @param x The x coordinate
|
|
70
|
+
* @param y The y coordinate
|
|
71
|
+
* @returns Component object suitable for spreading into spawn()
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* ecs.spawn({
|
|
76
|
+
* ...createLocalTransform(100, 200),
|
|
77
|
+
* sprite,
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare function createLocalTransform(x: number, y: number): Pick<TransformComponentTypes, 'localTransform'>;
|
|
82
|
+
/**
|
|
83
|
+
* Create a world transform component with position only.
|
|
84
|
+
* Typically used alongside createLocalTransform for initial state.
|
|
85
|
+
*
|
|
86
|
+
* @param x The x coordinate
|
|
87
|
+
* @param y The y coordinate
|
|
88
|
+
* @returns Component object suitable for spreading into spawn()
|
|
89
|
+
*/
|
|
90
|
+
export declare function createWorldTransform(x: number, y: number): Pick<TransformComponentTypes, 'worldTransform'>;
|
|
91
|
+
/**
|
|
92
|
+
* Options for creating a full transform.
|
|
93
|
+
*/
|
|
94
|
+
export interface TransformOptions {
|
|
95
|
+
rotation?: number;
|
|
96
|
+
scaleX?: number;
|
|
97
|
+
scaleY?: number;
|
|
98
|
+
/** Uniform scale (overrides scaleX/scaleY if provided) */
|
|
99
|
+
scale?: number;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create both local and world transform components.
|
|
103
|
+
* World transform is initialized to match local transform.
|
|
104
|
+
*
|
|
105
|
+
* @param x The x coordinate
|
|
106
|
+
* @param y The y coordinate
|
|
107
|
+
* @param options Optional rotation and scale
|
|
108
|
+
* @returns Component object suitable for spreading into spawn()
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* ecs.spawn({
|
|
113
|
+
* ...createTransform(100, 200),
|
|
114
|
+
* sprite,
|
|
115
|
+
* });
|
|
116
|
+
*
|
|
117
|
+
* // With rotation and scale
|
|
118
|
+
* ecs.spawn({
|
|
119
|
+
* ...createTransform(100, 200, { rotation: Math.PI / 4, scale: 2 }),
|
|
120
|
+
* sprite,
|
|
121
|
+
* });
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export declare function createTransform(x: number, y: number, options?: TransformOptions): TransformComponentTypes;
|
|
125
|
+
/**
|
|
126
|
+
* Create a transform bundle for ECSpresso.
|
|
127
|
+
*
|
|
128
|
+
* This bundle provides:
|
|
129
|
+
* - Transform propagation system that computes world transforms from local transforms
|
|
130
|
+
* - Parent-first traversal ensures parents are processed before children
|
|
131
|
+
* - Supports full transform hierarchy (position, rotation, scale)
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* const ecs = ECSpresso
|
|
136
|
+
* .create<Components, Events, Resources>()
|
|
137
|
+
* .withBundle(createTransformBundle())
|
|
138
|
+
* .withBundle(createMovementBundle())
|
|
139
|
+
* .build();
|
|
140
|
+
*
|
|
141
|
+
* // Spawn entity with transform
|
|
142
|
+
* ecs.spawn({
|
|
143
|
+
* ...createTransform(100, 200),
|
|
144
|
+
* velocity: { x: 50, y: 0 },
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export declare function createTransformBundle(options?: TransformBundleOptions): Bundle<TransformComponentTypes, {}, {}>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type ECSpresso from './ecspresso';
|
|
2
|
+
import type { RemoveEntityOptions } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* CommandBuffer queues structural changes to be executed later.
|
|
5
|
+
* This prevents ordering issues when modifying entities during system execution.
|
|
6
|
+
*
|
|
7
|
+
* Commands are executed in FIFO order when playback() is called.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // In a system
|
|
12
|
+
* ecs.commands.removeEntity(entityId);
|
|
13
|
+
* ecs.commands.spawn({ position: { x: 0, y: 0 } });
|
|
14
|
+
*
|
|
15
|
+
* // Later (automatically at end of update())
|
|
16
|
+
* ecs.commands.playback(ecs);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export default class CommandBuffer<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}> {
|
|
20
|
+
private commands;
|
|
21
|
+
/**
|
|
22
|
+
* Queue an entity removal command
|
|
23
|
+
* @param entityId The ID of the entity to remove
|
|
24
|
+
* @param options Optional removal options (cascade, etc.)
|
|
25
|
+
*/
|
|
26
|
+
removeEntity(entityId: number, options?: RemoveEntityOptions): void;
|
|
27
|
+
/**
|
|
28
|
+
* Queue a component addition command
|
|
29
|
+
* @param entityId The ID of the entity
|
|
30
|
+
* @param componentName The name of the component to add
|
|
31
|
+
* @param componentValue The component data
|
|
32
|
+
*/
|
|
33
|
+
addComponent<K extends keyof ComponentTypes>(entityId: number, componentName: K, componentValue: ComponentTypes[K]): void;
|
|
34
|
+
/**
|
|
35
|
+
* Queue a component removal command
|
|
36
|
+
* @param entityId The ID of the entity
|
|
37
|
+
* @param componentName The name of the component to remove
|
|
38
|
+
*/
|
|
39
|
+
removeComponent<K extends keyof ComponentTypes>(entityId: number, componentName: K): void;
|
|
40
|
+
/**
|
|
41
|
+
* Queue an entity spawn command
|
|
42
|
+
* @param components The initial components for the new entity
|
|
43
|
+
* @returns void (entity ID not available until playback)
|
|
44
|
+
*/
|
|
45
|
+
spawn<T extends {
|
|
46
|
+
[K in keyof ComponentTypes]?: ComponentTypes[K];
|
|
47
|
+
}>(components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): void;
|
|
48
|
+
/**
|
|
49
|
+
* Queue a child entity spawn command
|
|
50
|
+
* @param parentId The ID of the parent entity
|
|
51
|
+
* @param components The initial components for the new child entity
|
|
52
|
+
*/
|
|
53
|
+
spawnChild<T extends {
|
|
54
|
+
[K in keyof ComponentTypes]?: ComponentTypes[K];
|
|
55
|
+
}>(parentId: number, components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): void;
|
|
56
|
+
/**
|
|
57
|
+
* Queue multiple component additions
|
|
58
|
+
* @param entityId The ID of the entity
|
|
59
|
+
* @param components Object with component names as keys and component data as values
|
|
60
|
+
*/
|
|
61
|
+
addComponents<T extends {
|
|
62
|
+
[K in keyof ComponentTypes]?: ComponentTypes[K];
|
|
63
|
+
}>(entityId: number, components: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>): void;
|
|
64
|
+
/**
|
|
65
|
+
* Queue a parent assignment command
|
|
66
|
+
* @param childId The ID of the child entity
|
|
67
|
+
* @param parentId The ID of the parent entity
|
|
68
|
+
*/
|
|
69
|
+
setParent(childId: number, parentId: number): void;
|
|
70
|
+
/**
|
|
71
|
+
* Queue a parent removal command
|
|
72
|
+
* @param childId The ID of the child entity
|
|
73
|
+
*/
|
|
74
|
+
removeParent(childId: number): void;
|
|
75
|
+
/**
|
|
76
|
+
* Execute all queued commands in FIFO order.
|
|
77
|
+
* Errors from individual commands are caught and logged, but do not stop playback.
|
|
78
|
+
* @param ecs The ECSpresso instance to execute commands on
|
|
79
|
+
*/
|
|
80
|
+
playback<AssetTypes extends Record<string, any> = {}, ScreenStates extends Record<string, any> = {}>(ecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes, AssetTypes, ScreenStates>): void;
|
|
81
|
+
/**
|
|
82
|
+
* Clear all queued commands without executing them
|
|
83
|
+
*/
|
|
84
|
+
clear(): void;
|
|
85
|
+
/**
|
|
86
|
+
* Get the number of queued commands
|
|
87
|
+
* @returns The number of commands waiting to be executed
|
|
88
|
+
*/
|
|
89
|
+
get length(): number;
|
|
90
|
+
}
|
package/dist/ecspresso.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import EventBus from "./event-bus";
|
|
|
3
3
|
import AssetManager from "./asset-manager";
|
|
4
4
|
import ScreenManager from "./screen-manager";
|
|
5
5
|
import { type ReactiveQueryDefinition } from "./reactive-query-manager";
|
|
6
|
+
import CommandBuffer from "./command-buffer";
|
|
6
7
|
import type { System, FilteredEntity, Entity, RemoveEntityOptions, HierarchyEntry, HierarchyIteratorOptions } from "./types";
|
|
7
8
|
import type Bundle from "./bundle";
|
|
8
9
|
import type { BundlesAreCompatible } from "./type-utils";
|
|
@@ -31,6 +32,8 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
31
32
|
private _eventBus;
|
|
32
33
|
/** Access/modify registered resources*/
|
|
33
34
|
private _resourceManager;
|
|
35
|
+
/** Command buffer for deferred structural changes */
|
|
36
|
+
private _commandBuffer;
|
|
34
37
|
/** Registered systems that will be updated in order*/
|
|
35
38
|
private _systems;
|
|
36
39
|
/** Cached sorted systems for efficient updates */
|
|
@@ -342,6 +345,18 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
342
345
|
get installedBundles(): string[];
|
|
343
346
|
get entityManager(): EntityManager<ComponentTypes>;
|
|
344
347
|
get eventBus(): EventBus<EventTypes>;
|
|
348
|
+
/**
|
|
349
|
+
* Command buffer for queuing deferred structural changes.
|
|
350
|
+
* Commands are executed automatically at the end of each update() cycle.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* // In a system or event handler
|
|
355
|
+
* ecs.commands.removeEntity(entityId);
|
|
356
|
+
* ecs.commands.spawn({ position: { x: 0, y: 0 } });
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
get commands(): CommandBuffer<ComponentTypes, EventTypes, ResourceTypes>;
|
|
345
360
|
/**
|
|
346
361
|
* Register a callback when a specific component is added to any entity
|
|
347
362
|
* @param componentName The component key
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './screen-types';
|
|
|
7
7
|
export type { ReactiveQueryDefinition } from './reactive-query-manager';
|
|
8
8
|
export { default as EntityManager } from './entity-manager';
|
|
9
9
|
export { default as EventBus } from './event-bus';
|
|
10
|
+
export { default as CommandBuffer } from './command-buffer';
|
|
10
11
|
export { default as HierarchyManager } from './hierarchy-manager';
|
|
11
12
|
/**
|
|
12
13
|
* @internal ResourceManager is exported for testing purposes only.
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var h=Object.create;var{getPrototypeOf:k,defineProperty:T,getOwnPropertyNames:g}=Object;var I=Object.prototype.hasOwnProperty;var s=(j,J,X)=>{X=j!=null?h(k(j)):{};let Y=J||!j||!j.__esModule?T(X,"default",{value:j,enumerable:!0}):X;for(let Z of g(j))if(!I.call(Y,Z))T(Y,Z,{get:()=>j[Z],enumerable:!0});return Y};var y=((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 W{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 Q{nextId=1;entities=new Map;componentIndices=new Map;addedCallbacks=new Map;removedCallbacks=new Map;hierarchyManager=new W;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 G=this.componentIndices.get($)?.size??0,U=this.componentIndices.get(F)?.size??1/0;return G<U?$: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((G)=>(G in $.components))&&(!_||J.every((G)=>!(G 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 L{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 p(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 G of J(F))if(j.includes(G))_(G,[...$,F]);Z.delete(F),Y.add(F),X.push(F)}for(let F of j)_(F);return X}class z{resources=new Map;resourceFactories=new Map;resourceDependencies=new Map;resourceDisposers=new Map;initializedResourceKeys=new Set;add(j,J){if(p(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 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 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 K(j){return new q(j??new E)}class w{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 R(j){return new S(j??new w)}class M{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 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.6.0";var m={};class D{static VERSION=f;_entityManager;_eventBus;_resourceManager;_systems=[];_sortedSystems=[];_installedBundles=new Set;_disabledGroups=new Set;_assetManager=null;_screenManager=null;_reactiveQueryManager;_postUpdateHooks=[];constructor(){this._entityManager=new Q,this._eventBus=new L,this._resourceManager=new z,this._reactiveQueryManager=new M(this._entityManager),this._sortedSystems=[],this._setupReactiveQueryHooks()}_setupReactiveQueryHooks(){let j=0,J=new Set,X=()=>{for(let $ of J){let G=this._entityManager.getEntity($);if(G)this._reactiveQueryManager.recheckEntity(G)}J.clear()},Y=this._entityManager.addComponent.bind(this._entityManager);this._entityManager.addComponent=($,G,U)=>{let H=Y($,G,U),V=typeof $==="number"?$:$.id;if(j>0)J.add(V);else{let A=this._entityManager.getEntity(V);if(A)this._reactiveQueryManager.onComponentAdded(A,G)}return H};let Z=this._entityManager.addComponents.bind(this._entityManager);this._entityManager.addComponents=($,G)=>{j++;let U=Z($,G);if(j--,j===0)X();return U};let _=this._entityManager.removeComponent.bind(this._entityManager);this._entityManager.removeComponent=($,G)=>{let U=typeof $==="number"?$:$.id,H=this._entityManager.getEntity(U),V=_($,G);if(H)this._reactiveQueryManager.onComponentRemoved(H,G);return V};let F=this._entityManager.removeEntity.bind(this._entityManager);this._entityManager.removeEntity=($,G)=>{let U=typeof $==="number"?$:$.id;if(this._entityManager.getEntity(U)){if(G?.cascade??!0){let A=this._entityManager.getDescendants(U);for(let b of A)this._reactiveQueryManager.onEntityRemoved(b)}this._reactiveQueryManager.onEntityRemoved(U)}return F($,G)}}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(m,j,this)}for(let X of this._postUpdateHooks)X(this,j)}async initialize(){if(await this.initializeResources(),this._assetManager)this._assetManager.setEventBus(this._eventBus),await this._assetManager.loadEagerAssets(),this._resourceManager.add("$assets",this._assetManager.createResource());if(this._screenManager)this._screenManager.setDependencies(this._eventBus,this._assetManager,this),this._resourceManager.add("$screen",this._screenManager.createResource());for(let j of this._systems)await j.onInitialize?.(this)}async initializeResources(...j){await this._resourceManager.initializeResources(this,...j)}_sortSystems(){this._sortedSystems=[...this._systems].sort((j,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}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 D}withBundle(j){return this.ecspresso._installBundle(j),this}withResource(j,J){return this.pendingResources.push({key:j,value:J}),this}withAssets(j){let J=K();return j(J),this.assetConfigurator=J,this}withScreens(j){let J=R();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 c(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class P{_systems=[];_resources=new Map;_assets=new Map;_assetGroups=new Map;_screens=new Map;_id;constructor(j){this._id=j||c()}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 l(j,...J){if(J.length===0)return new P(j);let X=new P(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 Ej(j){return j}var bj=D;export{l as mergeBundles,bj as default,R as createScreenConfigurator,Ej as createQueryDefinition,K as createAssetConfigurator,B as SystemBuilder,w as ScreenManager,z as ResourceManager,W as HierarchyManager,L as EventBus,Q as EntityManager,P as Bundle,E as AssetManager};
|
|
1
|
+
var k=Object.create;var{getPrototypeOf:g,defineProperty:C,getOwnPropertyNames:I}=Object;var p=Object.prototype.hasOwnProperty;var y=(j,J,X)=>{X=j!=null?k(g(j)):{};let Y=J||!j||!j.__esModule?C(X,"default",{value:j,enumerable:!0}):X;for(let Z of I(j))if(!p.call(Y,Z))C(Y,Z,{get:()=>j[Z],enumerable:!0});return Y};var o=((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 L{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 u(j){return typeof j==="object"&&j!==null&&"factory"in j&&typeof j.factory==="function"}function q(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 z{resources=new Map;resourceFactories=new Map;resourceDependencies=new Map;resourceDisposers=new Map;initializedResourceKeys=new Set;add(j,J){if(u(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=q(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=q(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 S{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 S(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 v{manager;constructor(j){this.manager=j}add(j,J){return this.manager.register(j,J),this}getManager(){return this.manager}}function x(j){return new v(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 D{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();T(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)T(J,this._ecspresso);if(j)T(J,j);return this}}function T(j,J){J._registerSystem(j)}function O(j,J){return new B(j,J)}function f(j,J){return new B(j,null,J)}var N="0.7.1";var l={};class P{static VERSION=N;_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 L,this._resourceManager=new z,this._reactiveQueryManager=new K(this._entityManager),this._commandBuffer=new D,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 h of E)this._reactiveQueryManager.onEntityRemoved(h)}this._reactiveQueryManager.onEntityRemoved(G)}return F($,U)}}static create(){return new b}addSystem(j){return O(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(l,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 b{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=x();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 c(){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||c()}get id(){return this._id}set id(j){this._id=j}addSystem(j){if(typeof j==="string"){let J=f(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 s(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 Kj(j){return j}var Ij=P;export{s as mergeBundles,Ij as default,x as createScreenConfigurator,Kj as createQueryDefinition,R as createAssetConfigurator,B as SystemBuilder,M as ScreenManager,z as ResourceManager,Q as HierarchyManager,L as EventBus,V as EntityManager,D as CommandBuffer,A as Bundle,w as AssetManager};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=BB975495804CE50E64756E2164756E21
|
|
4
4
|
//# sourceMappingURL=index.js.map
|