ecspresso 0.10.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +256 -148
- package/dist/asset-manager.d.ts +16 -16
- package/dist/asset-types.d.ts +18 -16
- package/dist/command-buffer.d.ts +30 -20
- package/dist/ecspresso-builder.d.ts +193 -0
- package/dist/ecspresso.d.ts +323 -209
- package/dist/entity-manager.d.ts +76 -30
- package/dist/event-bus.d.ts +6 -1
- package/dist/index.d.ts +6 -13
- package/dist/plugin.d.ts +61 -0
- package/dist/plugins/audio.d.ts +273 -0
- package/dist/{bundles/utils → plugins}/bounds.d.ts +20 -26
- package/dist/plugins/camera.d.ts +88 -0
- package/dist/plugins/collision.d.ts +285 -0
- package/dist/plugins/coroutine.d.ts +126 -0
- package/dist/plugins/diagnostics.d.ts +49 -0
- package/dist/{bundles/utils → plugins}/input.d.ts +22 -29
- package/dist/plugins/particles.d.ts +225 -0
- package/dist/plugins/physics2D.d.ts +163 -0
- package/dist/plugins/renderers/renderer2D.d.ts +262 -0
- package/dist/plugins/spatial-index.d.ts +58 -0
- package/dist/plugins/sprite-animation.d.ts +150 -0
- package/dist/plugins/state-machine.d.ts +244 -0
- package/dist/plugins/timers.d.ts +151 -0
- package/dist/{bundles/utils → plugins}/transform.d.ts +21 -22
- package/dist/plugins/tween.d.ts +162 -0
- package/dist/reactive-query-manager.d.ts +14 -3
- package/dist/resource-manager.d.ts +64 -23
- package/dist/screen-manager.d.ts +21 -15
- package/dist/screen-types.d.ts +15 -11
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +25 -0
- package/dist/src/plugins/audio.js +4 -0
- package/dist/src/plugins/audio.js.map +10 -0
- package/dist/src/plugins/bounds.js +4 -0
- package/dist/src/plugins/bounds.js.map +10 -0
- package/dist/src/plugins/camera.js +4 -0
- package/dist/src/plugins/camera.js.map +10 -0
- package/dist/src/plugins/collision.js +4 -0
- package/dist/src/plugins/collision.js.map +11 -0
- package/dist/src/plugins/coroutine.js +4 -0
- package/dist/src/plugins/coroutine.js.map +10 -0
- package/dist/src/plugins/diagnostics.js +5 -0
- package/dist/src/plugins/diagnostics.js.map +10 -0
- package/dist/src/plugins/input.js +4 -0
- package/dist/src/plugins/input.js.map +10 -0
- package/dist/src/plugins/particles.js +4 -0
- package/dist/src/plugins/particles.js.map +10 -0
- package/dist/src/plugins/physics2D.js +4 -0
- package/dist/src/plugins/physics2D.js.map +11 -0
- package/dist/src/plugins/renderers/renderer2D.js +4 -0
- package/dist/src/plugins/renderers/renderer2D.js.map +10 -0
- package/dist/src/plugins/spatial-index.js +4 -0
- package/dist/src/plugins/spatial-index.js.map +11 -0
- package/dist/src/plugins/sprite-animation.js +4 -0
- package/dist/src/plugins/sprite-animation.js.map +10 -0
- package/dist/src/plugins/state-machine.js +4 -0
- package/dist/src/plugins/state-machine.js.map +10 -0
- package/dist/src/plugins/timers.js +4 -0
- package/dist/src/plugins/timers.js.map +10 -0
- package/dist/src/plugins/transform.js +4 -0
- package/dist/src/plugins/transform.js.map +10 -0
- package/dist/src/plugins/tween.js +4 -0
- package/dist/src/plugins/tween.js.map +11 -0
- package/dist/system-builder.d.ts +75 -112
- package/dist/type-utils.d.ts +247 -7
- package/dist/types.d.ts +58 -39
- package/dist/utils/check-required-cycle.d.ts +12 -0
- package/dist/utils/easing.d.ts +71 -0
- package/dist/utils/math.d.ts +67 -0
- package/dist/utils/narrowphase.d.ts +63 -0
- package/dist/utils/spatial-hash.d.ts +53 -0
- package/package.json +65 -27
- package/dist/bundle.d.ts +0 -123
- package/dist/bundles/renderers/renderer2D.d.ts +0 -220
- package/dist/bundles/renderers/renderer2D.js +0 -4
- package/dist/bundles/renderers/renderer2D.js.map +0 -10
- package/dist/bundles/utils/bounds.js +0 -4
- package/dist/bundles/utils/bounds.js.map +0 -10
- package/dist/bundles/utils/collision.d.ts +0 -204
- package/dist/bundles/utils/collision.js +0 -4
- package/dist/bundles/utils/collision.js.map +0 -10
- package/dist/bundles/utils/input.js +0 -4
- package/dist/bundles/utils/input.js.map +0 -10
- package/dist/bundles/utils/movement.d.ts +0 -86
- package/dist/bundles/utils/movement.js +0 -4
- package/dist/bundles/utils/movement.js.map +0 -10
- package/dist/bundles/utils/timers.d.ts +0 -172
- package/dist/bundles/utils/timers.js +0 -4
- package/dist/bundles/utils/timers.js.map +0 -10
- package/dist/bundles/utils/transform.js +0 -4
- package/dist/bundles/utils/transform.js.map +0 -10
- package/dist/index.js +0 -4
- package/dist/index.js.map +0 -22
package/dist/ecspresso.d.ts
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
import EntityManager from "./entity-manager";
|
|
2
2
|
import EventBus from "./event-bus";
|
|
3
|
+
import { type ResourceFactoryWithDeps, type ResourceDirectValue } from "./resource-manager";
|
|
3
4
|
import AssetManager from "./asset-manager";
|
|
4
5
|
import ScreenManager from "./screen-manager";
|
|
5
6
|
import { type ReactiveQueryDefinition } from "./reactive-query-manager";
|
|
6
7
|
import CommandBuffer from "./command-buffer";
|
|
7
8
|
import type { System, SystemPhase, FilteredEntity, Entity, RemoveEntityOptions, HierarchyEntry, HierarchyIteratorOptions } from "./types";
|
|
8
|
-
import type
|
|
9
|
-
import
|
|
10
|
-
import type {
|
|
11
|
-
import type { ScreenDefinition
|
|
9
|
+
import { type Plugin } from "./plugin";
|
|
10
|
+
import { SystemBuilder } from "./system-builder";
|
|
11
|
+
import type { AssetDefinition, AssetHandle } from "./asset-types";
|
|
12
|
+
import type { ScreenDefinition } from "./screen-types";
|
|
13
|
+
import { ECSpressoBuilder } from "./ecspresso-builder";
|
|
14
|
+
import type { WorldConfig, EmptyConfig } from "./type-utils";
|
|
12
15
|
/**
|
|
13
16
|
* Interface declaration for ECSpresso constructor to ensure type augmentation works properly.
|
|
14
17
|
* This merges with the class declaration below.
|
|
15
18
|
*/
|
|
16
|
-
export default interface ECSpresso<
|
|
19
|
+
export default interface ECSpresso<Cfg extends WorldConfig = EmptyConfig, Labels extends string = string, Groups extends string = string, AssetGroupNames extends string = string, ReactiveQueryNames extends string = string> {
|
|
17
20
|
/**
|
|
18
21
|
* Default constructor
|
|
19
22
|
*/
|
|
20
|
-
new (): ECSpresso<
|
|
23
|
+
new (): ECSpresso<Cfg, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
23
26
|
* ECSpresso is the central ECS framework class that connects all features.
|
|
24
27
|
* It handles creation and management of entities, components, and systems, and provides lifecycle hooks.
|
|
25
28
|
*/
|
|
26
|
-
export default class ECSpresso<
|
|
29
|
+
export default class ECSpresso<Cfg extends WorldConfig = EmptyConfig, Labels extends string = string, Groups extends string = string, AssetGroupNames extends string = string, ReactiveQueryNames extends string = string> {
|
|
30
|
+
readonly _cfg: Cfg;
|
|
27
31
|
/** Library version*/
|
|
28
32
|
static readonly VERSION: string;
|
|
29
33
|
/** Access/modify stored components and entities*/
|
|
@@ -38,8 +42,8 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
38
42
|
private _systems;
|
|
39
43
|
/** Systems grouped by execution phase, each sorted by priority */
|
|
40
44
|
private _phaseSystems;
|
|
41
|
-
/** Track installed
|
|
42
|
-
private
|
|
45
|
+
/** Track installed plugins to prevent duplicates*/
|
|
46
|
+
private _installedPlugins;
|
|
43
47
|
/** Disabled system groups */
|
|
44
48
|
private _disabledGroups;
|
|
45
49
|
/** Asset manager for loading and accessing assets */
|
|
@@ -64,36 +68,71 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
64
68
|
private _interpolationAlpha;
|
|
65
69
|
/** Maximum fixed update steps per frame (spiral-of-death protection) */
|
|
66
70
|
private _maxFixedSteps;
|
|
71
|
+
/** Registry of required component relationships: trigger -> [{component, factory}] */
|
|
72
|
+
private _requiredComponents;
|
|
73
|
+
/** Pending plugin assets awaiting manager creation at build time */
|
|
74
|
+
private _pendingPluginAssets;
|
|
75
|
+
/** Pending plugin screens awaiting manager creation at build time */
|
|
76
|
+
private _pendingPluginScreens;
|
|
77
|
+
/** Whether diagnostics timing collection is enabled */
|
|
78
|
+
private _diagnosticsEnabled;
|
|
79
|
+
/** Per-system timing in ms, populated when diagnostics enabled */
|
|
80
|
+
private _systemTimings;
|
|
81
|
+
/** Per-phase timing in ms, populated when diagnostics enabled */
|
|
82
|
+
private _phaseTimings;
|
|
83
|
+
/** Per-system per-query seen entity IDs for onEntityEnter tracking */
|
|
84
|
+
private _entityEnterTracking;
|
|
85
|
+
/** Shared reusable set for per-tick entity enter comparison (avoids allocation) */
|
|
86
|
+
private _entityEnterFrameSet;
|
|
87
|
+
/** Pre-allocated process context per system (avoids per-frame allocation) */
|
|
88
|
+
private _systemContexts;
|
|
89
|
+
/** Pending system builder finalizers to run before next update/initialize */
|
|
90
|
+
private _pendingFinalizers;
|
|
91
|
+
private _batchingRegistrations;
|
|
67
92
|
/**
|
|
68
93
|
* Creates a new ECSpresso instance.
|
|
69
94
|
*/
|
|
70
95
|
constructor();
|
|
71
96
|
/**
|
|
72
|
-
*
|
|
97
|
+
* Subscribes to EntityManager lifecycle hooks for change detection,
|
|
98
|
+
* required component auto-addition, and reactive query tracking.
|
|
73
99
|
* @private
|
|
74
100
|
*/
|
|
75
|
-
private
|
|
101
|
+
private _subscribeLifecycleHooks;
|
|
76
102
|
/**
|
|
77
|
-
* Creates a new ECSpresso builder for type-safe
|
|
78
|
-
*
|
|
103
|
+
* Creates a new ECSpresso builder for type-safe plugin installation.
|
|
104
|
+
* Types are inferred from the builder chain — use `.withPlugin()`,
|
|
105
|
+
* `.withComponentTypes<T>()`, `.withEventTypes<T>()`, and `.withResource()`
|
|
106
|
+
* to accumulate types without manual aggregate interfaces.
|
|
79
107
|
*
|
|
80
108
|
* @returns A builder instance for fluent method chaining
|
|
81
109
|
*
|
|
82
110
|
* @example
|
|
83
111
|
* ```typescript
|
|
84
|
-
* const ecs = ECSpresso.create
|
|
85
|
-
* .
|
|
86
|
-
* .
|
|
112
|
+
* const ecs = ECSpresso.create()
|
|
113
|
+
* .withPlugin(createRenderer2DPlugin({ ... }))
|
|
114
|
+
* .withPlugin(createPhysics2DPlugin())
|
|
115
|
+
* .withComponentTypes<{ player: true; enemy: { type: string } }>()
|
|
116
|
+
* .withEventTypes<{ gameStart: true }>()
|
|
117
|
+
* .withResource('score', { value: 0 })
|
|
87
118
|
* .build();
|
|
119
|
+
*
|
|
120
|
+
* type ECS = typeof ecs;
|
|
88
121
|
* ```
|
|
89
122
|
*/
|
|
90
|
-
static create<
|
|
123
|
+
static create<Cfg2 extends WorldConfig = EmptyConfig>(): ECSpressoBuilder<Cfg2, never, never, never, never>;
|
|
91
124
|
/**
|
|
92
|
-
* Adds a system directly to this ECSpresso instance
|
|
125
|
+
* Adds a system directly to this ECSpresso instance.
|
|
126
|
+
* The system is registered when initialize() or update() is next called.
|
|
93
127
|
* @param label Unique name to identify the system
|
|
94
128
|
* @returns A SystemBuilder instance for method chaining
|
|
95
129
|
*/
|
|
96
|
-
addSystem(label: string):
|
|
130
|
+
addSystem(label: string): SystemBuilder<Cfg>;
|
|
131
|
+
/**
|
|
132
|
+
* Finalize and register all pending system builders.
|
|
133
|
+
* @private
|
|
134
|
+
*/
|
|
135
|
+
private _finalizePendingBuilders;
|
|
97
136
|
/**
|
|
98
137
|
* Update all systems across execution phases.
|
|
99
138
|
* Phases run in order: preUpdate -> fixedUpdate -> update -> postUpdate -> render.
|
|
@@ -106,6 +145,11 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
106
145
|
* @private
|
|
107
146
|
*/
|
|
108
147
|
private _executePhase;
|
|
148
|
+
/**
|
|
149
|
+
* Execute a non-fixed phase with optional timing, then play back the command buffer.
|
|
150
|
+
* @private
|
|
151
|
+
*/
|
|
152
|
+
private _runPhase;
|
|
109
153
|
/**
|
|
110
154
|
* Initialize all resources and systems
|
|
111
155
|
* This method:
|
|
@@ -127,7 +171,7 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
127
171
|
* @param keys Optional array of resource keys to initialize. If not provided, all pending resources will be initialized.
|
|
128
172
|
* @returns Promise that resolves when the specified resources are initialized
|
|
129
173
|
*/
|
|
130
|
-
initializeResources<K extends keyof
|
|
174
|
+
initializeResources<K extends keyof Cfg['resources']>(...keys: K[]): Promise<void>;
|
|
131
175
|
/**
|
|
132
176
|
* Rebuild per-phase system arrays from the flat _systems list.
|
|
133
177
|
* Each phase array is sorted by priority (higher first), with
|
|
@@ -141,14 +185,14 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
141
185
|
* @param priority The new priority value (higher values execute first)
|
|
142
186
|
* @returns true if the system was found and updated, false otherwise
|
|
143
187
|
*/
|
|
144
|
-
updateSystemPriority(label:
|
|
188
|
+
updateSystemPriority(label: Labels, priority: number): boolean;
|
|
145
189
|
/**
|
|
146
190
|
* Move a system to a different execution phase at runtime.
|
|
147
191
|
* @param label The unique label of the system to move
|
|
148
192
|
* @param phase The target phase
|
|
149
193
|
* @returns true if the system was found and updated, false otherwise
|
|
150
194
|
*/
|
|
151
|
-
updateSystemPhase(label:
|
|
195
|
+
updateSystemPhase(label: Labels, phase: SystemPhase): boolean;
|
|
152
196
|
/**
|
|
153
197
|
* The interpolation alpha between fixed update steps.
|
|
154
198
|
* Ranges from 0 to <1, representing how far into the next
|
|
@@ -164,64 +208,88 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
164
208
|
* Disable a system group. Systems in this group will be skipped during update().
|
|
165
209
|
* @param groupName The name of the group to disable
|
|
166
210
|
*/
|
|
167
|
-
disableSystemGroup(groupName:
|
|
211
|
+
disableSystemGroup(groupName: Groups): void;
|
|
168
212
|
/**
|
|
169
213
|
* Enable a system group. Systems in this group will run during update().
|
|
170
214
|
* @param groupName The name of the group to enable
|
|
171
215
|
*/
|
|
172
|
-
enableSystemGroup(groupName:
|
|
216
|
+
enableSystemGroup(groupName: Groups): void;
|
|
173
217
|
/**
|
|
174
218
|
* Check if a system group is enabled.
|
|
175
219
|
* @param groupName The name of the group to check
|
|
176
220
|
* @returns true if the group is enabled (or doesn't exist), false if disabled
|
|
177
221
|
*/
|
|
178
|
-
isSystemGroupEnabled(groupName:
|
|
222
|
+
isSystemGroupEnabled(groupName: Groups): boolean;
|
|
179
223
|
/**
|
|
180
224
|
* Get all system labels that belong to a specific group.
|
|
181
225
|
* @param groupName The name of the group
|
|
182
226
|
* @returns Array of system labels in the group
|
|
183
227
|
*/
|
|
184
|
-
getSystemsInGroup(groupName:
|
|
228
|
+
getSystemsInGroup(groupName: Groups): string[];
|
|
185
229
|
/**
|
|
186
230
|
* Remove a system by its label
|
|
187
231
|
* Calls the system's onDetach method with this ECSpresso instance if defined
|
|
188
232
|
* @param label The unique label of the system to remove
|
|
189
233
|
* @returns true if the system was found and removed, false otherwise
|
|
190
234
|
*/
|
|
191
|
-
removeSystem(label:
|
|
235
|
+
removeSystem(label: Labels): boolean;
|
|
192
236
|
/**
|
|
193
237
|
* Internal method to register a system with this ECSpresso instance
|
|
194
238
|
* @internal Used by SystemBuilder - replaces direct private property access
|
|
195
239
|
*/
|
|
196
|
-
_registerSystem(system: System<
|
|
240
|
+
_registerSystem(system: System<Cfg, any, any>): void;
|
|
197
241
|
/**
|
|
198
242
|
* Check if a resource exists
|
|
199
243
|
*/
|
|
200
|
-
hasResource<K extends keyof
|
|
244
|
+
hasResource<K extends keyof Cfg['resources']>(key: K): boolean;
|
|
201
245
|
/**
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
246
|
+
* Get a resource by key. Throws if the resource is not found.
|
|
247
|
+
* @param key The resource key
|
|
248
|
+
* @returns The resource value
|
|
249
|
+
* @throws Error if resource not found
|
|
250
|
+
* @see tryGetResource — the non-throwing alternative that returns undefined
|
|
251
|
+
*/
|
|
252
|
+
getResource<K extends keyof Cfg['resources']>(key: K): Cfg['resources'][K];
|
|
205
253
|
/**
|
|
206
|
-
|
|
254
|
+
* Try to get a resource by key. Returns undefined if the resource is not found.
|
|
255
|
+
* Inspired by Bevy's `World::get_resource::<T>()` which returns `Option<&T>`.
|
|
256
|
+
*
|
|
257
|
+
* Two overloads:
|
|
258
|
+
* 1. Known key — full type safety from `ResourceTypes`
|
|
259
|
+
* 2. String key with explicit type param — for cross-plugin optional dependencies
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* ```typescript
|
|
263
|
+
* // Known key (type inferred from ResourceTypes)
|
|
264
|
+
* const score = ecs.tryGetResource('score'); // ScoreResource | undefined
|
|
265
|
+
*
|
|
266
|
+
* // Cross-plugin optional dependency (caller specifies expected type)
|
|
267
|
+
* const si = ecs.tryGetResource<SpatialIndex>('spatialIndex') ?? null;
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
tryGetResource<K extends keyof Cfg['resources']>(key: K): Cfg['resources'][K] | undefined;
|
|
271
|
+
tryGetResource<T>(key: unknown extends T ? never : string): T | undefined;
|
|
272
|
+
/**
|
|
273
|
+
* Add a resource to the ECS instance.
|
|
274
|
+
*
|
|
275
|
+
* - Plain value → stored directly
|
|
276
|
+
* - Function → treated as a factory, called with this ECSpresso instance on first access
|
|
277
|
+
* - `{ factory, dependsOn?, onDispose? }` → factory with dependencies/disposal
|
|
278
|
+
* - `directValue(val)` → stores the value as-is (use to store functions/classes without invoking them)
|
|
207
279
|
*/
|
|
208
|
-
addResource<K extends keyof
|
|
209
|
-
dependsOn?: readonly string[];
|
|
210
|
-
factory: (ecs: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) => ResourceTypes[K] | Promise<ResourceTypes[K]>;
|
|
211
|
-
onDispose?: (resource: ResourceTypes[K], ecs?: ECSpresso<ComponentTypes, EventTypes, ResourceTypes>) => void | Promise<void>;
|
|
212
|
-
}): this;
|
|
280
|
+
addResource<K extends keyof Cfg['resources']>(key: K, resource: Cfg['resources'][K] | ((ecs: ECSpresso<Cfg>) => Cfg['resources'][K] | Promise<Cfg['resources'][K]>) | ResourceFactoryWithDeps<Cfg['resources'][K], ECSpresso<Cfg>, keyof Cfg['resources'] & string> | ResourceDirectValue<Cfg['resources'][K]>): this;
|
|
213
281
|
/**
|
|
214
282
|
* Remove a resource from the ECS instance (without calling onDispose)
|
|
215
283
|
* @param key The resource key to remove
|
|
216
284
|
* @returns True if the resource was removed, false if it didn't exist
|
|
217
285
|
*/
|
|
218
|
-
removeResource<K extends keyof
|
|
286
|
+
removeResource<K extends keyof Cfg['resources']>(key: K): boolean;
|
|
219
287
|
/**
|
|
220
288
|
* Dispose a single resource, calling its onDispose callback if defined
|
|
221
289
|
* @param key The resource key to dispose
|
|
222
290
|
* @returns True if the resource existed and was disposed, false if it didn't exist
|
|
223
291
|
*/
|
|
224
|
-
disposeResource<K extends keyof
|
|
292
|
+
disposeResource<K extends keyof Cfg['resources']>(key: K): Promise<boolean>;
|
|
225
293
|
/**
|
|
226
294
|
* Dispose all initialized resources in reverse dependency order.
|
|
227
295
|
* Resources that depend on others are disposed first.
|
|
@@ -235,34 +303,64 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
235
303
|
* @returns This ECSpresso instance for chaining
|
|
236
304
|
* @throws Error if the resource doesn't exist
|
|
237
305
|
*/
|
|
238
|
-
updateResource<K extends keyof
|
|
306
|
+
updateResource<K extends keyof Cfg['resources']>(key: K, updater: (current: Cfg['resources'][K]) => Cfg['resources'][K]): this;
|
|
239
307
|
/**
|
|
240
308
|
* Get all resource keys that are currently registered
|
|
241
309
|
* @returns Array of resource keys
|
|
242
310
|
*/
|
|
243
|
-
getResourceKeys(): Array<keyof
|
|
311
|
+
getResourceKeys(): Array<keyof Cfg['resources']>;
|
|
244
312
|
/**
|
|
245
313
|
* Check if a resource needs initialization (was added as a factory function)
|
|
246
314
|
* @param key The resource key to check
|
|
247
315
|
* @returns True if the resource needs initialization
|
|
248
316
|
*/
|
|
249
|
-
resourceNeedsInitialization<K extends keyof
|
|
317
|
+
resourceNeedsInitialization<K extends keyof Cfg['resources']>(key: K): boolean;
|
|
318
|
+
/**
|
|
319
|
+
* Get a component value from an entity.
|
|
320
|
+
* @param entityId The entity ID
|
|
321
|
+
* @param componentName The component to retrieve
|
|
322
|
+
* @returns The component value, or undefined if the entity doesn't have it
|
|
323
|
+
*/
|
|
324
|
+
getComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K): Cfg['components'][K] | undefined;
|
|
325
|
+
/**
|
|
326
|
+
* Add or replace a component on an entity.
|
|
327
|
+
* Triggers component-added callbacks and marks the component as changed.
|
|
328
|
+
* @param entityId The entity ID
|
|
329
|
+
* @param componentName The component to add
|
|
330
|
+
* @param value The component value
|
|
331
|
+
*/
|
|
332
|
+
addComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K, value: Cfg['components'][K]): void;
|
|
333
|
+
/**
|
|
334
|
+
* Add multiple components to an entity at once.
|
|
335
|
+
* @param entityId The entity ID
|
|
336
|
+
* @param components Object with component names as keys and component data as values
|
|
337
|
+
*/
|
|
338
|
+
addComponents<T extends {
|
|
339
|
+
[K in keyof Cfg['components']]?: Cfg['components'][K];
|
|
340
|
+
}>(entityId: number, components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>): void;
|
|
341
|
+
/**
|
|
342
|
+
* Remove a component from an entity.
|
|
343
|
+
* Triggers component-removed and dispose callbacks.
|
|
344
|
+
* @param entityId The entity ID
|
|
345
|
+
* @param componentName The component to remove
|
|
346
|
+
*/
|
|
347
|
+
removeComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K): void;
|
|
250
348
|
/**
|
|
251
349
|
* Check if an entity has a component
|
|
252
350
|
*/
|
|
253
|
-
hasComponent<K extends keyof
|
|
351
|
+
hasComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K): boolean;
|
|
254
352
|
/**
|
|
255
353
|
* Create an entity and add components to it in one call
|
|
256
354
|
* @param components Object with component names as keys and component data as values
|
|
257
355
|
* @returns The created entity with all components added
|
|
258
356
|
*/
|
|
259
357
|
spawn<T extends {
|
|
260
|
-
[K in keyof
|
|
261
|
-
}>(components: T & Record<Exclude<keyof T, keyof
|
|
358
|
+
[K in keyof Cfg['components']]?: Cfg['components'][K];
|
|
359
|
+
}>(components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>): FilteredEntity<Cfg['components'], keyof T & keyof Cfg['components']>;
|
|
262
360
|
/**
|
|
263
361
|
* Get all entities with specific components
|
|
264
362
|
*/
|
|
265
|
-
getEntitiesWithQuery<WithComponents extends keyof
|
|
363
|
+
getEntitiesWithQuery<WithComponents extends keyof Cfg['components'], WithoutComponents extends keyof Cfg['components'] = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>, changedComponents?: ReadonlyArray<keyof Cfg['components']>, parentHas?: ReadonlyArray<keyof Cfg['components']>): Array<FilteredEntity<Cfg['components'], WithComponents, WithoutComponents>>;
|
|
266
364
|
/**
|
|
267
365
|
* Get the single entity matching a query. Throws if zero or more than one match.
|
|
268
366
|
* @param withComponents Components the entity must have
|
|
@@ -270,7 +368,7 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
270
368
|
* @returns The single matching entity
|
|
271
369
|
* @throws If zero or more than one entity matches
|
|
272
370
|
*/
|
|
273
|
-
getSingleton<WithComponents extends keyof
|
|
371
|
+
getSingleton<WithComponents extends keyof Cfg['components'], WithoutComponents extends keyof Cfg['components'] = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>): FilteredEntity<Cfg['components'], WithComponents, WithoutComponents>;
|
|
274
372
|
/**
|
|
275
373
|
* Get the single entity matching a query, or undefined if none match.
|
|
276
374
|
* Throws if more than one entity matches.
|
|
@@ -279,14 +377,14 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
279
377
|
* @returns The single matching entity, or undefined if none match
|
|
280
378
|
* @throws If more than one entity matches
|
|
281
379
|
*/
|
|
282
|
-
tryGetSingleton<WithComponents extends keyof
|
|
380
|
+
tryGetSingleton<WithComponents extends keyof Cfg['components'], WithoutComponents extends keyof Cfg['components'] = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>): FilteredEntity<Cfg['components'], WithComponents, WithoutComponents> | undefined;
|
|
283
381
|
/**
|
|
284
382
|
* Remove an entity (and optionally its descendants)
|
|
285
|
-
* @param
|
|
383
|
+
* @param entityId Entity ID to remove
|
|
286
384
|
* @param options Options for removal (cascade: true by default)
|
|
287
385
|
* @returns true if entity was removed
|
|
288
386
|
*/
|
|
289
|
-
removeEntity(
|
|
387
|
+
removeEntity(entityId: number, options?: RemoveEntityOptions): boolean;
|
|
290
388
|
/**
|
|
291
389
|
* Create an entity as a child of another entity with initial components
|
|
292
390
|
* @param parentId The parent entity ID
|
|
@@ -294,81 +392,81 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
294
392
|
* @returns The created child entity
|
|
295
393
|
*/
|
|
296
394
|
spawnChild<T extends {
|
|
297
|
-
[K in keyof
|
|
298
|
-
}>(parentId: number, components: T & Record<Exclude<keyof T, keyof
|
|
395
|
+
[K in keyof Cfg['components']]?: Cfg['components'][K];
|
|
396
|
+
}>(parentId: number, components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>): FilteredEntity<Cfg['components'], keyof T & keyof Cfg['components']>;
|
|
299
397
|
/**
|
|
300
398
|
* Set the parent of an entity
|
|
301
|
-
* @param childId The entity to set as a child
|
|
302
|
-
* @param parentId The entity to set as the parent
|
|
399
|
+
* @param childId The entity ID to set as a child
|
|
400
|
+
* @param parentId The entity ID to set as the parent
|
|
303
401
|
*/
|
|
304
402
|
setParent(childId: number, parentId: number): this;
|
|
305
403
|
/**
|
|
306
404
|
* Remove the parent relationship for an entity (orphan it)
|
|
307
|
-
* @param childId The entity to orphan
|
|
405
|
+
* @param childId The entity ID to orphan
|
|
308
406
|
* @returns true if a parent was removed, false if entity had no parent
|
|
309
407
|
*/
|
|
310
408
|
removeParent(childId: number): boolean;
|
|
311
409
|
/**
|
|
312
410
|
* Get the parent of an entity
|
|
313
|
-
* @param entityId The entity to get the parent of
|
|
411
|
+
* @param entityId The entity ID to get the parent of
|
|
314
412
|
* @returns The parent entity ID, or null if no parent
|
|
315
413
|
*/
|
|
316
414
|
getParent(entityId: number): number | null;
|
|
317
415
|
/**
|
|
318
416
|
* Get all children of an entity in insertion order
|
|
319
|
-
* @param parentId The parent entity
|
|
417
|
+
* @param parentId The parent entity ID
|
|
320
418
|
* @returns Readonly array of child entity IDs
|
|
321
419
|
*/
|
|
322
420
|
getChildren(parentId: number): readonly number[];
|
|
323
421
|
/**
|
|
324
422
|
* Get a child at a specific index
|
|
325
|
-
* @param parentId The parent entity
|
|
423
|
+
* @param parentId The parent entity ID
|
|
326
424
|
* @param index The index of the child
|
|
327
425
|
* @returns The child entity ID, or null if index is out of bounds
|
|
328
426
|
*/
|
|
329
427
|
getChildAt(parentId: number, index: number): number | null;
|
|
330
428
|
/**
|
|
331
429
|
* Get the index of a child within its parent's children list
|
|
332
|
-
* @param parentId The parent entity
|
|
333
|
-
* @param childId The child entity to find
|
|
430
|
+
* @param parentId The parent entity ID
|
|
431
|
+
* @param childId The child entity ID to find
|
|
334
432
|
* @returns The index of the child, or -1 if not found
|
|
335
433
|
*/
|
|
336
434
|
getChildIndex(parentId: number, childId: number): number;
|
|
337
435
|
/**
|
|
338
436
|
* Get all ancestors of an entity in order [parent, grandparent, ...]
|
|
339
|
-
* @param entityId The entity to get ancestors of
|
|
437
|
+
* @param entityId The entity ID to get ancestors of
|
|
340
438
|
* @returns Readonly array of ancestor entity IDs
|
|
341
439
|
*/
|
|
342
440
|
getAncestors(entityId: number): readonly number[];
|
|
343
441
|
/**
|
|
344
442
|
* Get all descendants of an entity in depth-first order
|
|
345
|
-
* @param entityId The entity to get descendants of
|
|
443
|
+
* @param entityId The entity ID to get descendants of
|
|
346
444
|
* @returns Readonly array of descendant entity IDs
|
|
347
445
|
*/
|
|
348
446
|
getDescendants(entityId: number): readonly number[];
|
|
349
447
|
/**
|
|
350
448
|
* Get the root ancestor of an entity (topmost parent), or self if no parent
|
|
351
|
-
* @param entityId The entity to get the root of
|
|
449
|
+
* @param entityId The entity ID to get the root of
|
|
352
450
|
* @returns The root entity ID
|
|
353
451
|
*/
|
|
354
452
|
getRoot(entityId: number): number;
|
|
355
453
|
/**
|
|
356
454
|
* Get siblings of an entity (other children of the same parent)
|
|
357
|
-
* @param entityId The entity to get siblings of
|
|
455
|
+
* @param entityId The entity ID to get siblings of
|
|
358
456
|
* @returns Readonly array of sibling entity IDs
|
|
359
457
|
*/
|
|
360
458
|
getSiblings(entityId: number): readonly number[];
|
|
361
459
|
/**
|
|
362
460
|
* Check if an entity is a descendant of another entity
|
|
363
|
-
* @param entityId The potential descendant
|
|
364
|
-
* @param ancestorId The potential ancestor
|
|
461
|
+
* @param entityId The potential descendant ID
|
|
462
|
+
* @param ancestorId The potential ancestor ID
|
|
365
463
|
* @returns true if entityId is a descendant of ancestorId
|
|
366
464
|
*/
|
|
367
465
|
isDescendantOf(entityId: number, ancestorId: number): boolean;
|
|
368
466
|
/**
|
|
369
467
|
* Check if an entity is an ancestor of another entity
|
|
370
|
-
* @param entityId The potential ancestor
|
|
371
|
-
* @param descendantId The potential descendant
|
|
468
|
+
* @param entityId The potential ancestor ID
|
|
469
|
+
* @param descendantId The potential descendant ID
|
|
372
470
|
* @returns true if entityId is an ancestor of descendantId
|
|
373
471
|
*/
|
|
374
472
|
isAncestorOf(entityId: number, descendantId: number): boolean;
|
|
@@ -397,11 +495,11 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
397
495
|
*/
|
|
398
496
|
private _emitHierarchyChanged;
|
|
399
497
|
/**
|
|
400
|
-
* Get all installed
|
|
498
|
+
* Get all installed plugin IDs
|
|
401
499
|
*/
|
|
402
|
-
get
|
|
403
|
-
get entityManager(): EntityManager<
|
|
404
|
-
get eventBus(): EventBus<
|
|
500
|
+
get installedPlugins(): string[];
|
|
501
|
+
get entityManager(): EntityManager<Cfg["components"]>;
|
|
502
|
+
get eventBus(): EventBus<Cfg["events"]>;
|
|
405
503
|
/**
|
|
406
504
|
* Command buffer for queuing deferred structural changes.
|
|
407
505
|
* Commands are executed automatically at the end of each update() cycle.
|
|
@@ -413,7 +511,7 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
413
511
|
* ecs.commands.spawn({ position: { x: 0, y: 0 } });
|
|
414
512
|
* ```
|
|
415
513
|
*/
|
|
416
|
-
get commands(): CommandBuffer<
|
|
514
|
+
get commands(): CommandBuffer<Cfg>;
|
|
417
515
|
/**
|
|
418
516
|
* The current tick number, incremented at the end of each update()
|
|
419
517
|
*/
|
|
@@ -425,6 +523,25 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
425
523
|
* Manual change detection should compare: getChangeSeq(...) > changeThreshold
|
|
426
524
|
*/
|
|
427
525
|
get changeThreshold(): number;
|
|
526
|
+
/**
|
|
527
|
+
* Toggle diagnostics timing collection. When enabled, system and phase
|
|
528
|
+
* timings are recorded each frame. When disabled, timing maps are cleared
|
|
529
|
+
* and no overhead is incurred.
|
|
530
|
+
*/
|
|
531
|
+
enableDiagnostics(enabled: boolean): void;
|
|
532
|
+
get diagnosticsEnabled(): boolean;
|
|
533
|
+
get systemTimings(): ReadonlyMap<string, number>;
|
|
534
|
+
get phaseTimings(): Readonly<Record<SystemPhase, number>>;
|
|
535
|
+
get entityCount(): number;
|
|
536
|
+
/**
|
|
537
|
+
* Mutate a component in place and automatically mark it as changed.
|
|
538
|
+
* Throws if the entity does not exist or does not have the component.
|
|
539
|
+
* @param entityId The entity ID
|
|
540
|
+
* @param componentName The component to mutate
|
|
541
|
+
* @param mutator A function that receives the component value for in-place mutation
|
|
542
|
+
* @returns The mutated component value
|
|
543
|
+
*/
|
|
544
|
+
mutateComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K, mutator: (value: Cfg['components'][K]) => void): Cfg['components'][K];
|
|
428
545
|
/**
|
|
429
546
|
* Mark a component as changed on an entity.
|
|
430
547
|
* Each call increments a global monotonic sequence; systems with changed
|
|
@@ -432,93 +549,130 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
432
549
|
* @param entityId The entity ID
|
|
433
550
|
* @param componentName The component that was changed
|
|
434
551
|
*/
|
|
435
|
-
markChanged<K extends keyof
|
|
552
|
+
markChanged<K extends keyof Cfg['components']>(entityId: number, componentName: K): void;
|
|
553
|
+
/**
|
|
554
|
+
* Register a dispose callback for a component type.
|
|
555
|
+
* Called when a component is removed (explicit removal, entity destruction, or replacement).
|
|
556
|
+
* Later registrations replace earlier ones for the same component type.
|
|
557
|
+
* @param componentName The component type to register disposal for
|
|
558
|
+
* @param callback Function receiving the component value being disposed and the entity ID
|
|
559
|
+
*/
|
|
560
|
+
registerDispose<K extends keyof Cfg['components']>(componentName: K, callback: (ctx: {
|
|
561
|
+
value: Cfg['components'][K];
|
|
562
|
+
entityId: number;
|
|
563
|
+
}) => void): void;
|
|
564
|
+
/**
|
|
565
|
+
* Register a required component relationship.
|
|
566
|
+
* When an entity gains `trigger`, the `required` component is auto-added
|
|
567
|
+
* (using `factory` for the default value) if not already present.
|
|
568
|
+
* Enforced at insertion time (spawn/addComponent) only — removal is unrestricted.
|
|
569
|
+
* @param trigger The component whose presence triggers auto-addition
|
|
570
|
+
* @param required The component to auto-add
|
|
571
|
+
* @param factory Function that creates the default value for the required component
|
|
572
|
+
*/
|
|
573
|
+
registerRequired<Trigger extends keyof Cfg['components'], Required extends keyof Cfg['components']>(trigger: Trigger, required: Required, factory: (triggerValue: Cfg['components'][Trigger]) => Cfg['components'][Required]): void;
|
|
574
|
+
/**
|
|
575
|
+
* Check for circular dependencies in the required components graph.
|
|
576
|
+
* @throws Error if adding trigger→newRequired would create a cycle
|
|
577
|
+
*/
|
|
578
|
+
private _checkRequiredCycle;
|
|
436
579
|
/**
|
|
437
580
|
* Register a callback when a specific component is added to any entity
|
|
438
581
|
* @param componentName The component key
|
|
439
582
|
* @param handler Function receiving the new component value and the entity
|
|
440
583
|
* @returns Unsubscribe function to remove the callback
|
|
441
584
|
*/
|
|
442
|
-
onComponentAdded<K extends keyof
|
|
585
|
+
onComponentAdded<K extends keyof Cfg['components']>(componentName: K, handler: (ctx: {
|
|
586
|
+
value: Cfg['components'][K];
|
|
587
|
+
entity: Entity<Cfg['components']>;
|
|
588
|
+
}) => void): () => void;
|
|
443
589
|
/**
|
|
444
590
|
* Register a callback when a specific component is removed from any entity
|
|
445
591
|
* @param componentName The component key
|
|
446
592
|
* @param handler Function receiving the old component value and the entity
|
|
447
593
|
* @returns Unsubscribe function to remove the callback
|
|
448
594
|
*/
|
|
449
|
-
onComponentRemoved<K extends keyof
|
|
595
|
+
onComponentRemoved<K extends keyof Cfg['components']>(componentName: K, handler: (ctx: {
|
|
596
|
+
value: Cfg['components'][K];
|
|
597
|
+
entity: Entity<Cfg['components']>;
|
|
598
|
+
}) => void): () => void;
|
|
450
599
|
/**
|
|
451
600
|
* Add a reactive query that triggers callbacks when entities enter/exit the query match.
|
|
452
601
|
* @param name Unique name for the query
|
|
453
602
|
* @param definition Query definition with with/without arrays and onEnter/onExit callbacks
|
|
454
603
|
*/
|
|
455
|
-
addReactiveQuery<WithComponents extends keyof
|
|
604
|
+
addReactiveQuery<WithComponents extends keyof Cfg['components'], WithoutComponents extends keyof Cfg['components'] = never, OptionalComponents extends keyof Cfg['components'] = never>(name: ReactiveQueryNames, definition: ReactiveQueryDefinition<Cfg['components'], WithComponents, WithoutComponents, OptionalComponents>): void;
|
|
456
605
|
/**
|
|
457
606
|
* Remove a reactive query by name.
|
|
458
607
|
* @param name Name of the query to remove
|
|
459
608
|
* @returns true if the query existed and was removed, false otherwise
|
|
460
609
|
*/
|
|
461
|
-
removeReactiveQuery(name:
|
|
610
|
+
removeReactiveQuery(name: ReactiveQueryNames): boolean;
|
|
462
611
|
/**
|
|
463
612
|
* Subscribe to an event (convenience wrapper for eventBus.subscribe)
|
|
464
613
|
* @param eventType The event type to subscribe to
|
|
465
614
|
* @param callback The callback to invoke when the event is published
|
|
466
615
|
* @returns An unsubscribe function
|
|
467
616
|
*/
|
|
468
|
-
on<E extends keyof
|
|
617
|
+
on<E extends keyof Cfg['events']>(eventType: E, callback: (data: Cfg['events'][E]) => void): () => void;
|
|
469
618
|
/**
|
|
470
619
|
* Unsubscribe from an event by callback reference (convenience wrapper for eventBus.unsubscribe)
|
|
471
620
|
* @param eventType The event type to unsubscribe from
|
|
472
621
|
* @param callback The callback to remove
|
|
473
622
|
* @returns true if the callback was found and removed, false otherwise
|
|
474
623
|
*/
|
|
475
|
-
off<E extends keyof
|
|
624
|
+
off<E extends keyof Cfg['events']>(eventType: E, callback: (data: Cfg['events'][E]) => void): boolean;
|
|
476
625
|
/**
|
|
477
626
|
* Register a hook that runs after all systems in update()
|
|
478
627
|
* @param callback The hook to call after all systems have processed
|
|
479
628
|
* @returns An unsubscribe function to remove the hook
|
|
480
629
|
*/
|
|
481
|
-
onPostUpdate(callback: (
|
|
630
|
+
onPostUpdate(callback: (ctx: {
|
|
631
|
+
ecs: ECSpresso<Cfg>;
|
|
632
|
+
dt: number;
|
|
633
|
+
}) => void): () => void;
|
|
634
|
+
private requireAssetManager;
|
|
482
635
|
/**
|
|
483
636
|
* Get a loaded asset by key. Throws if not loaded.
|
|
484
637
|
*/
|
|
485
|
-
getAsset<K extends keyof
|
|
638
|
+
getAsset<K extends keyof Cfg['assets']>(key: K): Cfg['assets'][K];
|
|
486
639
|
/**
|
|
487
640
|
* Get a loaded asset or undefined if not loaded
|
|
488
641
|
*/
|
|
489
|
-
|
|
642
|
+
tryGetAsset<K extends keyof Cfg['assets']>(key: K): Cfg['assets'][K] | undefined;
|
|
490
643
|
/**
|
|
491
644
|
* Get a handle to an asset with status information
|
|
492
645
|
*/
|
|
493
|
-
getAssetHandle<K extends keyof
|
|
646
|
+
getAssetHandle<K extends keyof Cfg['assets']>(key: K): AssetHandle<Cfg['assets'][K]>;
|
|
494
647
|
/**
|
|
495
648
|
* Check if an asset is loaded
|
|
496
649
|
*/
|
|
497
|
-
isAssetLoaded<K extends keyof
|
|
650
|
+
isAssetLoaded<K extends keyof Cfg['assets']>(key: K): boolean;
|
|
498
651
|
/**
|
|
499
652
|
* Load a single asset
|
|
500
653
|
*/
|
|
501
|
-
loadAsset<K extends keyof
|
|
654
|
+
loadAsset<K extends keyof Cfg['assets']>(key: K): Promise<Cfg['assets'][K]>;
|
|
502
655
|
/**
|
|
503
656
|
* Load all assets in a group
|
|
504
657
|
*/
|
|
505
|
-
loadAssetGroup(groupName:
|
|
658
|
+
loadAssetGroup(groupName: AssetGroupNames): Promise<void>;
|
|
506
659
|
/**
|
|
507
660
|
* Check if all assets in a group are loaded
|
|
508
661
|
*/
|
|
509
|
-
isAssetGroupLoaded(groupName:
|
|
662
|
+
isAssetGroupLoaded(groupName: AssetGroupNames): boolean;
|
|
510
663
|
/**
|
|
511
664
|
* Get the loading progress of a group (0-1)
|
|
512
665
|
*/
|
|
513
|
-
getAssetGroupProgress(groupName:
|
|
666
|
+
getAssetGroupProgress(groupName: AssetGroupNames): number;
|
|
667
|
+
private requireScreenManager;
|
|
514
668
|
/**
|
|
515
669
|
* Transition to a new screen, clearing the stack
|
|
516
670
|
*/
|
|
517
|
-
setScreen<K extends keyof
|
|
671
|
+
setScreen<K extends keyof Cfg['screens']>(name: K, config: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? C : never): Promise<void>;
|
|
518
672
|
/**
|
|
519
673
|
* Push a screen onto the stack (overlay)
|
|
520
674
|
*/
|
|
521
|
-
pushScreen<K extends keyof
|
|
675
|
+
pushScreen<K extends keyof Cfg['screens']>(name: K, config: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? C : never): Promise<void>;
|
|
522
676
|
/**
|
|
523
677
|
* Pop the current screen and return to the previous one
|
|
524
678
|
*/
|
|
@@ -526,164 +680,124 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = {},
|
|
|
526
680
|
/**
|
|
527
681
|
* Get the current screen name
|
|
528
682
|
*/
|
|
529
|
-
getCurrentScreen(): keyof
|
|
683
|
+
getCurrentScreen(): keyof Cfg['screens'] | null;
|
|
684
|
+
/**
|
|
685
|
+
* Get the current screen config (immutable), narrowed to a specific screen.
|
|
686
|
+
* Throws if the current screen doesn't match.
|
|
687
|
+
*/
|
|
688
|
+
getScreenConfig<K extends keyof Cfg['screens'] & string>(screen: K): Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never;
|
|
689
|
+
/**
|
|
690
|
+
* Get the current screen config (immutable).
|
|
691
|
+
* Returns a union of all possible config types.
|
|
692
|
+
*/
|
|
693
|
+
getScreenConfig(): {
|
|
694
|
+
[K in keyof Cfg['screens']]: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never;
|
|
695
|
+
}[keyof Cfg['screens']];
|
|
696
|
+
/**
|
|
697
|
+
* Get the current screen config narrowed to a specific screen, or undefined if not on that screen.
|
|
698
|
+
*/
|
|
699
|
+
tryGetScreenConfig<K extends keyof Cfg['screens'] & string>(screen: K): (Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never) | undefined;
|
|
700
|
+
/**
|
|
701
|
+
* Get the current screen config or undefined.
|
|
702
|
+
* Returns a union of all possible config types, or undefined.
|
|
703
|
+
*/
|
|
704
|
+
tryGetScreenConfig(): {
|
|
705
|
+
[K in keyof Cfg['screens']]: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never;
|
|
706
|
+
}[keyof Cfg['screens']] | undefined;
|
|
530
707
|
/**
|
|
531
|
-
* Get the current screen
|
|
708
|
+
* Get the current screen state (mutable), narrowed to a specific screen.
|
|
709
|
+
* Throws if the current screen doesn't match.
|
|
532
710
|
*/
|
|
533
|
-
|
|
711
|
+
getScreenState<K extends keyof Cfg['screens'] & string>(screen: K): Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never;
|
|
534
712
|
/**
|
|
535
|
-
* Get the current screen
|
|
713
|
+
* Get the current screen state (mutable).
|
|
714
|
+
* Returns a union of all possible state types.
|
|
536
715
|
*/
|
|
537
|
-
|
|
716
|
+
getScreenState(): {
|
|
717
|
+
[K in keyof Cfg['screens']]: Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never;
|
|
718
|
+
}[keyof Cfg['screens']];
|
|
538
719
|
/**
|
|
539
|
-
* Get the current screen state
|
|
720
|
+
* Get the current screen state narrowed to a specific screen, or undefined if not on that screen.
|
|
540
721
|
*/
|
|
541
|
-
|
|
722
|
+
tryGetScreenState<K extends keyof Cfg['screens'] & string>(screen: K): (Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never) | undefined;
|
|
542
723
|
/**
|
|
543
|
-
* Get the current screen state or
|
|
724
|
+
* Get the current screen state or undefined.
|
|
725
|
+
* Returns a union of all possible state types, or undefined.
|
|
544
726
|
*/
|
|
545
|
-
|
|
727
|
+
tryGetScreenState(): {
|
|
728
|
+
[K in keyof Cfg['screens']]: Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never;
|
|
729
|
+
}[keyof Cfg['screens']] | undefined;
|
|
546
730
|
/**
|
|
547
|
-
* Update the current screen state
|
|
731
|
+
* Update the current screen state, narrowed to a specific screen.
|
|
732
|
+
* Throws if the current screen doesn't match.
|
|
548
733
|
*/
|
|
549
|
-
updateScreenState<K extends keyof
|
|
734
|
+
updateScreenState<K extends keyof Cfg['screens'] & string>(screen: K, update: Partial<Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never> | ((current: Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never) => Partial<Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never>)): void;
|
|
735
|
+
/**
|
|
736
|
+
* Update the current screen state.
|
|
737
|
+
*/
|
|
738
|
+
updateScreenState<K extends keyof Cfg['screens']>(update: Partial<Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never> | ((current: Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never) => Partial<Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never>)): void;
|
|
550
739
|
/**
|
|
551
740
|
* Check if a screen is the current screen
|
|
552
741
|
*/
|
|
553
|
-
isCurrentScreen(screenName: keyof
|
|
742
|
+
isCurrentScreen(screenName: keyof Cfg['screens']): boolean;
|
|
554
743
|
/**
|
|
555
744
|
* Check if a screen is active (current or in stack)
|
|
556
745
|
*/
|
|
557
|
-
isScreenActive(screenName: keyof
|
|
746
|
+
isScreenActive(screenName: keyof Cfg['screens']): boolean;
|
|
558
747
|
/**
|
|
559
748
|
* Get the screen stack depth
|
|
560
749
|
*/
|
|
561
750
|
getScreenStackDepth(): number;
|
|
562
751
|
/**
|
|
563
|
-
* Internal method to set the asset manager
|
|
752
|
+
* Internal method to set the asset manager and drain pending plugin assets
|
|
564
753
|
* @internal Used by ECSpressoBuilder
|
|
565
754
|
*/
|
|
566
|
-
_setAssetManager(manager: AssetManager<
|
|
755
|
+
_setAssetManager(manager: AssetManager<Cfg['assets']>): void;
|
|
567
756
|
/**
|
|
568
|
-
* Internal method to set the screen manager
|
|
757
|
+
* Internal method to set the screen manager and drain pending plugin screens
|
|
569
758
|
* @internal Used by ECSpressoBuilder
|
|
570
759
|
*/
|
|
571
|
-
_setScreenManager(manager: ScreenManager<
|
|
760
|
+
_setScreenManager(manager: ScreenManager<Cfg['screens']>): void;
|
|
761
|
+
/** @internal */
|
|
762
|
+
_hasPendingPluginAssets(): boolean;
|
|
763
|
+
/** @internal */
|
|
764
|
+
_hasPendingPluginScreens(): boolean;
|
|
572
765
|
/**
|
|
573
766
|
* Internal method to set the fixed timestep interval
|
|
574
767
|
* @internal Used by ECSpressoBuilder
|
|
575
768
|
*/
|
|
576
769
|
_setFixedDt(dt: number): void;
|
|
577
770
|
/**
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
_installBundle<C extends Record<string, any>, E extends Record<string, any>, R extends Record<string, any>, A extends Record<string, unknown> = {}, S extends Record<string, ScreenDefinition<any, any>> = {}>(bundle: Bundle<C, E, R, A, S>): this;
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* Resource factory with optional dependencies and disposal callback
|
|
586
|
-
*/
|
|
587
|
-
type ResourceFactoryWithDeps<T> = {
|
|
588
|
-
dependsOn?: readonly string[];
|
|
589
|
-
factory: (context?: any) => T | Promise<T>;
|
|
590
|
-
onDispose?: (resource: T, context?: any) => void | Promise<void>;
|
|
591
|
-
};
|
|
592
|
-
/**
|
|
593
|
-
* Builder class for ECSpresso that provides fluent type-safe bundle installation.
|
|
594
|
-
* Handles type checking during build process to ensure type safety.
|
|
595
|
-
*/
|
|
596
|
-
export declare class ECSpressoBuilder<C extends Record<string, any> = {}, E extends Record<string, any> = {}, R extends Record<string, any> = {}, A extends Record<string, unknown> = {}, S extends Record<string, ScreenDefinition<any, any>> = {}> {
|
|
597
|
-
/** The ECSpresso instance being built*/
|
|
598
|
-
private ecspresso;
|
|
599
|
-
/** Asset configurator for collecting asset definitions */
|
|
600
|
-
private assetConfigurator;
|
|
601
|
-
/** Screen configurator for collecting screen definitions */
|
|
602
|
-
private screenConfigurator;
|
|
603
|
-
/** Pending resources to add during build */
|
|
604
|
-
private pendingResources;
|
|
605
|
-
/** Fixed timestep interval (null means use default 1/60) */
|
|
606
|
-
private _fixedDt;
|
|
607
|
-
constructor();
|
|
608
|
-
/**
|
|
609
|
-
* Add the first bundle when starting with empty types.
|
|
610
|
-
* This overload allows any bundle to be added to an empty ECSpresso instance.
|
|
611
|
-
*/
|
|
612
|
-
withBundle<BC extends Record<string, any>, BE extends Record<string, any>, BR extends Record<string, any>>(this: ECSpressoBuilder<{}, {}, {}, A, S>, bundle: Bundle<BC, BE, BR>): ECSpressoBuilder<BC, BE, BR, A, S>;
|
|
771
|
+
* Register an asset definition for deferred registration.
|
|
772
|
+
* @internal Used by plugins that need to register assets
|
|
773
|
+
*/
|
|
774
|
+
_registerAsset(key: string, definition: AssetDefinition<unknown>): void;
|
|
613
775
|
/**
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
776
|
+
* Register a screen definition for deferred registration.
|
|
777
|
+
* @internal Used by plugins that need to register screens
|
|
778
|
+
*/
|
|
779
|
+
_registerScreen(name: string, definition: ScreenDefinition<any, any>): void;
|
|
618
780
|
/**
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
* @param resource The resource value, factory function, or factory with dependencies/disposal
|
|
622
|
-
* @returns This builder with updated resource types
|
|
623
|
-
*
|
|
624
|
-
* @example
|
|
625
|
-
* ```typescript
|
|
626
|
-
* ECSpresso.create<Components, Events, Resources>()
|
|
627
|
-
* .withResource('config', { debug: true })
|
|
628
|
-
* .withResource('counter', () => 42)
|
|
629
|
-
* .withResource('derived', {
|
|
630
|
-
* dependsOn: ['base'],
|
|
631
|
-
* factory: (ecs) => ecs.getResource('base') * 2,
|
|
632
|
-
* onDispose: (value) => console.log('Disposed:', value)
|
|
633
|
-
* })
|
|
634
|
-
* .build();
|
|
635
|
-
* ```
|
|
781
|
+
* Install a plugin into this ECSpresso instance.
|
|
782
|
+
* Deduplicates by plugin ID. Composite plugins call this in their install function.
|
|
636
783
|
*/
|
|
637
|
-
|
|
784
|
+
installPlugin(plugin: Plugin<any, any, any, any, any, any>): this;
|
|
638
785
|
/**
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
* @returns This builder with updated asset types
|
|
642
|
-
*
|
|
643
|
-
* @example
|
|
644
|
-
* ```typescript
|
|
645
|
-
* ECSpresso.create<Components, Events, Resources>()
|
|
646
|
-
* .withAssets(assets => assets
|
|
647
|
-
* .add('playerSprite', () => loadTexture('player.png'))
|
|
648
|
-
* .addGroup('level1', {
|
|
649
|
-
* background: () => loadTexture('level1-bg.png'),
|
|
650
|
-
* music: () => loadAudio('level1.mp3'),
|
|
651
|
-
* })
|
|
652
|
-
* )
|
|
653
|
-
* .build();
|
|
654
|
-
* ```
|
|
786
|
+
* Create a plugin factory from the built world's types.
|
|
787
|
+
* Returns a definePlugin equivalent with no manual type parameters.
|
|
655
788
|
*/
|
|
656
|
-
|
|
789
|
+
pluginFactory(): <PL extends string = never, PG extends string = never, PAG extends string = never, PRQ extends string = never>(config: {
|
|
790
|
+
id: string;
|
|
791
|
+
install: (world: ECSpresso<Cfg>) => void;
|
|
792
|
+
}) => Plugin<Cfg, EmptyConfig, PL, PG, PAG, PRQ>;
|
|
657
793
|
/**
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
* @returns This builder with updated screen types
|
|
794
|
+
* Call a helper factory with this world instance, inferring the full world type.
|
|
795
|
+
* Eliminates the need for a separate `type ECS = typeof ecs` ceremony.
|
|
661
796
|
*
|
|
662
797
|
* @example
|
|
663
798
|
* ```typescript
|
|
664
|
-
*
|
|
665
|
-
* .withScreens(screens => screens
|
|
666
|
-
* .add('loading', {
|
|
667
|
-
* initialState: () => ({ progress: 0 }),
|
|
668
|
-
* })
|
|
669
|
-
* .add('gameplay', {
|
|
670
|
-
* initialState: ({ level }) => ({ score: 0, level }),
|
|
671
|
-
* requiredAssetGroups: ['level1'],
|
|
672
|
-
* })
|
|
673
|
-
* )
|
|
674
|
-
* .build();
|
|
799
|
+
* const helpers = ecs.getHelpers(createStateMachineHelpers);
|
|
675
800
|
* ```
|
|
676
801
|
*/
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* Configure the fixed timestep interval for the fixedUpdate phase.
|
|
680
|
-
* @param dt The fixed timestep in seconds (e.g., 1/60 for 60Hz physics)
|
|
681
|
-
* @returns This builder for method chaining
|
|
682
|
-
*/
|
|
683
|
-
withFixedTimestep(dt: number): this;
|
|
684
|
-
/**
|
|
685
|
-
* Complete the build process and return the built ECSpresso instance
|
|
686
|
-
*/
|
|
687
|
-
build(): ECSpresso<C, E, R, A, S>;
|
|
802
|
+
getHelpers<H>(factory: (world: this) => H): H;
|
|
688
803
|
}
|
|
689
|
-
export {};
|