ecspresso 0.0.0 → 0.0.2

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.
@@ -0,0 +1,67 @@
1
+ import { SystemBuilder } from './system-builder';
2
+ /**
3
+ * Bundle class that encapsulates a set of components, resources, events, and systems
4
+ * that can be merged into a ECSpresso instance
5
+ */
6
+ export default class Bundle<ComponentTypes extends Record<string, any> = Record<string, any>, EventTypes extends Record<string, any> = Record<string, any>, ResourceTypes extends Record<string, any> = Record<string, any>> {
7
+ private _systems;
8
+ private _resources;
9
+ private _id;
10
+ constructor(id?: string);
11
+ /**
12
+ * Get the unique ID of this bundle
13
+ */
14
+ get id(): string;
15
+ /**
16
+ * Set the ID of this bundle
17
+ * @internal Used by combineBundles
18
+ */
19
+ set id(value: string);
20
+ /**
21
+ * Add a system to this bundle
22
+ */
23
+ addSystem(label: string): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, {}>;
24
+ /**
25
+ * Add a resource to this bundle
26
+ * @param label The resource key
27
+ * @param resource The resource value
28
+ */
29
+ addResource<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K]): this;
30
+ /**
31
+ * Get all systems defined in this bundle
32
+ * Returns built System objects instead of SystemBuilders
33
+ */
34
+ getSystems(): import("./types").System<ComponentTypes, any, any, EventTypes, ResourceTypes>[];
35
+ /**
36
+ * Get all resources defined in this bundle
37
+ */
38
+ getResources(): Map<keyof ResourceTypes, ResourceTypes[keyof ResourceTypes]>;
39
+ /**
40
+ * Get a specific resource by key
41
+ * @param key The resource key
42
+ * @returns The resource value or undefined if not found
43
+ */
44
+ getResource<K extends keyof ResourceTypes>(key: K): ResourceTypes[K] | undefined;
45
+ /**
46
+ * Get all system builders in this bundle
47
+ */
48
+ getSystemBuilders(): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, any>[];
49
+ /**
50
+ * Check if this bundle has a specific resource
51
+ * @param key The resource key to check
52
+ * @returns True if the resource exists
53
+ */
54
+ hasResource<K extends keyof ResourceTypes>(key: K): boolean;
55
+ }
56
+ /**
57
+ * Utility type for merging two types
58
+ */
59
+ export type Merge<T1, T2> = T1 & T2;
60
+ export type MergeAll<T extends any[]> = T extends [infer First, ...infer Rest] ? Rest extends [] ? First : Merge<First, MergeAll<Rest>> : {};
61
+ export declare function mergeBundles<Bundles extends Array<Bundle<any, any, any>>>(id: string, ...bundles: Bundles): Bundle<MergeAll<{
62
+ [K in keyof Bundles]: Bundles[K] extends Bundle<infer C, any, any> ? C : never;
63
+ }>, MergeAll<{
64
+ [K in keyof Bundles]: Bundles[K] extends Bundle<any, infer E, any> ? E : never;
65
+ }>, MergeAll<{
66
+ [K in keyof Bundles]: Bundles[K] extends Bundle<any, any, infer R> ? R : never;
67
+ }>>;
@@ -0,0 +1,56 @@
1
+ import EntityManager from "./entity-manager";
2
+ import EventBus from "./event-bus";
3
+ import ResourceManager from "./resource-manager";
4
+ import type Bundle from "./bundle";
5
+ export default class ECSpresso<ComponentTypes extends Record<string, any> = Record<string, any>, EventTypes extends Record<string, any> = Record<string, any>, ResourceTypes extends Record<string, any> = Record<string, any>> {
6
+ static readonly VERSION: string;
7
+ private _entityManager;
8
+ private _systems;
9
+ private _eventBus;
10
+ private _resourceManager;
11
+ private _installedBundles;
12
+ constructor();
13
+ /**
14
+ * Install one or more bundles into this ECS instance
15
+ */
16
+ install<Bundles extends Array<Bundle<any, any, any>>>(...bundles: Bundles): this;
17
+ /**
18
+ * Remove a system by its label
19
+ */
20
+ removeSystem(label: string): boolean;
21
+ /**
22
+ * Check if a resource exists
23
+ */
24
+ hasResource<K extends keyof ResourceTypes>(key: K): boolean;
25
+ /**
26
+ * Get a resource if it exists, or undefined if not
27
+ */
28
+ getResource<K extends keyof ResourceTypes>(key: K): ResourceTypes[K] | undefined;
29
+ /**
30
+ * Get a resource, throws error if not found
31
+ */
32
+ getResourceOrThrow<K extends keyof ResourceTypes>(key: K): ResourceTypes[K];
33
+ /**
34
+ * Add a resource to the ECS instance
35
+ */
36
+ addResource<K extends keyof ResourceTypes>(key: K, resource: ResourceTypes[K]): this;
37
+ /**
38
+ * Check if an entity has a component
39
+ */
40
+ hasComponent<K extends keyof ComponentTypes>(entityId: number, componentName: K): boolean;
41
+ /**
42
+ * Get all entities with specific components
43
+ */
44
+ getEntitiesWithComponents(withComponents: (keyof ComponentTypes)[], withoutComponents?: (keyof ComponentTypes)[]): import("./types").FilteredEntity<ComponentTypes, keyof ComponentTypes extends infer T ? T extends keyof ComponentTypes ? T extends never ? never : T : never : never, keyof ComponentTypes extends infer T_1 ? T_1 extends keyof ComponentTypes ? T_1 extends never ? never : T_1 : never : never>[];
45
+ /**
46
+ * Update all systems
47
+ */
48
+ update(deltaTime: number): void;
49
+ get entityManager(): EntityManager<ComponentTypes>;
50
+ get eventBus(): EventBus<EventTypes>;
51
+ get resourceManager(): ResourceManager<ResourceTypes>;
52
+ /**
53
+ * Get all installed bundle IDs
54
+ */
55
+ get installedBundles(): string[];
56
+ }
@@ -0,0 +1,13 @@
1
+ import type { Entity, FilteredEntity } from "./types";
2
+ export default class EntityManager<ComponentTypes> {
3
+ private nextId;
4
+ private entities;
5
+ private componentIndices;
6
+ createEntity(): Entity<ComponentTypes>;
7
+ addComponent<ComponentName extends keyof ComponentTypes>(entityOrId: number | Entity<ComponentTypes>, componentName: ComponentName, data: ComponentTypes[ComponentName]): this;
8
+ removeComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName): void;
9
+ getComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName): ComponentTypes[ComponentName] | null;
10
+ getEntitiesWithComponents<WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never>(required?: ReadonlyArray<WithComponents>, excluded?: ReadonlyArray<WithoutComponents>): Array<FilteredEntity<ComponentTypes, WithComponents extends never ? never : WithComponents, WithoutComponents extends never ? never : WithoutComponents>>;
11
+ removeEntity(entityId: number): boolean;
12
+ getEntity(entityId: number): Entity<ComponentTypes> | undefined;
13
+ }
@@ -0,0 +1,18 @@
1
+ export default class EventBus<EventTypes> {
2
+ private handlers;
3
+ /**
4
+ * Subscribe to an event
5
+ */
6
+ subscribe<E extends keyof EventTypes>(eventType: E, callback: (data: EventTypes[E]) => void): () => void;
7
+ /**
8
+ * Subscribe to an event once
9
+ */
10
+ once<E extends keyof EventTypes>(eventType: E, callback: (data: EventTypes[E]) => void): () => void;
11
+ /**
12
+ * Internal method to add an event handler
13
+ */
14
+ private addHandler;
15
+ publish<E extends keyof EventTypes>(eventType: E, data?: EventTypes[E]): void;
16
+ clear(): void;
17
+ clearEvent<E extends keyof EventTypes>(eventType: E): void;
18
+ }
@@ -0,0 +1,10 @@
1
+ import ECSpresso from './ecspresso';
2
+ import { SystemBuilder } from './system-builder';
3
+ import Bundle, { mergeBundles } from './bundle';
4
+ export * from './types';
5
+ export { default as EntityManager } from './entity-manager';
6
+ export { default as EventBus } from './event-bus';
7
+ export { default as ResourceManager } from './resource-manager';
8
+ export { SystemBuilder };
9
+ export { Bundle, mergeBundles };
10
+ export default ECSpresso;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- class M{nextId=1;entities=new Map;componentIndices=new Map;createEntity(){let f=this.nextId++,g={id:f,components:{}};return this.entities.set(f,g),g}addComponent(f,g,E){let J=typeof f==="number"?this.entities.get(f):f;if(!J)throw new Error(`Entity ${f} does not exist`);if(J.components[g]=E,!this.componentIndices.has(g))this.componentIndices.set(g,new Set);return this.componentIndices.get(g)?.add(J.id),this}removeComponent(f,g){let E=this.entities.get(f);if(!E)throw new Error(`Entity ${f} does not exist`);delete E.components[g],this.componentIndices.get(g)?.delete(f)}getComponent(f,g){let E=this.entities.get(f);if(!E)throw new Error(`Entity ${f} does not exist`);return E.components[g]||null}getEntitiesWithComponents(f=[],g=[]){if(f.length===0){if(g.length===0)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((j)=>{return g.every((F)=>!(F in j.components))})}let E=f.reduce((j,F)=>{let K=this.componentIndices.get(F),U=K?K.size:0,X=this.componentIndices.get(j)?.size??1/0;return U<X?F:j},f[0]);return Array.from(this.componentIndices.get(E)||[]).filter((j)=>{let F=this.entities.get(j);return F&&f.every((K)=>(K in F.components))&&g.every((K)=>!(K in F.components))}).map((j)=>this.entities.get(j))}removeEntity(f){let g=this.entities.get(f);if(!g)return!1;for(let E of Object.keys(g.components))this.componentIndices.get(E)?.delete(f);return this.entities.delete(f)}getEntity(f){return this.entities.get(f)}}class P{handlers=new Map;subscribe(f,g){return this.addHandler(f,g,!1)}once(f,g){return this.addHandler(f,g,!0)}addHandler(f,g,E){if(!this.handlers.has(f))this.handlers.set(f,[]);let J={callback:g,once:E};return this.handlers.get(f).push(J),()=>{let j=this.handlers.get(f);if(j){let F=j.indexOf(J);if(F!==-1)j.splice(F,1)}}}publish(f,g=void 0){let E=this.handlers.get(f);if(!E)return;let J=[...E],j=[];for(let F of J)if(F.callback(g),F.once)j.push(F);if(j.length>0)for(let F of j){let K=E.indexOf(F);if(K!==-1)E.splice(K,1)}}clear(){this.handlers.clear()}clearEvent(f){this.handlers.delete(f)}}class Q{resources=new Map;add(f,g){return this.resources.set(f,g),g}get(f){let g=this.resources.get(f);if(g===void 0)throw new Error(`Resource ${String(f)} not found`);return g}getOptional(f){return this.resources.get(f)}has(f){return this.resources.has(f)}remove(f){return this.resources.delete(f)}getKeys(){return Array.from(this.resources.keys())}}var Y="0.0.0";class V{static VERSION=Y;_entityManager;_systems=[];_eventBus;_resourceManager;_installedBundles=new Set;constructor(){this._entityManager=new M,this._eventBus=new P,this._resourceManager=new Q}install(...f){for(let g of f){if(this._installedBundles.has(g.id)){console.warn(`Bundle ${g.id} is already installed`);continue}let E=g.getSystems();if(!E.length)console.warn(`Bundle ${g.id} has no systems`);for(let j of E){let F=j;if(this._systems.push(F),F.onAttach)F.onAttach(this._entityManager,this._resourceManager,this._eventBus);if(F.eventHandlers)for(let K in F.eventHandlers){let U=F.eventHandlers[K];if(U?.handler){let X=(Z)=>{U.handler(Z,this._entityManager,this._resourceManager,this._eventBus)};this._eventBus.subscribe(K,X)}}}let J=g.getResources();for(let[j,F]of J.entries())this._resourceManager.add(j,F);this._installedBundles.add(g.id)}return this}removeSystem(f){let g=this._systems.findIndex((J)=>J.label===f);if(g===-1)return!1;let E=this._systems[g];if(!E)return!1;return E.onDetach?.(this._entityManager,this._resourceManager,this._eventBus),this._systems.splice(g,1),!0}hasResource(f){return this._resourceManager.has(f)}getResource(f){return this._resourceManager.getOptional(f)}getResourceOrThrow(f){return this._resourceManager.get(f)}addResource(f,g){return this._resourceManager.add(f,g),this}hasComponent(f,g){return this._entityManager.getComponent(f,g)!==null}getEntitiesWithComponents(f,g=[]){return this._entityManager.getEntitiesWithComponents(f,g)}update(f){for(let g of this._systems){if(!g.process)continue;let E={};if(g.entityQueries){for(let J in g.entityQueries){let j=g.entityQueries[J];if(j)E[J]=this._entityManager.getEntitiesWithComponents(j.with,j.without||[])}g.process(E,f,this._entityManager,this._resourceManager,this._eventBus)}else g.process([],f,this._entityManager,this._resourceManager,this._eventBus)}}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}get resourceManager(){return this._resourceManager}get installedBundles(){return Array.from(this._installedBundles)}}function $(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class L{_systems=[];_resources=new Map;_id;constructor(f){this._id=f||$()}get id(){return this._id}set id(f){this._id=f}addSystem(f){let g=new W(f,this);return this._systems.push(g),g}addResource(f,g){return this._resources.set(f,g),this}getSystems(){return this._systems.map((f)=>f.build())}getResources(){return new Map(this._resources)}getResource(f){return this._resources.get(f)}getSystemBuilders(){return[...this._systems]}hasResource(f){return this._resources.has(f)}}function D(f,...g){if(g.length===0)return new L(f);let E=new L(f);for(let J of g){for(let j of J.getSystemBuilders())E.addSystem(j);for(let[j,F]of J.getResources().entries())E.addResource(j,F)}return E}class W{_label;_bundle;queries={};processFunction;attachFunction;detachFunction;eventHandlers;constructor(f,g=new L){this._label=f;this._bundle=g}get label(){return this._label}get bundle(){return this._bundle}addQuery(f,g){let E=this;return E.queries={...this.queries,[f]:g},E}setProcess(f){return this.processFunction=f,this}setOnAttach(f){return this.attachFunction=f,this}setOnDetach(f){return this.detachFunction=f,this}setEventHandlers(f){return this.eventHandlers=f,this}build(){let f={label:this._label,entityQueries:this.queries};if(this.processFunction)f.process=this.processFunction;if(this.attachFunction)f.onAttach=this.attachFunction;if(this.detachFunction)f.onDetach=this.detachFunction;if(this.eventHandlers)f.eventHandlers=this.eventHandlers;return f}}var c=V;export{D as mergeBundles,c as default,W as SystemBuilder,Q as ResourceManager,P as EventBus,M as EntityManager,L as Bundle};
1
+ class M{nextId=1;entities=new Map;componentIndices=new Map;createEntity(){let f=this.nextId++,g={id:f,components:{}};return this.entities.set(f,g),g}addComponent(f,g,j){let J=typeof f==="number"?this.entities.get(f):f;if(!J)throw new Error(`Entity ${f} does not exist`);if(J.components[g]=j,!this.componentIndices.has(g))this.componentIndices.set(g,new Set);return this.componentIndices.get(g)?.add(J.id),this}removeComponent(f,g){let j=this.entities.get(f);if(!j)throw new Error(`Entity ${f} does not exist`);delete j.components[g],this.componentIndices.get(g)?.delete(f)}getComponent(f,g){let j=this.entities.get(f);if(!j)throw new Error(`Entity ${f} does not exist`);return j.components[g]||null}getEntitiesWithComponents(f=[],g=[]){if(f.length===0){if(g.length===0)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((E)=>{return g.every((F)=>!(F in E.components))})}let j=f.reduce((E,F)=>{let K=this.componentIndices.get(F),U=K?K.size:0,X=this.componentIndices.get(E)?.size??1/0;return U<X?F:E},f[0]);return Array.from(this.componentIndices.get(j)||[]).filter((E)=>{let F=this.entities.get(E);return F&&f.every((K)=>(K in F.components))&&g.every((K)=>!(K in F.components))}).map((E)=>this.entities.get(E))}removeEntity(f){let g=this.entities.get(f);if(!g)return!1;for(let j of Object.keys(g.components))this.componentIndices.get(j)?.delete(f);return this.entities.delete(f)}getEntity(f){return this.entities.get(f)}}class P{handlers=new Map;subscribe(f,g){return this.addHandler(f,g,!1)}once(f,g){return this.addHandler(f,g,!0)}addHandler(f,g,j){if(!this.handlers.has(f))this.handlers.set(f,[]);let J={callback:g,once:j};return this.handlers.get(f).push(J),()=>{let E=this.handlers.get(f);if(E){let F=E.indexOf(J);if(F!==-1)E.splice(F,1)}}}publish(f,g=void 0){let j=this.handlers.get(f);if(!j)return;let J=[...j],E=[];for(let F of J)if(F.callback(g),F.once)E.push(F);if(E.length>0)for(let F of E){let K=j.indexOf(F);if(K!==-1)j.splice(K,1)}}clear(){this.handlers.clear()}clearEvent(f){this.handlers.delete(f)}}class Q{resources=new Map;add(f,g){return this.resources.set(f,g),g}get(f){let g=this.resources.get(f);if(g===void 0)throw new Error(`Resource ${String(f)} not found`);return g}getOptional(f){return this.resources.get(f)}has(f){return this.resources.has(f)}remove(f){return this.resources.delete(f)}getKeys(){return Array.from(this.resources.keys())}}var Y="0.0.2";class V{static VERSION=Y;_entityManager;_systems=[];_eventBus;_resourceManager;_installedBundles=new Set;constructor(){this._entityManager=new M,this._eventBus=new P,this._resourceManager=new Q}install(...f){for(let g of f){if(this._installedBundles.has(g.id)){console.warn(`Bundle ${g.id} is already installed`);continue}let j=g.getSystems();if(!j.length)console.warn(`Bundle ${g.id} has no systems`);for(let E of j){let F=E;if(this._systems.push(F),F.onAttach)F.onAttach(this._entityManager,this._resourceManager,this._eventBus);if(F.eventHandlers)for(let K in F.eventHandlers){let U=F.eventHandlers[K];if(U?.handler){let X=(Z)=>{U.handler(Z,this._entityManager,this._resourceManager,this._eventBus)};this._eventBus.subscribe(K,X)}}}let J=g.getResources();for(let[E,F]of J.entries())this._resourceManager.add(E,F);this._installedBundles.add(g.id)}return this}removeSystem(f){let g=this._systems.findIndex((J)=>J.label===f);if(g===-1)return!1;let j=this._systems[g];if(!j)return!1;return j.onDetach?.(this._entityManager,this._resourceManager,this._eventBus),this._systems.splice(g,1),!0}hasResource(f){return this._resourceManager.has(f)}getResource(f){return this._resourceManager.getOptional(f)}getResourceOrThrow(f){return this._resourceManager.get(f)}addResource(f,g){return this._resourceManager.add(f,g),this}hasComponent(f,g){return this._entityManager.getComponent(f,g)!==null}getEntitiesWithComponents(f,g=[]){return this._entityManager.getEntitiesWithComponents(f,g)}update(f){for(let g of this._systems){if(!g.process)continue;let j={};if(g.entityQueries){for(let J in g.entityQueries){let E=g.entityQueries[J];if(E)j[J]=this._entityManager.getEntitiesWithComponents(E.with,E.without||[])}g.process(j,f,this._entityManager,this._resourceManager,this._eventBus)}else g.process([],f,this._entityManager,this._resourceManager,this._eventBus)}}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}get resourceManager(){return this._resourceManager}get installedBundles(){return Array.from(this._installedBundles)}}function $(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class L{_systems=[];_resources=new Map;_id;constructor(f){this._id=f||$()}get id(){return this._id}set id(f){this._id=f}addSystem(f){let g=new W(f,this);return this._systems.push(g),g}addResource(f,g){return this._resources.set(f,g),this}getSystems(){return this._systems.map((f)=>f.build())}getResources(){return new Map(this._resources)}getResource(f){return this._resources.get(f)}getSystemBuilders(){return[...this._systems]}hasResource(f){return this._resources.has(f)}}function D(f,...g){if(g.length===0)return new L(f);let j=new L(f);for(let J of g){for(let E of J.getSystemBuilders())j.addSystem(E);for(let[E,F]of J.getResources().entries())j.addResource(E,F)}return j}class W{_label;_bundle;queries={};processFunction;attachFunction;detachFunction;eventHandlers;constructor(f,g=new L){this._label=f;this._bundle=g}get label(){return this._label}get bundle(){return this._bundle}addQuery(f,g){let j=this;return j.queries={...this.queries,[f]:g},j}setProcess(f){return this.processFunction=f,this}setOnAttach(f){return this.attachFunction=f,this}setOnDetach(f){return this.detachFunction=f,this}setEventHandlers(f){return this.eventHandlers=f,this}build(){let f={label:this._label,entityQueries:this.queries};if(this.processFunction)f.process=this.processFunction;if(this.attachFunction)f.onAttach=this.attachFunction;if(this.detachFunction)f.onDetach=this.detachFunction;if(this.eventHandlers)f.eventHandlers=this.eventHandlers;return f}}var i=V;export{D as mergeBundles,i as default,W as SystemBuilder,Q as ResourceManager,P as EventBus,M as EntityManager,L as Bundle};
2
2
 
3
- //# debugId=7DD37829380BFEFA64756E2164756E21
3
+ //# debugId=3C890DE03A8FCB0764756E2164756E21
4
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -11,6 +11,6 @@
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
13
  "mappings": "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",
14
- "debugId": "7DD37829380BFEFA64756E2164756E21",
14
+ "debugId": "3C890DE03A8FCB0764756E2164756E21",
15
15
  "names": []
16
16
  }
