ecspresso 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ecspresso.d.ts +3 -7
- package/dist/index.js +2 -2
- package/dist/index.js.map +4 -4
- package/package.json +5 -3
package/dist/ecspresso.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ type BundlesAreCompatible<C1 extends Record<string, any>, C2 extends Record<stri
|
|
|
21
21
|
* Interface declaration for ECSpresso constructor to ensure type augmentation works properly.
|
|
22
22
|
* This merges with the class declaration below.
|
|
23
23
|
*/
|
|
24
|
-
export default interface ECSpresso<ComponentTypes extends Record<string, any> =
|
|
24
|
+
export default interface ECSpresso<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}> {
|
|
25
25
|
/**
|
|
26
26
|
* Default constructor
|
|
27
27
|
*/
|
|
@@ -43,17 +43,13 @@ export default interface ECSpresso {
|
|
|
43
43
|
* .build();
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
|
-
create
|
|
47
|
-
/**
|
|
48
|
-
* Create a new ECSpresso builder with type-safe bundle installation and explicit starting types.
|
|
49
|
-
*/
|
|
50
|
-
create<BaseC extends Record<string, any>, BaseE extends Record<string, any>, BaseR extends Record<string, any>>(): ECSpressoBuilder<BaseC, BaseE, BaseR>;
|
|
46
|
+
create<BaseC extends Record<string, any> = {}, BaseE extends Record<string, any> = {}, BaseR extends Record<string, any> = {}>(): ECSpressoBuilder<BaseC, BaseE, BaseR>;
|
|
51
47
|
}
|
|
52
48
|
/**
|
|
53
49
|
* ECSpresso is the central ECS framework class that connects all features.
|
|
54
50
|
* It handles creation and management of entities, components, and systems, and provides lifecycle hooks.
|
|
55
51
|
*/
|
|
56
|
-
export default class ECSpresso<ComponentTypes extends Record<string, any> =
|
|
52
|
+
export default class ECSpresso<ComponentTypes extends Record<string, any> = {}, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}> {
|
|
57
53
|
/** Library version*/
|
|
58
54
|
static readonly VERSION: string;
|
|
59
55
|
/** Access/modify stored components and entities*/
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class J{nextId=1;entities=new Map;componentIndices=new Map;createEntity(){let j=this.nextId++,g={id:j,components:{}};return this.entities.set(j,g),g}addComponent(j,g,f){let D=typeof j==="number"?this.entities.get(j):j;if(!D)throw new Error(`Entity ${j} does not exist`);if(D.components[g]=f,!this.componentIndices.has(g))this.componentIndices.set(g,new Set);return this.componentIndices.get(g)?.add(D.id),this}addComponents(j,g){let f=typeof j==="number"?this.entities.get(j):j;if(!f)throw new Error(`Entity ${j} does not exist`);for(let D in g)this.addComponent(f,D,g[D]);return this}removeComponent(j,g){let f=this.entities.get(j);if(!f)throw new Error(`Entity ${j} does not exist`);delete f.components[g],this.componentIndices.get(g)?.delete(j)}getComponent(j,g){let f=this.entities.get(j);if(!f)throw new Error(`Entity ${j} does not exist`);return f.components[g]||null}getEntitiesWithComponents(j=[],g=[]){if(j.length===0){if(g.length===0)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((L)=>{return g.every((F)=>!(F in L.components))})}let f=j.reduce((L,F)=>{let H=this.componentIndices.get(F),x=H?H.size:0,G=this.componentIndices.get(L)?.size??1/0;return x<G?F:L},j[0]);return Array.from(this.componentIndices.get(f)||[]).filter((L)=>{let F=this.entities.get(L);return F&&j.every((H)=>(H in F.components))&&g.every((H)=>!(H in F.components))}).map((L)=>this.entities.get(L))}removeEntity(j){let g=typeof j==="number"?this.entities.get(j):j;if(!g)return!1;for(let f of Object.keys(g.components))this.componentIndices.get(f)?.delete(g.id);return this.entities.delete(g.id)}getEntity(j){return this.entities.get(j)}}class M{handlers=new Map;subscribe(j,g){return this.addHandler(j,g,!1)}once(j,g){return this.addHandler(j,g,!0)}addHandler(j,g,f){if(!this.handlers.has(j))this.handlers.set(j,[]);let D={callback:g,once:f};return this.handlers.get(j).push(D),()=>{let L=this.handlers.get(j);if(L){let F=L.indexOf(D);if(F!==-1)L.splice(F,1)}}}publish(j,g){let f=this.handlers.get(j);if(!f)return;let D=[...f],L=[];for(let F of D)if(F.callback(g),F.once)L.push(F);if(L.length>0)for(let F of L){let H=f.indexOf(F);if(H!==-1)f.splice(H,1)}}clear(){this.handlers.clear()}clearEvent(j){this.handlers.delete(j)}}class P{resources=new Map;add(j,g){return this.resources.set(j,g),this}get(j){let g=this.resources.get(j);if(g===void 0)throw new Error(`Resource ${String(j)} not found`);return g}getOptional(j){return this.resources.get(j)}has(j){return this.resources.has(j)}remove(j){return this.resources.delete(j)}getKeys(){return Array.from(this.resources.keys())}}class V{_label;_ecspresso;_bundle;queries={};processFunction;attachFunction;detachFunction;eventHandlers;constructor(j,g=null,f=null){this._label=j;this._ecspresso=g;this._bundle=f}get label(){return this._label}get bundle(){return this._bundle}get ecspresso(){return this._ecspresso}addQuery(j,g){let f=this;return f.queries={...this.queries,[j]:g},f}setProcess(j){return this.processFunction=j,this}setOnAttach(j){return this.attachFunction=j,this}setOnDetach(j){return this.detachFunction=j,this}setEventHandlers(j){return this.eventHandlers=j,this}build(j){let g={label:this._label,entityQueries:this.queries};if(this.processFunction)g.process=this.processFunction;if(this.attachFunction)g.onAttach=this.attachFunction;if(this.detachFunction)g.onDetach=this.detachFunction;if(this.eventHandlers)g.eventHandlers=this.eventHandlers;if(this._ecspresso)X(g,this._ecspresso);if(j)X(g,j);return this}}function X(j,g){if(g._systems.push(j),j.onAttach?.(g),!j.eventHandlers)return;for(let f in j.eventHandlers){let D=j.eventHandlers[f]?.handler;D&&g.eventBus.subscribe(f,(L)=>{D(L,g)})}}function Y(j,g){return new V(j,g)}function Z(j,g){return new V(j,null,g)}var _="0.1.4";class Q{static VERSION=_;_entityManager;_eventBus;_resourceManager;_systems=[];_installedBundles=new Set;constructor(){this._entityManager=new J,this._eventBus=new M,this._resourceManager=new P}static create(){return new $}addSystem(j){return Y(j,this)}update(j){for(let g of this._systems){if(!g.process)continue;let f={};if(g.entityQueries)for(let D in g.entityQueries){let L=g.entityQueries[D];if(L)f[D]=this._entityManager.getEntitiesWithComponents(L.with,L.without||[])}g.process(f,j,this)}}_installBundle(j){if(this._installedBundles.has(j.id))return this;this._installedBundles.add(j.id),j.registerSystemsWithEcspresso(this);let g=j.getResources();for(let[f,D]of g.entries())this._resourceManager.add(f,D);return this}removeSystem(j){let g=this._systems.findIndex((D)=>D.label===j);if(g===-1)return!1;let f=this._systems[g];if(!f)return!1;if(f.onDetach)f.onDetach(this);return this._systems.splice(g,1),!0}hasResource(j){return this._resourceManager.has(j)}getResource(j){let g=this._resourceManager.getOptional(j);if(!g)throw new Error(`Resource "${j.toString()}" not found`);return g}addResource(j,g){return this._resourceManager.add(j,g),this}hasComponent(j,g){return this._entityManager.getComponent(j,g)!==null}getEntitiesWithComponents(j,g=[]){return this._entityManager.getEntitiesWithComponents(j,g)}get installedBundles(){return Array.from(this._installedBundles)}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}get resourceManager(){return this._resourceManager}}class ${ecspresso;constructor(){this.ecspresso=new Q}withBundle(j){return this.ecspresso._installBundle(j),this}build(){return this.ecspresso}}function W(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class U{_systems=[];_resources=new Map;_id;constructor(j){this._id=j||W()}get id(){return this._id}set id(j){this._id=j}addSystem(j){let g=Z(j,this);return this._systems.push(g),g}addResource(j,g){return this._resources.set(j,g),this}getSystems(){return this._systems.map((j)=>j.build())}registerSystemsWithEcspresso(j){for(let g of this._systems)g.build(j)}getResources(){return new Map(this._resources)}getResource(j){return this._resources.get(j)}getSystemBuilders(){return[...this._systems]}hasResource(j){return this._resources.has(j)}}function A(j,...g){if(g.length===0)return new U(j);let f=new U(j);for(let D of g){for(let L of D.getSystemBuilders())f.addSystem(L);for(let[L,F]of D.getResources().entries())f.addResource(L,F)}return f}var o=Q;export{A as mergeBundles,o as default,V as SystemBuilder,P as ResourceManager,M as EventBus,J as EntityManager,U as Bundle};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=5B3F11C4615EDE1564756E2164756E21
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
"import type { Entity, FilteredEntity } from \"./types\";\n\nexport default\nclass EntityManager<ComponentTypes> {\n\tprivate nextId: number = 1;\n\tprivate entities: Map<number, Entity<ComponentTypes>> = new Map();\n\tprivate componentIndices: Map<keyof ComponentTypes, Set<number>> = new Map();\n\n\tcreateEntity(): Entity<ComponentTypes> {\n\t\tconst id = this.nextId++;\n\t\tconst entity: Entity<ComponentTypes> = { id, components: {} };\n\t\tthis.entities.set(id, entity);\n\t\treturn entity;\n\t}\n\n\t// TODO: Component object pooling if(/when) garbage collection is an issue...?\n\taddComponent<ComponentName extends keyof ComponentTypes>(\n\t\tentityOrId: number | Entity<ComponentTypes>,\n\t\tcomponentName: ComponentName,\n\t\tdata: ComponentTypes[ComponentName]\n\t) {\n\t\tconst entity = typeof entityOrId === 'number' ?\n\t\t\tthis.entities.get(entityOrId) :\n\t\t\tentityOrId;\n\n\t\tif (!entity) throw new Error(`Entity ${entityOrId} does not exist`);\n\n\t\tentity.components[componentName] = data;\n\n\t\t// Update component index\n\t\tif (!this.componentIndices.has(componentName)) {\n\t\t\tthis.componentIndices.set(componentName, new Set());\n\t\t}\n\t\tthis.componentIndices.get(componentName)?.add(entity.id);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add multiple components to an entity at once\n\t * @param entityOrId Entity or entity ID to add components to\n\t * @param components Object with component names as keys and component data as values\n\t */\n\taddComponents<\n\t\tT extends { [K in keyof ComponentTypes]?: ComponentTypes[K] }\n\t>(\n\t\tentityOrId: number | Entity<ComponentTypes>,\n\t\tcomponents: T & Record<Exclude<keyof T, keyof ComponentTypes>, never>\n\t) {\n\t\tconst entity = typeof entityOrId === 'number' ?\n\t\t\tthis.entities.get(entityOrId) :\n\t\t\tentityOrId;\n\n\t\tif (!entity) throw new Error(`Entity ${entityOrId} does not exist`);\n\n\t\tfor (const componentName in components) {\n\t\t\tthis.addComponent(\n\t\t\t\tentity,\n\t\t\t\tcomponentName as keyof ComponentTypes,\n\t\t\t\tcomponents[componentName as keyof T] as ComponentTypes[keyof ComponentTypes]\n\t\t\t);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tremoveComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName) {\n\t\tconst entity = this.entities.get(entityId);\n\t\tif (!entity) throw new Error(`Entity ${entityId} does not exist`);\n\n\t\tdelete entity.components[componentName];\n\n\t\t// Update component index\n\t\tthis.componentIndices.get(componentName)?.delete(entityId);\n\t}\n\n\tgetComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName): ComponentTypes[ComponentName] | null {\n\t\tconst entity = this.entities.get(entityId);\n\n\t\tif (!entity) throw new Error(`Entity ${entityId} does not exist`);\n\n\t\treturn entity.components[componentName] || null;\n\t}\n\n\tgetEntitiesWithComponents<\n\t\tWithComponents extends keyof ComponentTypes = never,\n\t\tWithoutComponents extends keyof ComponentTypes = never\n\t>(\n\t\trequired: ReadonlyArray<WithComponents> = [],\n\t\texcluded: ReadonlyArray<WithoutComponents> = [],\n\t): Array<FilteredEntity<ComponentTypes, WithComponents extends never ? never : WithComponents, WithoutComponents extends never ? never : WithoutComponents>> {\n\t\t// Use the smallest component set as base for better performance\n\t\tif (required.length === 0) {\n\t\t\tif (excluded.length === 0) {\n\t\t\t\treturn Array.from(this.entities.values()) as any;\n\t\t\t}\n\n\t\t\treturn Array\n\t\t\t\t.from(this.entities.values())\n\t\t\t\t.filter((entity) => {\n\t\t\t\t\treturn excluded.every(comp => !(comp in entity.components));\n\t\t\t\t}) as any;\n\t\t}\n\n\t\t// Find the component with the smallest entity set to start with\n\t\tconst smallestComponent = required.reduce((smallest, comp) => {\n\t\t\tconst set = this.componentIndices.get(comp);\n\t\t\tconst currentSize = set ? set.size : 0;\n\t\t\tconst smallestSize = this.componentIndices.get(smallest!)?.size ?? Infinity;\n\n\t\t\treturn currentSize < smallestSize ? comp : smallest;\n\t\t}, required[0])!;\n\n\t\t// Start with the entities from the smallest component set\n\t\tconst candidates = Array.from(this.componentIndices.get(smallestComponent) || []);\n\n\t\t// Return full entity objects, not just IDs\n\t\treturn candidates\n\t\t\t.filter(id => {\n\t\t\t\tconst entity = this.entities.get(id);\n\t\t\t\treturn (\n\t\t\t\t\tentity &&\n\t\t\t\t\trequired.every(comp => comp in entity.components) &&\n\t\t\t\t\texcluded.every(comp => !(comp in entity.components))\n\t\t\t\t);\n\t\t\t})\n\t\t\t.map(id => this.entities.get(id)!) as Array<FilteredEntity<ComponentTypes, WithComponents extends never ? never : WithComponents, WithoutComponents extends never ? never : WithoutComponents>>;\n\t}\n\n\tremoveEntity(entityOrId: number | Entity<ComponentTypes>): boolean {\n\t\tconst entity = typeof entityOrId === 'number' ?\n\t\t\tthis.entities.get(entityOrId) :\n\t\t\tentityOrId;\n\n\t\tif (!entity) return false;\n\n\t\t// Remove entity from all component indices\n\t\tfor (const componentName of Object.keys(entity.components) as Array<keyof ComponentTypes>) {\n\t\t\tthis.componentIndices.get(componentName)?.delete(entity.id);\n\t\t}\n\n\t\t// Remove the entity itself\n\t\treturn this.entities.delete(entity.id);\n\t}\n\n\tgetEntity(entityId: number): Entity<ComponentTypes> | undefined {\n\t\treturn this.entities.get(entityId);\n\t}\n}\n",
|
|
6
6
|
"import type { EventHandler } from \"./types\";\n\nexport default\nclass EventBus<EventTypes> {\n\tprivate handlers: Map<string, Array<EventHandler<any>>> = new Map();\n\n\t/**\n\t * Subscribe to an event\n\t */\n\tsubscribe<E extends keyof EventTypes>(\n\t\teventType: E,\n\t\tcallback: (data: EventTypes[E]) => void\n\t): () => void {\n\t\treturn this.addHandler(eventType, callback, false);\n\t}\n\n\t/**\n\t * Subscribe to an event once\n\t */\n\tonce<E extends keyof EventTypes>(\n\t\teventType: E,\n\t\tcallback: (data: EventTypes[E]) => void\n\t): () => void {\n\t\treturn this.addHandler(eventType, callback, true);\n\t}\n\n\t/**\n\t * Internal method to add an event handler\n\t */\n\tprivate addHandler<E extends keyof EventTypes>(\n\t\teventType: E,\n\t\tcallback: (data: EventTypes[E]) => void,\n\t\tonce: boolean\n\t): () => void {\n\t\tif (!this.handlers.has(eventType as string)) {\n\t\t\tthis.handlers.set(eventType as string, []);\n\t\t}\n\n\t\tconst handler: EventHandler<any> = {\n\t\t\tcallback,\n\t\t\tonce\n\t\t};\n\n\t\tthis.handlers.get(eventType as string)!.push(handler);\n\n\t\t// Return unsubscribe function\n\t\treturn () => {\n\t\t\tconst handlers = this.handlers.get(eventType as string);\n\t\t\tif (handlers) {\n\t\t\t\tconst index = handlers.indexOf(handler);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\thandlers.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tpublish<E extends keyof EventTypes>(\n\t\teventType: E,\n\t\tdata?: EventTypes[E]\n\t): void {\n\t\tconst handlers = this.handlers.get(eventType as string);\n\t\tif (!handlers) return;\n\n\t\t// Create a copy of handlers to avoid issues with handlers that modify the array\n\t\tconst handlersToCall = [...handlers];\n\n\t\t// Call all handlers and collect handlers to remove\n\t\tconst handlersToRemove: EventHandler<any>[] = [];\n\n\t\tfor (const handler of handlersToCall) {\n\t\t\thandler.callback(data as EventTypes[E]);\n\t\t\tif (handler.once) {\n\t\t\t\thandlersToRemove.push(handler);\n\t\t\t}\n\t\t}\n\n\t\tif (handlersToRemove.length > 0) {\n\t\t\tfor (const handler of handlersToRemove) {\n\t\t\t\tconst index = handlers.indexOf(handler);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\thandlers.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.handlers.clear();\n\t}\n\n\tclearEvent<E extends keyof EventTypes>(eventType: E): void {\n\t\tthis.handlers.delete(eventType as string);\n\t}\n}\n",
|
|
7
7
|
"export default\nclass ResourceManager<ResourceTypes extends Record<string, any> = Record<string, any>> {\n\tprivate resources: Map<string, any> = new Map();\n\n\t/**\n\t * Add a resource to the manager\n\t * @param label The resource key\n\t * @param resource The resource value\n\t * @returns The resource manager instance for chaining\n\t */\n\tadd<K extends keyof ResourceTypes | string>(label: K, resource: K extends keyof ResourceTypes ? ResourceTypes[K] : any) {\n\t\tthis.resources.set(label as string, resource);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get a resource from the manager\n\t * @param label The resource key\n\t * @returns The resource value\n\t * @throws Error if resource not found\n\t */\n\tget<K extends keyof ResourceTypes | string>(label: K): K extends keyof ResourceTypes ? ResourceTypes[K] : any {\n\t\tconst resource = this.resources.get(label as string);\n\n\t\tif (resource === undefined) {\n\t\t\tthrow new Error(`Resource ${String(label)} not found`);\n\t\t}\n\n\t\treturn resource as any;\n\t}\n\n\t/**\n\t * Get a resource from the manager, returning undefined if not found\n\t * @param label The resource key\n\t * @returns The resource value or undefined if not found\n\t */\n\tgetOptional<K extends keyof ResourceTypes | string>(label: K): K extends keyof ResourceTypes ? ResourceTypes[K] : any | undefined {\n\t\tconst resource = this.resources.get(label as string);\n\t\treturn resource as any | undefined;\n\t}\n\n\t/**\n\t * Check if a resource exists\n\t * @param label The resource key\n\t * @returns True if the resource exists\n\t */\n\thas<K extends keyof ResourceTypes | string>(label: K): boolean {\n\t\treturn this.resources.has(label as string);\n\t}\n\n\t/**\n\t * Remove a resource\n\t * @param label The resource key\n\t * @returns True if the resource was removed\n\t */\n\tremove<K extends keyof ResourceTypes | string>(label: K): boolean {\n\t\treturn this.resources.delete(label as string);\n\t}\n\n\t/**\n\t * Get all resource keys\n\t * @returns Array of resource keys\n\t */\n\tgetKeys(): Array<string> {\n\t\treturn Array.from(this.resources.keys());\n\t}\n}\n",
|
|
8
|
-
"import Bundle from \"./bundle\";\nimport ECSpresso from \"./ecspresso\";\nimport type { FilteredEntity, System } from \"./types\";\n\n/**\n * Builder class for creating type-safe ECS Systems with proper query inference\n */\nexport class SystemBuilder<\n\tComponentTypes extends Record<string, any> = Record<string, any>,\n\tEventTypes extends Record<string, any> = Record<string, any>,\n\tResourceTypes extends Record<string, any> = Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>> = {},\n> {\n\tprivate queries: Queries = {} as Queries;\n\tprivate processFunction?: ProcessFunction<ComponentTypes, EventTypes, ResourceTypes, Queries>;\n\tprivate attachFunction?: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>;\n\tprivate detachFunction?: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>;\n\tprivate eventHandlers?: {\n\t\t[EventName in keyof EventTypes]?: {\n\t\t\thandler(\n\t\t\t\tdata: EventTypes[EventName],\n\t\t\t\tecs: ECSpresso<\n\t\t\t\t\tComponentTypes & Record<string, any>,\n\t\t\t\t\tEventTypes,\n\t\t\t\t\tResourceTypes\n\t\t\t\t>,\n\t\t\t): void;\n\t\t};\n\t};\n\n\tconstructor(\n\t\tprivate _label: string,\n\t\tprivate _ecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes> | null = null,\n\t\tprivate _bundle: Bundle<ComponentTypes, EventTypes, ResourceTypes> | null = null,\n\t) {}\n\n\tget label() {\n\t\treturn this._label;\n\t}\n\n\t/**\n\t * Returns the associated bundle if one was provided in the constructor\n\t */\n\tget bundle() {\n\t\treturn this._bundle;\n\t}\n\n\t/**\n\t * Returns the associated ECSpresso instance if one was provided in the constructor\n\t */\n\tget ecspresso() {\n\t\treturn this._ecspresso;\n\t}\n\n\t/**\n\t * Add a query definition to the system\n\t */\n\taddQuery<\n\t\tQueryName extends string,\n\t\tWithComponents extends keyof ComponentTypes,\n\t\tWithoutComponents extends keyof ComponentTypes = never,\n\t\tNewQueries extends Queries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents>> =\n\t\t\tQueries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents>>\n\t>(\n\t\tname: QueryName,\n\t\tdefinition: {\n\t\t\twith: ReadonlyArray<WithComponents>;\n\t\t\twithout?: ReadonlyArray<WithoutComponents>;\n\t\t}\n\t): this extends SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes, Queries>\n\t\t? SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes, NewQueries>\n\t\t: this extends SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes, Queries>\n\t\t\t? SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes, NewQueries>\n\t\t\t: SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, NewQueries> {\n\t\t// Cast is needed because TypeScript can't preserve the type information\n\t\t// when modifying an object property\n\t\tconst newBuilder = this as any;\n\t\tnewBuilder.queries = {\n\t\t\t...this.queries,\n\t\t\t[name]: definition,\n\t\t};\n\t\treturn newBuilder;\n\t}\n\n\t/**\n\t * Set the system's process function that runs each update\n\t * @param process Function to process entities matching the system's queries each update\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetProcess(\n\t\tprocess: ProcessFunction<ComponentTypes, EventTypes, ResourceTypes, Queries>\n\t): this {\n\t\tthis.processFunction = process;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the onAttach lifecycle hook\n\t * Called when the system is attached to the ECS\n\t * @param onAttach Function to run when this system is attached to the ECS\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetOnAttach(\n\t\tonAttach: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>\n\t): this {\n\t\tthis.attachFunction = onAttach;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the onDetach lifecycle hook\n\t * Called when the system is removed from the ECS\n\t * @param onDetach Function to run when this system is detached from the ECS\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetOnDetach(\n\t\tonDetach: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>\n\t): this {\n\t\tthis.detachFunction = onDetach;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set event handlers for the system\n\t * These handlers will be automatically subscribed when the system is attached\n\t * @param handlers Object mapping event names to handler functions\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetEventHandlers(\n\t\thandlers: {\n\t\t\t[EventName in keyof EventTypes]?: {\n\t\t\t\thandler(\n\t\t\t\t\tdata: EventTypes[EventName],\n\t\t\t\t\tecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>\n\t\t\t\t): void;\n\t\t\t};\n\t\t}\n\t): this {\n\t\tthis.eventHandlers = handlers;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Build the final system object\n\t */\n\tbuild(ecspresso?: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) {\n\t\tconst system: System<ComponentTypes, any, any, EventTypes, ResourceTypes> = {\n\t\t\tlabel: this._label,\n\t\t\tentityQueries: this.queries,\n\t\t};\n\n\t\tif (this.processFunction) {\n\t\t\tsystem.process = this.processFunction;\n\t\t}\n\n\t\tif (this.attachFunction) {\n\t\t\tsystem.onAttach = this.attachFunction;\n\t\t}\n\n\t\tif (this.detachFunction) {\n\t\t\tsystem.onDetach = this.detachFunction;\n\t\t}\n\n\t\tif (this.eventHandlers) {\n\t\t\tsystem.eventHandlers = this.eventHandlers;\n\t\t}\n\n\t\tif (this._ecspresso) {\n\t\t\tregisterSystemWithEcspresso(system, this._ecspresso);\n\t\t}\n\n\t\tif(ecspresso) {\n\t\t\tregisterSystemWithEcspresso(system, ecspresso);\n\t\t}\n\n\t\treturn this;\n\t}\n}\n\n/**\n * Helper function to register a system with an ECSpresso instance\n * This handles attaching the system and setting up event handlers\n * @internal Used by SystemBuilder and Bundle\n */\nexport function registerSystemWithEcspresso<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>\n>(\n\tsystem: System<ComponentTypes, any, any, EventTypes, ResourceTypes>,\n\tecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>\n) {\n\t// Add system to ECSpresso's system list\n\tecspresso[\"_systems\"].push(system);\n\n\tsystem.onAttach?.(ecspresso);\n\n\tif(!system.eventHandlers) return;\n\n\tfor (const eventName in system.eventHandlers) {\n\t\tconst handler = system.eventHandlers[eventName]?.handler;\n\n\t\thandler && ecspresso.eventBus.subscribe(eventName, (data: any) => {\n\t\t\thandler(data, ecspresso);\n\t\t});\n\t}\n}\n\n// Helper type definitions\ntype QueryDefinition<\n\tComponentTypes,\n\tWithComponents extends keyof ComponentTypes = any,\n\tWithoutComponents extends keyof ComponentTypes = any,\n> = {\n\twith: ReadonlyArray<WithComponents>;\n\twithout?: ReadonlyArray<WithoutComponents>;\n};\n\ntype QueryResults<\n\tComponentTypes,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>>,\n> = {\n\t[QueryName in keyof Queries]: QueryName extends string\n\t\t? FilteredEntity<\n\t\t\tComponentTypes,\n\t\t\tQueries[QueryName] extends QueryDefinition<ComponentTypes, infer W, any> ? W : never,\n\t\t\tQueries[QueryName] extends QueryDefinition<ComponentTypes, any, infer WO> ? WO : never\n\t\t>[]\n\t\t: never;\n};\n\n/**\n * Function signature for system process methods\n * @param queries Results of entity queries defined by the system\n * @param deltaTime Time elapsed since last update in seconds\n * @param ecs The ECSpresso instance providing access to all ECS functionality\n */\ntype ProcessFunction<\n\tComponentTypes,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>>,\n> = (\n\tqueries: QueryResults<ComponentTypes, Queries>,\n\tdeltaTime: number,\n\tecs: ECSpresso<\n\t\tComponentTypes & Record<string, any>,\n\t\tEventTypes,\n\t\tResourceTypes\n\t>\n) => void;\n\n/**\n * Function signature for system lifecycle hooks (onAttach and onDetach)\n * @param ecs The ECSpresso instance providing access to all ECS functionality\n */\ntype LifecycleFunction<\n\tComponentTypes,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n> = (\n\tecs: ECSpresso<\n\t\tComponentTypes & Record<string, any>,\n\t\tEventTypes,\n\t\tResourceTypes\n\t>,\n) => void;\n\n/**\n * Create a SystemBuilder attached to an ECSpresso instance\n * Helper function used by ECSpresso.addSystem\n */\nexport function createEcspressoSystemBuilder<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>\n>(\n\tlabel: string,\n\tecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>\n): SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes> {\n\treturn new SystemBuilder<ComponentTypes, EventTypes, ResourceTypes>(\n\t\tlabel,\n\t\tecspresso\n\t) as SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes>;\n}\n\n/**\n * Create a SystemBuilder attached to a Bundle\n * Helper function used by Bundle.addSystem\n */\nexport function createBundleSystemBuilder<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>\n>(\n\tlabel: string,\n\tbundle: Bundle<ComponentTypes, EventTypes, ResourceTypes>\n): SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes> {\n\treturn new SystemBuilder<ComponentTypes, EventTypes, ResourceTypes>(\n\t\tlabel,\n\t\tnull,\n\t\tbundle\n\t) as SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes>;\n}\n\n// Type interfaces for specialized SystemBuilders\n\n/**\n * SystemBuilder with a guaranteed non-null reference to an ECSpresso instance\n */\nexport interface SystemBuilderWithEcspresso<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>> = {}\n> extends SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries> {\n\treadonly ecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>;\n}\n\n/**\n * SystemBuilder with a guaranteed non-null reference to a Bundle\n */\nexport interface SystemBuilderWithBundle<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>> = {}\n> extends SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries> {\n\treadonly bundle: Bundle<ComponentTypes, EventTypes, ResourceTypes>;\n}\n",
|
|
9
|
-
"import EntityManager from \"./entity-manager\";\nimport EventBus from \"./event-bus\";\nimport ResourceManager from \"./resource-manager\";\nimport type { System, FilteredEntity } from \"./types\";\nimport type Bundle from \"./bundle\";\nimport { createEcspressoSystemBuilder } from \"./system-builder\";\nimport { version } from \"../package.json\";\n\n/**\n\t* Type helper to detect conflicting types between two record types.\n\t* Returns a union of keys that exist in both T and U but have incompatible types.\n*/\ntype GetConflictingKeys<T, U> = {\n\t[K in keyof T & keyof U]: T[K] extends U[K]\n\t\t? U[K] extends T[K]\n\t\t\t? never\n\t\t\t: K\n\t\t: K\n}[keyof T & keyof U];\n\n/**\n\t* Simplified type helper to check bundle type compatibility.\n\t* Returns true if bundles can be merged without type conflicts.\n*/\ntype BundlesAreCompatible<\n\tC1 extends Record<string, any>,\n\tC2 extends Record<string, any>,\n\tE1 extends Record<string, any>,\n\tE2 extends Record<string, any>,\n\tR1 extends Record<string, any>,\n\tR2 extends Record<string, any>\n> =\n\t// If all base types are empty, any bundle is compatible\n\t[keyof C1] extends [never]\n\t\t? [keyof E1] extends [never]\n\t\t\t? [keyof R1] extends [never]\n\t\t\t\t? true\n\t\t\t\t: GetConflictingKeys<R1, R2> extends never ? true : false\n\t\t\t: GetConflictingKeys<E1, E2> extends never\n\t\t\t\t? GetConflictingKeys<R1, R2> extends never ? true : false\n\t\t\t\t: false\n\t\t: GetConflictingKeys<C1, C2> extends never\n\t\t\t? GetConflictingKeys<E1, E2> extends never\n\t\t\t\t? GetConflictingKeys<R1, R2> extends never\n\t\t\t\t\t? true\n\t\t\t\t\t: false\n\t\t\t\t: false\n\t\t\t: false;\n\n/**\n\t* Interface declaration for ECSpresso constructor to ensure type augmentation works properly.\n\t* This merges with the class declaration below.\n*/\nexport default interface ECSpresso<\n\tComponentTypes extends Record<string, any> = Record<string, any>,\n\tEventTypes extends Record<string, any> = Record<string, any>,\n\tResourceTypes extends Record<string, any> = Record<string, any>,\n> {\n\t/**\n\t\t* Default constructor\n\t*/\n\tnew(): ECSpresso<ComponentTypes, EventTypes, ResourceTypes>;\n}\n\n/**\n\t* Static methods on the ECSpresso class\n*/\nexport default interface ECSpresso {\n\t\t/**\n\t\t\t* Create a new ECSpresso builder with type-safe bundle installation.\n\t\t\t* This is the preferred way to create an ECSpresso instance with bundles.\n\t\t *\n\t\t\t* Example:\n\t\t\t* ```typescript\n\t\t\t* const ecs = ECSpresso.create<MyComponents, MyEvents, MyResources>()\n\t\t *\t .withBundle(bundle1)\n\t\t *\t .withBundle(bundle2)\n\t\t *\t .build();\n\t\t\t* ```\n\t\t*/\n\t\tcreate(): ECSpressoBuilder<{}, {}, {}>; // No type parameters - returns a builder with empty types\n\n\t\t/**\n\t\t\t* Create a new ECSpresso builder with type-safe bundle installation and explicit starting types.\n\t\t*/\n\t\tcreate<\n\t\t\t\tBaseC extends Record<string, any>,\n\t\t\t\tBaseE extends Record<string, any>,\n\t\t\t\tBaseR extends Record<string, any>\n\t\t>(): ECSpressoBuilder<BaseC, BaseE, BaseR>;\n}\n\n/**\n\t* ECSpresso is the central ECS framework class that connects all features.\n\t* It handles creation and management of entities, components, and systems, and provides lifecycle hooks.\n*/\nexport default class ECSpresso<\n\tComponentTypes extends Record<string, any> = Record<string, any>,\n\tEventTypes extends Record<string, any> = Record<string, any>,\n\tResourceTypes extends Record<string, any> = Record<string, any>,\n> {\n\t/** Library version*/\n\tpublic static readonly VERSION = version;\n\n\t/** Access/modify stored components and entities*/\n\tprivate _entityManager: EntityManager<ComponentTypes>;\n\t/** Publish/subscribe to events*/\n\tprivate _eventBus: EventBus<EventTypes>;\n\t/** Access/modify registered resources*/\n\tprivate _resourceManager: ResourceManager<ResourceTypes>;\n\n\t/** Registered systems that will be updated in order*/\n\tprivate _systems: Array<System<ComponentTypes, any, any, EventTypes, ResourceTypes>> = [];\n\t/** Track installed bundles to prevent duplicates*/\n\tprivate _installedBundles: Set<string> = new Set();\n\n\t/**\n\t\t* Creates a new ECSpresso instance.\n\t*/\n\tconstructor() {\n\t\tthis._entityManager = new EntityManager<ComponentTypes>();\n\t\tthis._eventBus = new EventBus<EventTypes>();\n\t\tthis._resourceManager = new ResourceManager<ResourceTypes>();\n\t}\n\n\t/**\n\t\t* Creates a new ECSpresso builder for type-safe bundle installation.\n\t\t* This is the preferred way to create an ECSpresso instance with bundles.\n\t *\n\t\t* @returns A builder instance for fluent method chaining\n\t *\n\t\t* @example\n\t\t* ```typescript\n\t\t* const ecs = ECSpresso.create<BaseComponents, BaseEvents, BaseResources>()\n\t *\t .withBundle(bundle1)\n\t *\t .withBundle(bundle2)\n\t *\t .build();\n\t\t* ```\n\t*/\n\tstatic create<\n\t\tC extends Record<string, any> = {},\n\t\tE extends Record<string, any> = {},\n\t\tR extends Record<string, any> = {}\n\t>(): ECSpressoBuilder<C, E, R> {\n\t\treturn new ECSpressoBuilder<C, E, R>();\n\t}\n\n\t/**\n\t\t* Adds a system directly to this ECSpresso instance\n\t\t* @param label Unique name to identify the system\n\t\t* @returns A SystemBuilder instance for method chaining\n\t*/\n\taddSystem(label: string) {\n\t\treturn createEcspressoSystemBuilder<\n\t\t\tComponentTypes,\n\t\t\tEventTypes,\n\t\t\tResourceTypes\n\t\t>(label, this);\n\t}\n\n\t/**\n\t\t* Update all systems, passing deltaTime and query results to each system's process function\n\t\t* @param deltaTime Time elapsed since the last update (in seconds)\n\t*/\n\tupdate(deltaTime: number) {\n\t\tfor (const system of this._systems) {\n\t\t\tif (!system.process) continue;\n\n\t\t\t// Prepare query results for each defined query in the system\n\t\t\tconst queryResults: Record<string, any> = {};\n\n\t\t\tif (system.entityQueries) {\n\t\t\t\tfor (const queryName in system.entityQueries) {\n\t\t\t\t\tconst query = system.entityQueries[queryName];\n\t\t\t\t\tif (query) {\n\t\t\t\t\t\tqueryResults[queryName] = this._entityManager.getEntitiesWithComponents(\n\t\t\t\t\t\t\tquery.with,\n\t\t\t\t\t\t\tquery.without || []\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Call the system's process function\n\t\t\tsystem.process(queryResults, deltaTime, this);\n\t\t}\n\t}\n\n\t/**\n\t\t* Internal method to install a bundle into this ECSpresso instance.\n\t\t* Called by the ECSpressoBuilder during the build process.\n\t\t* The type safety is guaranteed by the builder's type system.\n\t*/\n\t_installBundle<\n\t\tC extends Record<string, any>,\n\t\tE extends Record<string, any>,\n\t\tR extends Record<string, any>\n\t>(bundle: Bundle<C, E, R>): this {\n\t\t// Prevent duplicate installation of the same bundle\n\t\tif (this._installedBundles.has(bundle.id)) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Mark this bundle as installed\n\t\tthis._installedBundles.add(bundle.id);\n\n\t\t// Register systems from the bundle\n\t\t// Type casting is necessary because the generic parameters don't match\n\t\tbundle.registerSystemsWithEcspresso(this as any);\n\n\t\t// Register resources from the bundle\n\t\tconst resources = bundle.getResources();\n\t\tfor (const [key, value] of resources.entries()) {\n\t\t\t// Type compatibility is guaranteed by the builder's type system\n\t\t\tthis._resourceManager.add(key as unknown as keyof ResourceTypes, value as any);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t\t* Remove a system by its label\n\t\t* Calls the system's onDetach method with this ECSpresso instance if defined\n\t\t* @param label The unique label of the system to remove\n\t\t* @returns true if the system was found and removed, false otherwise\n\t*/\n\tremoveSystem(label: string): boolean {\n\t\tconst index = this._systems.findIndex(system => system.label === label);\n\t\tif (index === -1) return false;\n\n\t\tconst system = this._systems[index];\n\t\t// This should never happen since we just found the system by index\n\t\tif (!system) return false;\n\n\t\t// Call the onDetach lifecycle hook if defined\n\t\tif (system.onDetach) {\n\t\t\tsystem.onDetach(this);\n\t\t}\n\n\t\t// Remove system\n\t\tthis._systems.splice(index, 1);\n\t\treturn true;\n\t}\n\n\t/**\n\t\t* Check if a resource exists\n\t*/\n\thasResource<K extends keyof ResourceTypes>(key: K): boolean {\n\t\treturn this._resourceManager.has(key);\n\t}\n\n\t/**\n\t\t* Get a resource if it exists, or undefined if not\n\t*/\n\tgetResource<K extends keyof ResourceTypes>(key: K): ResourceTypes[K] {\n\t\tconst resource = this._resourceManager.getOptional(key);\n\n\t\tif (!resource) throw new Error(`Resource \"${key.toString()}\" not found`);\n\n\t\treturn resource;\n\t}\n\n\t/**\n\t\t* Add a resource to the ECS instance\n\t*/\n\taddResource<K extends keyof ResourceTypes>(key: K, resource: ResourceTypes[K]): this {\n\t\tthis._resourceManager.add(key, resource);\n\t\treturn this;\n\t}\n\n\t/**\n\t\t* Check if an entity has a component\n\t*/\n\thasComponent<K extends keyof ComponentTypes>(\n\t\tentityId: number,\n\t\tcomponentName: K\n\t): boolean {\n\t\tconst component = this._entityManager.getComponent(entityId, componentName);\n\t\treturn component !== null;\n\t}\n\n\t/**\n\t\t* Get all entities with specific components\n\t*/\n\tgetEntitiesWithComponents<\n\t\tWithComponents extends keyof ComponentTypes,\n\t\tWithoutComponents extends keyof ComponentTypes = never\n\t>(\n\t\twithComponents: ReadonlyArray<WithComponents>,\n\t\twithoutComponents: ReadonlyArray<WithoutComponents> = []\n\t): Array<FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>> {\n\t\treturn this._entityManager.getEntitiesWithComponents(\n\t\t\twithComponents,\n\t\t\twithoutComponents\n\t\t);\n\t}\n\n\t/**\n\t\t* Get all installed bundle IDs\n\t*/\n\tget installedBundles(): string[] {\n\t\treturn Array.from(this._installedBundles);\n\t}\n\n\t// Getters for the internal managers\n\tget entityManager() {\n\t\treturn this._entityManager;\n\t}\n\n\tget eventBus() {\n\t\treturn this._eventBus;\n\t}\n\n\tget resourceManager() {\n\t\treturn this._resourceManager;\n\t}\n}\n\n/**\n\t* Builder class for ECSpresso that provides fluent type-safe bundle installation.\n\t* Handles type checking during build process to ensure type safety.\n*/\nexport class ECSpressoBuilder<\n\tC extends Record<string, any> = {},\n\tE extends Record<string, any> = {},\n\tR extends Record<string, any> = {}\n> {\n\t/** The ECSpresso instance being built*/\n\tprivate ecspresso: ECSpresso<C, E, R>;\n\n\tconstructor() {\n\t\tthis.ecspresso = new ECSpresso<C, E, R>();\n\t}\n\n\t/**\n\t\t* Add the first bundle when starting with empty types.\n\t\t* This overload allows any bundle to be added to an empty ECSpresso instance.\n\t*/\n\twithBundle<\n\t\tBC extends Record<string, any>,\n\t\tBE extends Record<string, any>,\n\t\tBR extends Record<string, any>\n\t>(\n\t\tthis: ECSpressoBuilder<{}, {}, {}>,\n\t\tbundle: Bundle<BC, BE, BR>\n\t): ECSpressoBuilder<BC, BE, BR>;\n\n\t/**\n\t\t* Add a subsequent bundle with type checking.\n\t\t* This overload enforces bundle type compatibility.\n\t*/\n\twithBundle<\n\t\tBC extends Record<string, any>,\n\t\tBE extends Record<string, any>,\n\t\tBR extends Record<string, any>\n\t>(\n\t\tbundle: BundlesAreCompatible<C, BC, E, BE, R, BR> extends true\n\t\t\t? Bundle<BC, BE, BR>\n\t\t\t: never\n\t): ECSpressoBuilder<C & BC, E & BE, R & BR>;\n\n\t/**\n\t\t* Implementation of both overloads.\n\t\t* Since the type compatibility is checked in the method signature,\n\t\t* we can safely assume the bundle is compatible here.\n\t*/\n\twithBundle<\n\t\tBC extends Record<string, any>,\n\t\tBE extends Record<string, any>,\n\t\tBR extends Record<string, any>\n\t>(\n\t\tbundle: Bundle<BC, BE, BR>\n\t): ECSpressoBuilder<C & BC, E & BE, R & BR> {\n\t\t// Install the bundle\n\t\t// Type compatibility is guaranteed by method overloads\n\t\tthis.ecspresso._installBundle(bundle as any);\n\n\t\t// Return a builder with the updated type parameters\n\t\treturn this as unknown as ECSpressoBuilder<C & BC, E & BE, R & BR>;\n\t}\n\n\t/**\n\t\t* Complete the build process and return the built ECSpresso instance\n\t*/\n\tbuild(): ECSpresso<C, E, R> {\n\t\treturn this.ecspresso;\n\t}\n}\n",
|
|
8
|
+
"import Bundle from \"./bundle\";\nimport ECSpresso from \"./ecspresso\";\nimport type { FilteredEntity, System } from \"./types\";\n\n/**\n * Builder class for creating type-safe ECS Systems with proper query inference\n */\nexport class SystemBuilder<\n\tComponentTypes extends Record<string, any> = Record<string, any>,\n\tEventTypes extends Record<string, any> = Record<string, any>,\n\tResourceTypes extends Record<string, any> = Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>> = {},\n> {\n\tprivate queries: Queries = {} as Queries;\n\tprivate processFunction?: ProcessFunction<ComponentTypes, EventTypes, ResourceTypes, Queries>;\n\tprivate attachFunction?: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>;\n\tprivate detachFunction?: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>;\n\tprivate eventHandlers?: {\n\t\t[EventName in keyof EventTypes]?: {\n\t\t\thandler(\n\t\t\t\tdata: EventTypes[EventName],\n\t\t\t\tecs: ECSpresso<\n\t\t\t\t\tComponentTypes & Record<string, any>,\n\t\t\t\t\tEventTypes,\n\t\t\t\t\tResourceTypes\n\t\t\t\t>,\n\t\t\t): void;\n\t\t};\n\t};\n\n\tconstructor(\n\t\tprivate _label: string,\n\t\tprivate _ecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes> | null = null,\n\t\tprivate _bundle: Bundle<ComponentTypes, EventTypes, ResourceTypes> | null = null,\n\t) {}\n\n\tget label() {\n\t\treturn this._label;\n\t}\n\n\t/**\n\t * Returns the associated bundle if one was provided in the constructor\n\t */\n\tget bundle() {\n\t\treturn this._bundle;\n\t}\n\n\t/**\n\t * Returns the associated ECSpresso instance if one was provided in the constructor\n\t */\n\tget ecspresso() {\n\t\treturn this._ecspresso;\n\t}\n\n\t/**\n\t * Add a query definition to the system\n\t */\n\taddQuery<\n\t\tQueryName extends string,\n\t\tWithComponents extends keyof ComponentTypes,\n\t\tWithoutComponents extends keyof ComponentTypes = never,\n\t\tNewQueries extends Queries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents>> =\n\t\t\tQueries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents>>\n\t>(\n\t\tname: QueryName,\n\t\tdefinition: {\n\t\t\twith: ReadonlyArray<WithComponents>;\n\t\t\twithout?: ReadonlyArray<WithoutComponents>;\n\t\t}\n\t): this extends SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes, Queries>\n\t\t? SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes, NewQueries>\n\t\t: this extends SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes, Queries>\n\t\t\t? SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes, NewQueries>\n\t\t\t: SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, NewQueries> {\n\t\t// Cast is needed because TypeScript can't preserve the type information\n\t\t// when modifying an object property\n\t\tconst newBuilder = this as any;\n\t\tnewBuilder.queries = {\n\t\t\t...this.queries,\n\t\t\t[name]: definition,\n\t\t};\n\t\treturn newBuilder;\n\t}\n\n\t/**\n\t * Set the system's process function that runs each update\n\t * @param process Function to process entities matching the system's queries each update\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetProcess(\n\t\tprocess: ProcessFunction<ComponentTypes, EventTypes, ResourceTypes, Queries>\n\t): this {\n\t\tthis.processFunction = process;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the onAttach lifecycle hook\n\t * Called when the system is attached to the ECS\n\t * @param onAttach Function to run when this system is attached to the ECS\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetOnAttach(\n\t\tonAttach: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>\n\t): this {\n\t\tthis.attachFunction = onAttach;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the onDetach lifecycle hook\n\t * Called when the system is removed from the ECS\n\t * @param onDetach Function to run when this system is detached from the ECS\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetOnDetach(\n\t\tonDetach: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>\n\t): this {\n\t\tthis.detachFunction = onDetach;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set event handlers for the system\n\t * These handlers will be automatically subscribed when the system is attached\n\t * @param handlers Object mapping event names to handler functions\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetEventHandlers(\n\t\thandlers: {\n\t\t\t[EventName in keyof EventTypes]?: {\n\t\t\t\thandler(\n\t\t\t\t\tdata: EventTypes[EventName],\n\t\t\t\t\tecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>\n\t\t\t\t): void;\n\t\t\t};\n\t\t}\n\t): this {\n\t\tthis.eventHandlers = handlers;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Build the final system object\n\t */\n\tbuild(ecspresso?: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) {\n\t\tconst system: System<ComponentTypes, any, any, EventTypes, ResourceTypes> = {\n\t\t\tlabel: this._label,\n\t\t\tentityQueries: this.queries,\n\t\t};\n\n\t\tif (this.processFunction) {\n\t\t\tsystem.process = this.processFunction;\n\t\t}\n\n\t\tif (this.attachFunction) {\n\t\t\tsystem.onAttach = this.attachFunction;\n\t\t}\n\n\t\tif (this.detachFunction) {\n\t\t\tsystem.onDetach = this.detachFunction;\n\t\t}\n\n\t\tif (this.eventHandlers) {\n\t\t\tsystem.eventHandlers = this.eventHandlers;\n\t\t}\n\n\t\tif (this._ecspresso) {\n\t\t\tregisterSystemWithEcspresso(system, this._ecspresso);\n\t\t}\n\n\t\tif(ecspresso) {\n\t\t\tregisterSystemWithEcspresso(system, ecspresso);\n\t\t}\n\n\t\treturn this;\n\t}\n}\n\n/**\n * Helper function to register a system with an ECSpresso instance\n * This handles attaching the system and setting up event handlers\n * @internal Used by SystemBuilder and Bundle\n */\nexport function registerSystemWithEcspresso<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>\n>(\n\tsystem: System<ComponentTypes, any, any, EventTypes, ResourceTypes>,\n\tecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>\n) {\n\t// Add system to ECSpresso's system list\n\tecspresso[\"_systems\"].push(system);\n\n\tsystem.onAttach?.(ecspresso);\n\n\tif(!system.eventHandlers) return;\n\n\tfor (const eventName in system.eventHandlers) {\n\t\tconst handler = system.eventHandlers[eventName]?.handler;\n\n\t\thandler && ecspresso.eventBus.subscribe(eventName, (data) => {\n\t\t\thandler(data, ecspresso);\n\t\t});\n\t}\n}\n\n// Helper type definitions\ntype QueryDefinition<\n\tComponentTypes,\n\tWithComponents extends keyof ComponentTypes = any,\n\tWithoutComponents extends keyof ComponentTypes = any,\n> = {\n\twith: ReadonlyArray<WithComponents>;\n\twithout?: ReadonlyArray<WithoutComponents>;\n};\n\ntype QueryResults<\n\tComponentTypes,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>>,\n> = {\n\t[QueryName in keyof Queries]: QueryName extends string\n\t\t? FilteredEntity<\n\t\t\tComponentTypes,\n\t\t\tQueries[QueryName] extends QueryDefinition<ComponentTypes, infer W, any> ? W : never,\n\t\t\tQueries[QueryName] extends QueryDefinition<ComponentTypes, any, infer WO> ? WO : never\n\t\t>[]\n\t\t: never;\n};\n\n/**\n * Function signature for system process methods\n * @param queries Results of entity queries defined by the system\n * @param deltaTime Time elapsed since last update in seconds\n * @param ecs The ECSpresso instance providing access to all ECS functionality\n */\ntype ProcessFunction<\n\tComponentTypes,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>>,\n> = (\n\tqueries: QueryResults<ComponentTypes, Queries>,\n\tdeltaTime: number,\n\tecs: ECSpresso<\n\t\tComponentTypes & Record<string, any>,\n\t\tEventTypes,\n\t\tResourceTypes\n\t>\n) => void;\n\n/**\n * Function signature for system lifecycle hooks (onAttach and onDetach)\n * @param ecs The ECSpresso instance providing access to all ECS functionality\n */\ntype LifecycleFunction<\n\tComponentTypes,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n> = (\n\tecs: ECSpresso<\n\t\tComponentTypes & Record<string, any>,\n\t\tEventTypes,\n\t\tResourceTypes\n\t>,\n) => void;\n\n/**\n * Create a SystemBuilder attached to an ECSpresso instance\n * Helper function used by ECSpresso.addSystem\n */\nexport function createEcspressoSystemBuilder<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>\n>(\n\tlabel: string,\n\tecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>\n): SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes> {\n\treturn new SystemBuilder<ComponentTypes, EventTypes, ResourceTypes>(\n\t\tlabel,\n\t\tecspresso\n\t) as SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes>;\n}\n\n/**\n * Create a SystemBuilder attached to a Bundle\n * Helper function used by Bundle.addSystem\n */\nexport function createBundleSystemBuilder<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>\n>(\n\tlabel: string,\n\tbundle: Bundle<ComponentTypes, EventTypes, ResourceTypes>\n): SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes> {\n\treturn new SystemBuilder<ComponentTypes, EventTypes, ResourceTypes>(\n\t\tlabel,\n\t\tnull,\n\t\tbundle\n\t) as SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes>;\n}\n\n// Type interfaces for specialized SystemBuilders\n\n/**\n * SystemBuilder with a guaranteed non-null reference to an ECSpresso instance\n */\nexport interface SystemBuilderWithEcspresso<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>> = {}\n> extends SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries> {\n\treadonly ecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>;\n}\n\n/**\n * SystemBuilder with a guaranteed non-null reference to a Bundle\n */\nexport interface SystemBuilderWithBundle<\n\tComponentTypes extends Record<string, any>,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>> = {}\n> extends SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries> {\n\treadonly bundle: Bundle<ComponentTypes, EventTypes, ResourceTypes>;\n}\n",
|
|
9
|
+
"import EntityManager from \"./entity-manager\";\nimport EventBus from \"./event-bus\";\nimport ResourceManager from \"./resource-manager\";\nimport type { System, FilteredEntity } from \"./types\";\nimport type Bundle from \"./bundle\";\nimport { createEcspressoSystemBuilder } from \"./system-builder\";\nimport { version } from \"../package.json\";\n\n/**\n\t* Type helper to detect conflicting types between two record types.\n\t* Returns a union of keys that exist in both T and U but have incompatible types.\n*/\ntype GetConflictingKeys<T, U> = {\n\t[K in keyof T & keyof U]: T[K] extends U[K]\n\t\t? U[K] extends T[K]\n\t\t\t? never\n\t\t\t: K\n\t\t: K\n}[keyof T & keyof U];\n\n/**\n\t* Simplified type helper to check bundle type compatibility.\n\t* Returns true if bundles can be merged without type conflicts.\n*/\ntype BundlesAreCompatible<\n\tC1 extends Record<string, any>,\n\tC2 extends Record<string, any>,\n\tE1 extends Record<string, any>,\n\tE2 extends Record<string, any>,\n\tR1 extends Record<string, any>,\n\tR2 extends Record<string, any>\n> =\n\t// If all base types are empty, any bundle is compatible\n\t[keyof C1] extends [never]\n\t\t? [keyof E1] extends [never]\n\t\t\t? [keyof R1] extends [never]\n\t\t\t\t? true\n\t\t\t\t: GetConflictingKeys<R1, R2> extends never ? true : false\n\t\t\t: GetConflictingKeys<E1, E2> extends never\n\t\t\t\t? GetConflictingKeys<R1, R2> extends never ? true : false\n\t\t\t\t: false\n\t\t: GetConflictingKeys<C1, C2> extends never\n\t\t\t? GetConflictingKeys<E1, E2> extends never\n\t\t\t\t? GetConflictingKeys<R1, R2> extends never\n\t\t\t\t\t? true\n\t\t\t\t\t: false\n\t\t\t\t: false\n\t\t\t: false;\n\n/**\n\t* Interface declaration for ECSpresso constructor to ensure type augmentation works properly.\n\t* This merges with the class declaration below.\n*/\nexport default interface ECSpresso<\n\tComponentTypes extends Record<string, any> = {},\n\tEventTypes extends Record<string, any> = {},\n\tResourceTypes extends Record<string, any> = {},\n> {\n\t/**\n\t\t* Default constructor\n\t*/\n\tnew(): ECSpresso<ComponentTypes, EventTypes, ResourceTypes>;\n}\n\n/**\n\t* Static methods on the ECSpresso class\n*/\nexport default interface ECSpresso {\n\t\t/**\n\t\t\t* Create a new ECSpresso builder with type-safe bundle installation.\n\t\t\t* This is the preferred way to create an ECSpresso instance with bundles.\n\t\t *\n\t\t\t* Example:\n\t\t\t* ```typescript\n\t\t\t* const ecs = ECSpresso.create<MyComponents, MyEvents, MyResources>()\n\t\t *\t .withBundle(bundle1)\n\t\t *\t .withBundle(bundle2)\n\t\t *\t .build();\n\t\t\t* ```\n\t\t*/\n\t\tcreate<\n\t\t\t\tBaseC extends Record<string, any> = {},\n\t\t\t\tBaseE extends Record<string, any> = {},\n\t\t\t\tBaseR extends Record<string, any> = {},\n\t\t>(): ECSpressoBuilder<BaseC, BaseE, BaseR>;\n}\n\n/**\n\t* ECSpresso is the central ECS framework class that connects all features.\n\t* It handles creation and management of entities, components, and systems, and provides lifecycle hooks.\n*/\nexport default class ECSpresso<\n\tComponentTypes extends Record<string, any> = {},\n\tEventTypes extends Record<string, any> = {},\n\tResourceTypes extends Record<string, any> = {},\n> {\n\t/** Library version*/\n\tpublic static readonly VERSION = version;\n\n\t/** Access/modify stored components and entities*/\n\tprivate _entityManager: EntityManager<ComponentTypes>;\n\t/** Publish/subscribe to events*/\n\tprivate _eventBus: EventBus<EventTypes>;\n\t/** Access/modify registered resources*/\n\tprivate _resourceManager: ResourceManager<ResourceTypes>;\n\n\t/** Registered systems that will be updated in order*/\n\tprivate _systems: Array<System<ComponentTypes, any, any, EventTypes, ResourceTypes>> = [];\n\t/** Track installed bundles to prevent duplicates*/\n\tprivate _installedBundles: Set<string> = new Set();\n\n\t/**\n\t\t* Creates a new ECSpresso instance.\n\t*/\n\tconstructor() {\n\t\tthis._entityManager = new EntityManager<ComponentTypes>();\n\t\tthis._eventBus = new EventBus<EventTypes>();\n\t\tthis._resourceManager = new ResourceManager<ResourceTypes>();\n\t}\n\n\t/**\n\t\t* Creates a new ECSpresso builder for type-safe bundle installation.\n\t\t* This is the preferred way to create an ECSpresso instance with bundles.\n\t *\n\t\t* @returns A builder instance for fluent method chaining\n\t *\n\t\t* @example\n\t\t* ```typescript\n\t\t* const ecs = ECSpresso.create<BaseComponents, BaseEvents, BaseResources>()\n\t *\t .withBundle(bundle1)\n\t *\t .withBundle(bundle2)\n\t *\t .build();\n\t\t* ```\n\t*/\n\tstatic create<\n\t\tC extends Record<string, any> = {},\n\t\tE extends Record<string, any> = {},\n\t\tR extends Record<string, any> = {},\n\t>(): ECSpressoBuilder<C, E, R> {\n\t\treturn new ECSpressoBuilder<C, E, R>();\n\t}\n\n\t/**\n\t\t* Adds a system directly to this ECSpresso instance\n\t\t* @param label Unique name to identify the system\n\t\t* @returns A SystemBuilder instance for method chaining\n\t*/\n\taddSystem(label: string) {\n\t\treturn createEcspressoSystemBuilder<\n\t\t\tComponentTypes,\n\t\t\tEventTypes,\n\t\t\tResourceTypes\n\t\t>(label, this);\n\t}\n\n\t/**\n\t\t* Update all systems, passing deltaTime and query results to each system's process function\n\t\t* @param deltaTime Time elapsed since the last update (in seconds)\n\t*/\n\tupdate(deltaTime: number) {\n\t\tfor (const system of this._systems) {\n\t\t\tif (!system.process) continue;\n\n\t\t\t// Prepare query results for each defined query in the system\n\t\t\tconst queryResults: Record<string, any> = {};\n\n\t\t\tif (system.entityQueries) {\n\t\t\t\tfor (const queryName in system.entityQueries) {\n\t\t\t\t\tconst query = system.entityQueries[queryName];\n\t\t\t\t\tif (query) {\n\t\t\t\t\t\tqueryResults[queryName] = this._entityManager.getEntitiesWithComponents(\n\t\t\t\t\t\t\tquery.with,\n\t\t\t\t\t\t\tquery.without || []\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Call the system's process function\n\t\t\tsystem.process(queryResults, deltaTime, this);\n\t\t}\n\t}\n\n\t/**\n\t\t* Internal method to install a bundle into this ECSpresso instance.\n\t\t* Called by the ECSpressoBuilder during the build process.\n\t\t* The type safety is guaranteed by the builder's type system.\n\t*/\n\t_installBundle<\n\t\tC extends Record<string, any>,\n\t\tE extends Record<string, any>,\n\t\tR extends Record<string, any>\n\t>(bundle: Bundle<C, E, R>): this {\n\t\t// Prevent duplicate installation of the same bundle\n\t\tif (this._installedBundles.has(bundle.id)) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Mark this bundle as installed\n\t\tthis._installedBundles.add(bundle.id);\n\n\t\t// Register systems from the bundle\n\t\t// Type casting is necessary because the generic parameters don't match\n\t\tbundle.registerSystemsWithEcspresso(this as any);\n\n\t\t// Register resources from the bundle\n\t\tconst resources = bundle.getResources();\n\t\tfor (const [key, value] of resources.entries()) {\n\t\t\t// Type compatibility is guaranteed by the builder's type system\n\t\t\tthis._resourceManager.add(key as unknown as keyof ResourceTypes, value as any);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t\t* Remove a system by its label\n\t\t* Calls the system's onDetach method with this ECSpresso instance if defined\n\t\t* @param label The unique label of the system to remove\n\t\t* @returns true if the system was found and removed, false otherwise\n\t*/\n\tremoveSystem(label: string): boolean {\n\t\tconst index = this._systems.findIndex(system => system.label === label);\n\t\tif (index === -1) return false;\n\n\t\tconst system = this._systems[index];\n\t\t// This should never happen since we just found the system by index\n\t\tif (!system) return false;\n\n\t\t// Call the onDetach lifecycle hook if defined\n\t\tif (system.onDetach) {\n\t\t\tsystem.onDetach(this);\n\t\t}\n\n\t\t// Remove system\n\t\tthis._systems.splice(index, 1);\n\t\treturn true;\n\t}\n\n\t/**\n\t\t* Check if a resource exists\n\t*/\n\thasResource<K extends keyof ResourceTypes>(key: K): boolean {\n\t\treturn this._resourceManager.has(key);\n\t}\n\n\t/**\n\t\t* Get a resource if it exists, or undefined if not\n\t*/\n\tgetResource<K extends keyof ResourceTypes>(key: K): ResourceTypes[K] {\n\t\tconst resource = this._resourceManager.getOptional(key);\n\n\t\tif (!resource) throw new Error(`Resource \"${key.toString()}\" not found`);\n\n\t\treturn resource;\n\t}\n\n\t/**\n\t\t* Add a resource to the ECS instance\n\t*/\n\taddResource<K extends keyof ResourceTypes>(key: K, resource: ResourceTypes[K]): this {\n\t\tthis._resourceManager.add(key, resource);\n\t\treturn this;\n\t}\n\n\t/**\n\t\t* Check if an entity has a component\n\t*/\n\thasComponent<K extends keyof ComponentTypes>(\n\t\tentityId: number,\n\t\tcomponentName: K\n\t): boolean {\n\t\tconst component = this._entityManager.getComponent(entityId, componentName);\n\t\treturn component !== null;\n\t}\n\n\t/**\n\t\t* Get all entities with specific components\n\t*/\n\tgetEntitiesWithComponents<\n\t\tWithComponents extends keyof ComponentTypes,\n\t\tWithoutComponents extends keyof ComponentTypes = never\n\t>(\n\t\twithComponents: ReadonlyArray<WithComponents>,\n\t\twithoutComponents: ReadonlyArray<WithoutComponents> = []\n\t): Array<FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>> {\n\t\treturn this._entityManager.getEntitiesWithComponents(\n\t\t\twithComponents,\n\t\t\twithoutComponents\n\t\t);\n\t}\n\n\t/**\n\t\t* Get all installed bundle IDs\n\t*/\n\tget installedBundles(): string[] {\n\t\treturn Array.from(this._installedBundles);\n\t}\n\n\t// Getters for the internal managers\n\tget entityManager() {\n\t\treturn this._entityManager;\n\t}\n\n\tget eventBus() {\n\t\treturn this._eventBus;\n\t}\n\n\tget resourceManager() {\n\t\treturn this._resourceManager;\n\t}\n}\n\n/**\n\t* Builder class for ECSpresso that provides fluent type-safe bundle installation.\n\t* Handles type checking during build process to ensure type safety.\n*/\nexport class ECSpressoBuilder<\n\tC extends Record<string, any> = {},\n\tE extends Record<string, any> = {},\n\tR extends Record<string, any> = {}\n> {\n\t/** The ECSpresso instance being built*/\n\tprivate ecspresso: ECSpresso<C, E, R>;\n\n\tconstructor() {\n\t\tthis.ecspresso = new ECSpresso<C, E, R>();\n\t}\n\n\t/**\n\t\t* Add the first bundle when starting with empty types.\n\t\t* This overload allows any bundle to be added to an empty ECSpresso instance.\n\t*/\n\twithBundle<\n\t\tBC extends Record<string, any>,\n\t\tBE extends Record<string, any>,\n\t\tBR extends Record<string, any>\n\t>(\n\t\tthis: ECSpressoBuilder<{}, {}, {}>,\n\t\tbundle: Bundle<BC, BE, BR>\n\t): ECSpressoBuilder<BC, BE, BR>;\n\n\t/**\n\t\t* Add a subsequent bundle with type checking.\n\t\t* This overload enforces bundle type compatibility.\n\t*/\n\twithBundle<\n\t\tBC extends Record<string, any>,\n\t\tBE extends Record<string, any>,\n\t\tBR extends Record<string, any>\n\t>(\n\t\tbundle: BundlesAreCompatible<C, BC, E, BE, R, BR> extends true\n\t\t\t? Bundle<BC, BE, BR>\n\t\t\t: never\n\t): ECSpressoBuilder<C & BC, E & BE, R & BR>;\n\n\t/**\n\t\t* Implementation of both overloads.\n\t\t* Since the type compatibility is checked in the method signature,\n\t\t* we can safely assume the bundle is compatible here.\n\t*/\n\twithBundle<\n\t\tBC extends Record<string, any>,\n\t\tBE extends Record<string, any>,\n\t\tBR extends Record<string, any>\n\t>(\n\t\tbundle: Bundle<BC, BE, BR>\n\t): ECSpressoBuilder<C & BC, E & BE, R & BR> {\n\t\t// Install the bundle\n\t\t// Type compatibility is guaranteed by method overloads\n\t\tthis.ecspresso._installBundle(bundle as any);\n\n\t\t// Return a builder with the updated type parameters\n\t\treturn this as unknown as ECSpressoBuilder<C & BC, E & BE, R & BR>;\n\t}\n\n\t/**\n\t\t* Complete the build process and return the built ECSpresso instance\n\t*/\n\tbuild(): ECSpresso<C, E, R> {\n\t\treturn this.ecspresso;\n\t}\n}\n",
|
|
10
10
|
"import { createBundleSystemBuilder, SystemBuilder } from './system-builder';\nimport type ECSpresso from './ecspresso';\n\n/**\n * Generates a unique ID for a bundle\n */\nfunction generateBundleId(): string {\n\treturn `bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Bundle class that encapsulates a set of components, resources, events, and systems\n * that can be merged into a ECSpresso instance\n */\nexport default class Bundle<\n\tComponentTypes extends Record<string, any> = Record<string, any>,\n\tEventTypes extends Record<string, any> = Record<string, any>,\n\tResourceTypes extends Record<string, any> = Record<string, any>,\n> {\n\tprivate _systems: SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, any>[] = [];\n\tprivate _resources: Map<keyof ResourceTypes, ResourceTypes[keyof ResourceTypes]> = new Map();\n\tprivate _id: string;\n\n\tconstructor(id?: string) {\n\t\tthis._id = id || generateBundleId();\n\t}\n\n\t/**\n\t * Get the unique ID of this bundle\n\t */\n\tget id(): string {\n\t\treturn this._id;\n\t}\n\n\t/**\n\t * Set the ID of this bundle\n\t * @internal Used by combineBundles\n\t */\n\tset id(value: string) {\n\t\tthis._id = value;\n\t}\n\n\t/**\n\t * Add a system to this bundle\n\t */\n\taddSystem(label: string) {\n\t\tconst system = createBundleSystemBuilder<ComponentTypes, EventTypes, ResourceTypes>(label, this);\n\n\t\tthis._systems.push(system);\n\n\t\treturn system;\n\t}\n\n\t/**\n\t * Add a resource to this bundle\n\t * @param label The resource key\n\t * @param resource The resource value\n\t */\n\taddResource<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K]) {\n\t\tthis._resources.set(label, resource);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get all systems defined in this bundle\n\t * Returns built System objects instead of SystemBuilders\n\t */\n\tgetSystems() {\n\t\treturn this._systems.map(system => system.build());\n\t}\n\n\t/**\n\t * Register all systems in this bundle with an ECSpresso instance\n\t * @internal Used by ECSpresso when adding a bundle\n\t */\n\tregisterSystemsWithEcspresso(ecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) {\n\t\tfor (const systemBuilder of this._systems) {\n\t\t\tsystemBuilder.build(ecspresso);\n\t\t}\n\t}\n\n\t/**\n\t * Get all resources defined in this bundle\n\t */\n\tgetResources(): Map<keyof ResourceTypes, ResourceTypes[keyof ResourceTypes]> {\n\t\treturn new Map(this._resources);\n\t}\n\n\t/**\n\t * Get a specific resource by key\n\t * @param key The resource key\n\t * @returns The resource value or undefined if not found\n\t */\n\tgetResource<K extends keyof ResourceTypes>(key: K): ResourceTypes[K] | undefined {\n\t\treturn this._resources.get(key) as ResourceTypes[K] | undefined;\n\t}\n\n\t/**\n\t * Get all system builders in this bundle\n\t */\n\tgetSystemBuilders(): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, any>[] {\n\t\treturn [...this._systems];\n\t}\n\n\t/**\n\t * Check if this bundle has a specific resource\n\t * @param key The resource key to check\n\t * @returns True if the resource exists\n\t */\n\thasResource<K extends keyof ResourceTypes>(key: K): boolean {\n\t\treturn this._resources.has(key);\n\t}\n}\n\n// Check if object has exactly the same type\ntype Exactly<T, U> =\n T extends U\n ? U extends T\n ? true\n : false\n : false;\n\n// Create a type error for incompatible types\ntype IncompatibleBundles<\n C1 extends Record<string, any>,\n C2 extends Record<string, any>,\n E1 extends Record<string, any>,\n E2 extends Record<string, any>,\n R1 extends Record<string, any>,\n R2 extends Record<string, any>\n> = {\n [K in keyof C1 & keyof C2]: Exactly<C1[K], C2[K]> extends false ? never : unknown;\n} & {\n [K in keyof E1 & keyof E2]: Exactly<E1[K], E2[K]> extends false ? never : unknown;\n} & {\n [K in keyof R1 & keyof R2]: Exactly<R1[K], R2[K]> extends false ? never : unknown;\n};\n\n/**\n * Function that merges multiple bundles into a single bundle\n */\nexport function mergeBundles<\n C1 extends Record<string, any>,\n E1 extends Record<string, any>,\n R1 extends Record<string, any>,\n C2 extends Record<string, any>,\n E2 extends Record<string, any>,\n R2 extends Record<string, any>\n>(\n id: string,\n bundle1: Bundle<C1, E1, R1>,\n bundle2: Bundle<C2, E2, R2> & IncompatibleBundles<C1, C2, E1, E2, R1, R2>\n): Bundle<C1 & C2, E1 & E2, R1 & R2>;\n\nexport function mergeBundles<\n ComponentTypes extends Record<string, any>,\n EventTypes extends Record<string, any>,\n ResourceTypes extends Record<string, any>\n>(\n id: string,\n ...bundles: Array<Bundle<ComponentTypes, EventTypes, ResourceTypes>>\n): Bundle<ComponentTypes, EventTypes, ResourceTypes>;\n\nexport function mergeBundles(\n id: string,\n ...bundles: Array<Bundle<any, any, any>>\n): Bundle<any, any, any> {\n if (bundles.length === 0) {\n return new Bundle(id);\n }\n\n const combined = new Bundle(id);\n\n for (const bundle of bundles) {\n for (const system of bundle.getSystemBuilders()) {\n combined.addSystem(system as any);\n }\n\n // Add resources from this bundle\n for (const [label, resource] of bundle.getResources().entries()) {\n combined.addResource(label as any, resource);\n }\n }\n\n return combined as any;\n}\n",
|
|
11
11
|
"import ECSpresso from './ecspresso';\nimport { SystemBuilder } from './system-builder';\nimport Bundle, { mergeBundles } from './bundle';\n\nexport * from './types';\nexport { default as EntityManager } from './entity-manager';\nexport { default as EventBus } from './event-bus';\nexport { default as ResourceManager } from './resource-manager';\nexport { SystemBuilder };\nexport { Bundle, mergeBundles };\nexport default ECSpresso;\n"
|
|
12
12
|
],
|
|
13
|
-
"mappings": "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
|
|
14
|
-
"debugId": "
|
|
13
|
+
"mappings": "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",
|
|
14
|
+
"debugId": "5B3F11C4615EDE1564756E2164756E21",
|
|
15
15
|
"names": []
|
|
16
16
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecspresso",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"pixi.js": "^8.9.0"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"typescript": "^5"
|
|
27
|
+
"typescript": "^5.8.2"
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"dist"
|
|
@@ -34,8 +34,10 @@
|
|
|
34
34
|
"build:ts": "bun tsc -p tsconfig.build.json",
|
|
35
35
|
"build:js": "bun build --target=browser --sourcemap=linked --minify --outdir=dist src/index.ts",
|
|
36
36
|
"build": "bun build:clean && bun build:ts && bun build:js",
|
|
37
|
+
"check:types": "bun tsc --noEmit --skipLibCheck",
|
|
38
|
+
"check": "bun run check:types && bun test",
|
|
37
39
|
"examples": "bun ./examples/serve-examples.ts",
|
|
38
|
-
"prepublishOnly": "bun
|
|
40
|
+
"prepublishOnly": "bun run check && bun run build"
|
|
39
41
|
},
|
|
40
42
|
"type": "module"
|
|
41
43
|
}
|