ecspresso 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,13 +3,17 @@ import type EntityManager from "./entity-manager";
3
3
  /**
4
4
  * Definition for a reactive query with enter/exit callbacks
5
5
  */
6
- export interface ReactiveQueryDefinition<ComponentTypes extends Record<string, any>, WithComponents extends keyof ComponentTypes = keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never> {
6
+ export interface ReactiveQueryDefinition<ComponentTypes extends Record<string, any>, WithComponents extends keyof ComponentTypes = keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never, OptionalComponents extends keyof ComponentTypes = never> {
7
7
  /** Components the entity must have */
8
8
  with: ReadonlyArray<WithComponents>;
9
9
  /** Components the entity must not have */
10
10
  without?: ReadonlyArray<WithoutComponents>;
11
+ /** Components to include in the entity type but not require for matching */
12
+ optional?: ReadonlyArray<OptionalComponents>;
13
+ /** Components the entity's direct parent must have */
14
+ parentHas?: ReadonlyArray<keyof ComponentTypes>;
11
15
  /** Called when an entity starts matching the query */
12
- onEnter?: (entity: FilteredEntity<ComponentTypes, WithComponents, WithoutComponents>) => void;
16
+ onEnter?: (entity: FilteredEntity<ComponentTypes, WithComponents, WithoutComponents, OptionalComponents>) => void;
13
17
  /** Called when an entity stops matching the query (receives just the ID since entity may be gone) */
14
18
  onExit?: (entityId: number) => void;
15
19
  }
@@ -19,13 +23,19 @@ export interface ReactiveQueryDefinition<ComponentTypes extends Record<string, a
19
23
  export default class ReactiveQueryManager<ComponentTypes extends Record<string, any>> {
20
24
  private queries;
21
25
  private entityManager;
26
+ /** Whether any registered query uses parentHas */
27
+ private _hasParentHasQueries;
22
28
  constructor(entityManager: EntityManager<ComponentTypes>);
29
+ /**
30
+ * Whether any registered reactive query uses parentHas filters
31
+ */
32
+ get hasParentHasQueries(): boolean;
23
33
  /**
24
34
  * Add a reactive query
25
35
  * @param name Unique name for the query
26
36
  * @param definition Query definition with callbacks
27
37
  */
28
- addQuery<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never>(name: string, definition: ReactiveQueryDefinition<ComponentTypes, WithComponents, WithoutComponents>): void;
38
+ addQuery<WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never, OptionalComponents extends keyof ComponentTypes = never>(name: string, definition: ReactiveQueryDefinition<ComponentTypes, WithComponents, WithoutComponents, OptionalComponents>): void;
29
39
  /**
30
40
  * Remove a reactive query
31
41
  * @param name Name of the query to remove
@@ -56,4 +66,13 @@ export default class ReactiveQueryManager<ComponentTypes extends Record<string,
56
66
  * Fires enter/exit callbacks as appropriate based on current state vs tracked state
57
67
  */
58
68
  recheckEntity(entity: Entity<ComponentTypes>): void;
69
+ /**
70
+ * Recheck all children of a parent entity against parentHas queries.
71
+ * Called when a component is added/removed from a parent entity.
72
+ */
73
+ private _recheckChildren;
74
+ /**
75
+ * Recalculate the _hasParentHasQueries flag from all registered queries
76
+ */
77
+ private _recalcParentHasFlag;
59
78
  }
@@ -1,6 +1,6 @@
1
1
  import Bundle from "./bundle";
2
2
  import ECSpresso from "./ecspresso";
3
- import type { FilteredEntity, System } from "./types";
3
+ import type { FilteredEntity, System, SystemPhase } from "./types";
4
4
  /**
5
5
  * Builder class for creating type-safe ECS Systems with proper query inference
6
6
  */
@@ -14,6 +14,7 @@ export declare class SystemBuilder<ComponentTypes extends Record<string, any> =
14
14
  private initializeFunction?;
15
15
  private eventHandlers?;
16
16
  private _priority;
17
+ private _phase;
17
18
  private _isRegistered;
18
19
  private _groups;
19
20
  private _inScreens?;
@@ -52,6 +53,14 @@ export declare class SystemBuilder<ComponentTypes extends Record<string, any> =
52
53
  * @returns This SystemBuilder instance for method chaining
53
54
  */
54
55
  setPriority(priority: number): this;
56
+ /**
57
+ * Set the execution phase for this system.
58
+ * Systems are grouped by phase and executed in order:
59
+ * preUpdate -> fixedUpdate -> update -> postUpdate -> render
60
+ * @param phase The phase to assign this system to (default: 'update')
61
+ * @returns This SystemBuilder instance for method chaining
62
+ */
63
+ inPhase(phase: SystemPhase): this;
55
64
  /**
56
65
  * Add this system to a group. Systems can belong to multiple groups.
57
66
  * When any group a system belongs to is disabled, the system will be skipped.
@@ -86,9 +95,12 @@ export declare class SystemBuilder<ComponentTypes extends Record<string, any> =
86
95
  /**
87
96
  * Add a query definition to the system
88
97
  */
89
- addQuery<QueryName extends string, WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never, NewQueries extends Queries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents>> = Queries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents>>>(name: QueryName, definition: {
98
+ addQuery<QueryName extends string, WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = never, OptionalComponents extends keyof ComponentTypes = never, NewQueries extends Queries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents, OptionalComponents>> = Queries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents, OptionalComponents>>>(name: QueryName, definition: {
90
99
  with: ReadonlyArray<WithComponents>;
91
100
  without?: ReadonlyArray<WithoutComponents>;
101
+ changed?: ReadonlyArray<WithComponents>;
102
+ optional?: ReadonlyArray<OptionalComponents>;
103
+ parentHas?: ReadonlyArray<keyof ComponentTypes>;
92
104
  }): this extends SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes, Queries> ? SystemBuilderWithEcspresso<ComponentTypes, EventTypes, ResourceTypes, NewQueries> : this extends SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes, Queries> ? SystemBuilderWithBundle<ComponentTypes, EventTypes, ResourceTypes, NewQueries> : SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, NewQueries>;
93
105
  /**
94
106
  * Set the system's process function that runs each update
@@ -145,12 +157,15 @@ export declare class SystemBuilder<ComponentTypes extends Record<string, any> =
145
157
  * @internal Used by SystemBuilder and Bundle
146
158
  */
147
159
  export declare function registerSystemWithEcspresso<ComponentTypes extends Record<string, any>, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>>(system: System<ComponentTypes, any, any, EventTypes, ResourceTypes>, ecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>): void;
148
- type QueryDefinition<ComponentTypes, WithComponents extends keyof ComponentTypes = any, WithoutComponents extends keyof ComponentTypes = any> = {
160
+ type QueryDefinition<ComponentTypes, WithComponents extends keyof ComponentTypes = any, WithoutComponents extends keyof ComponentTypes = any, OptionalComponents extends keyof ComponentTypes = any> = {
149
161
  with: ReadonlyArray<WithComponents>;
150
162
  without?: ReadonlyArray<WithoutComponents>;
163
+ changed?: ReadonlyArray<WithComponents>;
164
+ optional?: ReadonlyArray<OptionalComponents>;
165
+ parentHas?: ReadonlyArray<keyof ComponentTypes>;
151
166
  };
152
167
  type QueryResults<ComponentTypes, Queries extends Record<string, QueryDefinition<ComponentTypes>>> = {
153
- [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;
168
+ [QueryName in keyof Queries]: QueryName extends string ? FilteredEntity<ComponentTypes, Queries[QueryName] extends QueryDefinition<ComponentTypes, infer W, any, any> ? W : never, Queries[QueryName] extends QueryDefinition<ComponentTypes, any, infer WO, any> ? WO : never, Queries[QueryName] extends QueryDefinition<ComponentTypes, any, any, infer O> ? O : never>[] : never;
154
169
  };
155
170
  /**
156
171
  * Function signature for system process methods
package/dist/types.d.ts CHANGED
@@ -1,4 +1,10 @@
1
1
  import ECSpresso from "./ecspresso";
2
+ /**
3
+ * Execution phase for systems. Systems are grouped by phase and executed
4
+ * in this fixed order: preUpdate -> fixedUpdate -> update -> postUpdate -> render.
5
+ * Within each phase, systems are sorted by priority (higher first).
6
+ */
7
+ export type SystemPhase = 'preUpdate' | 'fixedUpdate' | 'update' | 'postUpdate' | 'render';
2
8
  export interface Entity<ComponentTypes> {
3
9
  id: number;
4
10
  components: Partial<ComponentTypes>;
@@ -45,15 +51,20 @@ export interface EventHandler<T> {
45
51
  callback: (data: T) => void;
46
52
  once: boolean;
47
53
  }
48
- export interface FilteredEntity<ComponentTypes, WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never> {
54
+ export interface FilteredEntity<ComponentTypes, WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never, OptionalComponents extends keyof ComponentTypes = never> {
49
55
  id: number;
50
- components: Omit<Partial<ComponentTypes>, WithoutComponents> & {
56
+ components: Omit<Partial<ComponentTypes>, WithoutComponents | OptionalComponents> & {
51
57
  [K in WithComponents]: ComponentTypes[K];
58
+ } & {
59
+ [K in OptionalComponents]: ComponentTypes[K] | undefined;
52
60
  };
53
61
  }
54
- export interface QueryConfig<ComponentTypes, WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes> {
62
+ export interface QueryConfig<ComponentTypes, WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes, OptionalComponents extends keyof ComponentTypes = WithComponents> {
55
63
  with: ReadonlyArray<WithComponents>;
56
64
  without?: ReadonlyArray<WithoutComponents>;
65
+ changed?: ReadonlyArray<WithComponents>;
66
+ optional?: ReadonlyArray<OptionalComponents>;
67
+ parentHas?: ReadonlyArray<keyof ComponentTypes>;
57
68
  }
58
69
  /**
59
70
  * Utility type to derive the entity type that would result from a query definition.
@@ -79,13 +90,19 @@ export interface QueryConfig<ComponentTypes, WithComponents extends keyof Compon
79
90
  export type QueryResultEntity<ComponentTypes extends Record<string, any>, QueryDef extends {
80
91
  with: ReadonlyArray<keyof ComponentTypes>;
81
92
  without?: ReadonlyArray<keyof ComponentTypes>;
82
- }> = FilteredEntity<ComponentTypes, QueryDef['with'][number], QueryDef['without'] extends ReadonlyArray<any> ? QueryDef['without'][number] : never>;
93
+ changed?: ReadonlyArray<keyof ComponentTypes>;
94
+ optional?: ReadonlyArray<keyof ComponentTypes>;
95
+ parentHas?: ReadonlyArray<keyof ComponentTypes>;
96
+ }> = FilteredEntity<ComponentTypes, QueryDef['with'][number], QueryDef['without'] extends ReadonlyArray<any> ? QueryDef['without'][number] : never, QueryDef['optional'] extends ReadonlyArray<any> ? QueryDef['optional'][number] : never>;
83
97
  /**
84
98
  * Simplified query definition type for creating reusable queries
85
99
  */
86
- export type QueryDefinition<ComponentTypes extends Record<string, any>, WithComponents extends keyof ComponentTypes = keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = keyof ComponentTypes> = {
100
+ export type QueryDefinition<ComponentTypes extends Record<string, any>, WithComponents extends keyof ComponentTypes = keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = keyof ComponentTypes, OptionalComponents extends keyof ComponentTypes = keyof ComponentTypes> = {
87
101
  with: ReadonlyArray<WithComponents>;
88
102
  without?: ReadonlyArray<WithoutComponents>;
103
+ changed?: ReadonlyArray<WithComponents>;
104
+ optional?: ReadonlyArray<OptionalComponents>;
105
+ parentHas?: ReadonlyArray<keyof ComponentTypes>;
89
106
  };
90
107
  /**
91
108
  * Helper function to create a query definition with proper type inference.
@@ -117,6 +134,9 @@ export type QueryDefinition<ComponentTypes extends Record<string, any>, WithComp
117
134
  export declare function createQueryDefinition<ComponentTypes extends Record<string, any>, const QueryDef extends {
118
135
  with: ReadonlyArray<keyof ComponentTypes>;
119
136
  without?: ReadonlyArray<keyof ComponentTypes>;
137
+ changed?: ReadonlyArray<keyof ComponentTypes>;
138
+ optional?: ReadonlyArray<keyof ComponentTypes>;
139
+ parentHas?: ReadonlyArray<keyof ComponentTypes>;
120
140
  }>(queryDef: QueryDef): QueryDef;
121
141
  export interface System<ComponentTypes extends Record<string, any> = {}, WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never, EventTypes extends Record<string, any> = {}, ResourceTypes extends Record<string, any> = {}, AssetTypes extends Record<string, unknown> = {}, ScreenStates extends Record<string, any> = {}> {
122
142
  label: string;
@@ -125,6 +145,12 @@ export interface System<ComponentTypes extends Record<string, any> = {}, WithCom
125
145
  * When systems have the same priority, they execute in registration order
126
146
  */
127
147
  priority?: number;
148
+ /**
149
+ * Execution phase for this system (default: 'update')
150
+ * Systems are grouped by phase and executed in order:
151
+ * preUpdate -> fixedUpdate -> update -> postUpdate -> render
152
+ */
153
+ phase?: SystemPhase;
128
154
  /**
129
155
  * Groups this system belongs to. If any group is disabled, the system will be skipped.
130
156
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ecspresso",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,6 +18,26 @@
18
18
  "./bundles/utils/timers": {
19
19
  "import": "./dist/bundles/utils/timers.js",
20
20
  "types": "./dist/bundles/utils/timers.d.ts"
21
+ },
22
+ "./bundles/utils/transform": {
23
+ "import": "./dist/bundles/utils/transform.js",
24
+ "types": "./dist/bundles/utils/transform.d.ts"
25
+ },
26
+ "./bundles/utils/movement": {
27
+ "import": "./dist/bundles/utils/movement.js",
28
+ "types": "./dist/bundles/utils/movement.d.ts"
29
+ },
30
+ "./bundles/utils/bounds": {
31
+ "import": "./dist/bundles/utils/bounds.js",
32
+ "types": "./dist/bundles/utils/bounds.d.ts"
33
+ },
34
+ "./bundles/utils/collision": {
35
+ "import": "./dist/bundles/utils/collision.js",
36
+ "types": "./dist/bundles/utils/collision.d.ts"
37
+ },
38
+ "./bundles/utils/input": {
39
+ "import": "./dist/bundles/utils/input.js",
40
+ "types": "./dist/bundles/utils/input.d.ts"
21
41
  }
22
42
  },
23
43
  "publishConfig": {
@@ -58,7 +78,7 @@
58
78
  "scripts": {
59
79
  "build:clean": "rm -rf dist",
60
80
  "build:ts": "bun tsc -p tsconfig.build.json",
61
- "build:js": "bun build --target=browser --sourcemap=linked --minify --external=pixi.js --outdir=dist src/index.ts src/bundles/renderers/renderer2D.ts src/bundles/utils/timers.ts",
81
+ "build:js": "bun scripts/build.ts",
62
82
  "build": "bun build:clean && bun build:ts && bun build:js",
63
83
  "check:types": "bun tsc --noEmit --skipLibCheck",
64
84
  "check": "bun run check:types && bun test",