@@ -0,0 +1,40 @@
1
+ export default class ResourceManager<ResourceTypes extends Record<string, any> = Record<string, any>> {
2
+ private resources;
3
+ /**
4
+ * Add a resource to the manager
5
+ * @param label The resource key
6
+ * @param resource The resource value
7
+ * @returns The added resource
8
+ */
9
+ add<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K]): ResourceTypes[K];
10
+ /**
11
+ * Get a resource from the manager
12
+ * @param label The resource key
13
+ * @returns The resource value
14
+ * @throws Error if resource not found
15
+ */
16
+ get<K extends keyof ResourceTypes>(label: K): ResourceTypes[K];
17
+ /**
18
+ * Get a resource from the manager, returning undefined if not found
19
+ * @param label The resource key
20
+ * @returns The resource value or undefined if not found
21
+ */
22
+ getOptional<K extends keyof ResourceTypes>(label: K): ResourceTypes[K] | undefined;
23
+ /**
24
+ * Check if a resource exists
25
+ * @param label The resource key
26
+ * @returns True if the resource exists
27
+ */
28
+ has<K extends keyof ResourceTypes>(label: K): boolean;
29
+ /**
30
+ * Remove a resource
31
+ * @param label The resource key
32
+ * @returns True if the resource was removed
33
+ */
34
+ remove<K extends keyof ResourceTypes>(label: K): boolean;
35
+ /**
36
+ * Get all resource keys
37
+ * @returns Array of resource keys
38
+ */
39
+ getKeys(): Array<keyof ResourceTypes>;
40
+ }
@@ -0,0 +1,61 @@
1
+ import Bundle from "./bundle";
2
+ import type EntityManager from "./entity-manager";
3
+ import type EventBus from "./event-bus";
4
+ import type ResourceManager from "./resource-manager";
5
+ import type { FilteredEntity, System } from "./types";
6
+ /**
7
+ * Builder class for creating type-safe ECS Systems with proper query inference
8
+ */
9
+ export declare class SystemBuilder<ComponentTypes extends Record<string, any> = Record<string, any>, EventTypes extends Record<string, any> = Record<string, any>, ResourceTypes extends Record<string, any> = Record<string, any>, Queries extends Record<string, QueryDefinition<ComponentTypes>> = {}> {
10
+ private _label;
11
+ private _bundle;
12
+ private queries;
13
+ private processFunction?;
14
+ private attachFunction?;
15
+ private detachFunction?;
16
+ private eventHandlers?;
17
+ constructor(_label: string, _bundle?: Bundle<ComponentTypes, EventTypes, ResourceTypes>);
18
+ get label(): string;
19
+ get bundle(): Bundle<ComponentTypes, EventTypes, ResourceTypes>;
20
+ /**
21
+ * Add a query definition to the system
22
+ */
23
+ addQuery<QueryName extends string, WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never>(name: QueryName, definition: {
24
+ with: ReadonlyArray<WithComponents>;
25
+ without?: ReadonlyArray<WithoutComponents>;
26
+ }): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents>>>;
27
+ /**
28
+ * Set the system's process function that runs each update
29
+ */
30
+ setProcess(process: ProcessFunction<ComponentTypes, EventTypes, ResourceTypes, Queries>): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries>;
31
+ /**
32
+ * Set the onAttach lifecycle hook
33
+ */
34
+ setOnAttach(onAttach: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries>;
35
+ /**
36
+ * Set the onDetach lifecycle hook
37
+ */
38
+ setOnDetach(onDetach: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries>;
39
+ /**
40
+ * Set event handlers for the system
41
+ */
42
+ setEventHandlers(handlers: {
43
+ [EventName in keyof EventTypes]?: {
44
+ handler(data: EventTypes[EventName], entityManager: EntityManager<ComponentTypes>, resourceManager: ResourceManager<ResourceTypes>, eventBus: EventBus<EventTypes>): void;
45
+ };
46
+ }): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries>;
47
+ /**
48
+ * Build the final system object
49
+ */
50
+ build(): System<ComponentTypes, any, any, EventTypes, ResourceTypes>;
51
+ }
52
+ type QueryDefinition<ComponentTypes, WithComponents extends keyof ComponentTypes = any, WithoutComponents extends keyof ComponentTypes = any> = {
53
+ with: ReadonlyArray<WithComponents>;
54
+ without?: ReadonlyArray<WithoutComponents>;
55
+ };
56
+ type QueryResults<ComponentTypes, Queries extends Record<string, QueryDefinition<ComponentTypes>>> = {
57
+ [QueryName in keyof Queries]: QueryName extends string ? FilteredEntity<ComponentTypes, Queries[QueryName] extends QueryDefinition<ComponentTypes, infer W, any> ? W : never, Queries[QueryName] extends QueryDefinition<ComponentTypes, any, infer WO> ? WO : never>[] : never;
58
+ };
59
+ type ProcessFunction<ComponentTypes, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>, Queries extends Record<string, QueryDefinition<ComponentTypes>>> = (queries: QueryResults<ComponentTypes, Queries>, deltaTime: number, entityManager: EntityManager<ComponentTypes>, resourceManager: ResourceManager<ResourceTypes>, eventBus: EventBus<EventTypes>) => void;
60
+ type LifecycleFunction<ComponentTypes, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>> = (entityManager: EntityManager<ComponentTypes>, resourceManager: ResourceManager<ResourceTypes>, eventBus: EventBus<EventTypes>) => void;
61
+ export {};
@@ -0,0 +1,37 @@
1
+ import type ResourceManager from "./resource-manager";
2
+ import type EventBus from "./event-bus";
3
+ import type EntityManager from "./entity-manager";
4
+ export interface Entity<ComponentTypes> {
5
+ id: number;
6
+ components: Partial<ComponentTypes>;
7
+ }
8
+ export interface EventHandler<T> {
9
+ callback: (data: T) => void;
10
+ once: boolean;
11
+ }
12
+ export interface FilteredEntity<ComponentTypes, WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never> {
13
+ id: number;
14
+ components: Omit<Partial<ComponentTypes>, WithoutComponents> & {
15
+ [ComponentName in WithComponents]: ComponentTypes[ComponentName];
16
+ };
17
+ }
18
+ export interface QueryConfig<ComponentTypes, WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes> {
19
+ with: ReadonlyArray<WithComponents>;
20
+ without?: ReadonlyArray<WithoutComponents>;
21
+ }
22
+ export interface System<ComponentTypes, WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never, EventTypes extends Record<string, any> = Record<string, any>, ResourceTypes extends Record<string, any> = Record<string, any>> {
23
+ label: string;
24
+ entityQueries?: {
25
+ [queryName: string]: QueryConfig<ComponentTypes, WithComponents, WithoutComponents>;
26
+ };
27
+ process?(queries: {
28
+ [queryName: string]: Array<FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>>;
29
+ } | Array<FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>>, deltaTime: number, entityManager: EntityManager<ComponentTypes>, resourceManager: ResourceManager<ResourceTypes>, eventBus: EventBus<EventTypes>): void;
30
+ onAttach?(entityManager: EntityManager<ComponentTypes>, resourceManager: ResourceManager<ResourceTypes>, eventBus: EventBus<EventTypes>): void;
31
+ onDetach?(entityManager: EntityManager<ComponentTypes>, resourceManager: ResourceManager<ResourceTypes>, eventBus: EventBus<EventTypes>): void;
32
+ eventHandlers?: {
33
+ [EventName in keyof EventTypes]?: {
34
+ handler(data: EventTypes[EventName], entityManager: EntityManager<ComponentTypes>, resourceManager: ResourceManager<ResourceTypes>, eventBus: EventBus<EventTypes>): void;
35
+ };
36
+ };
37
+ }
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "ecspresso",
3
- "version": "0.0.0",
4
- "main": "src/index.ts",
5
- "module": "src/index.ts",
3
+ "version": "0.0.2",
4
+ "main": "dist/index.js",
5
+ "module": "dist/index.js",
6
+ "types": "dist/index.d.ts",
6
7
  "description": "A minimal Entity-Component-System library for typescript and javascript.",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/david0178418/ecspresso"
11
+ },
7
12
  "keywords": [
8
13
  "game",
9
14
  "gamedev",
@@ -25,9 +30,10 @@
25
30
  ],
26
31
  "scripts": {
27
32
  "build:clean": "rm -rf dist",
28
- "build:ts": "bun build --target=browser --sourcemap=linked --minify --outdir=dist src/index.ts",
29
- "build": "bun build:clean && bun build:ts",
33
+ "build:ts": "bun tsc -p tsconfig.build.json",
34
+ "build:js": "bun build --target=browser --sourcemap=linked --minify --outdir=dist src/index.ts",
35
+ "build": "bun build:clean && bun build:ts && bun build:js",
30
36
  "prepublishOnly": "bun run build"
31
37
  },
32
38
  "type": "module"
33
- }
39
+ }