@zylem/game-lib 0.6.0 → 0.6.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,774 @@
1
+ import { Vector3, Vector2, Color, Material, BufferGeometry, Mesh, Group, ShaderMaterial } from 'three';
2
+ import RAPIER__default, { Vector3 as Vector3$1, RigidBodyDesc, ColliderDesc, RigidBody, Collider, World } from '@dimforge/rapier3d-compat';
3
+ import { E as Entity } from './entity-Bq_eNEDI.js';
4
+ import { IWorld, IComponent } from 'bitecs';
5
+ import * as mitt from 'mitt';
6
+
7
+ /**
8
+ * BehaviorSystem Interface
9
+ *
10
+ * Base interface for ECS-based behavior systems that run at the stage level.
11
+ * Systems query entities with matching components and process them each frame.
12
+ */
13
+
14
+ /**
15
+ * A behavior system that processes entities with specific components.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * class ThrusterMovementSystem implements BehaviorSystem {
20
+ * update(ecs: IWorld, delta: number): void {
21
+ * // Query and process entities with thruster components
22
+ * }
23
+ * }
24
+ * ```
25
+ */
26
+ interface BehaviorSystem {
27
+ /** Called once per frame with ECS world and delta time */
28
+ update(ecs: IWorld, delta: number): void;
29
+ /** Optional cleanup when stage is destroyed */
30
+ destroy?(ecs: IWorld): void;
31
+ }
32
+ /**
33
+ * Factory function that creates a BehaviorSystem.
34
+ * Receives the stage for access to world, scene, etc.
35
+ */
36
+ type BehaviorSystemFactory<T extends BehaviorSystem = BehaviorSystem> = (stage: {
37
+ world: any;
38
+ ecs: IWorld;
39
+ }) => T;
40
+
41
+ /**
42
+ * BehaviorDescriptor
43
+ *
44
+ * Type-safe behavior descriptors that provide options inference.
45
+ * Used with entity.use() to declaratively attach behaviors to entities.
46
+ *
47
+ * Each behavior can define its own handle type via `createHandle`,
48
+ * providing behavior-specific methods with full type safety.
49
+ */
50
+
51
+ /**
52
+ * Base handle returned by entity.use() for lazy access to behavior runtime.
53
+ * FSM is null until entity is spawned and components are initialized.
54
+ */
55
+ interface BaseBehaviorHandle<O extends Record<string, any> = Record<string, any>> {
56
+ /** Get the FSM instance (null until entity is spawned) */
57
+ getFSM(): any | null;
58
+ /** Get the current options */
59
+ getOptions(): O;
60
+ /** Access the underlying behavior ref */
61
+ readonly ref: BehaviorRef<O>;
62
+ }
63
+ /**
64
+ * Reference to a behavior stored on an entity
65
+ */
66
+ interface BehaviorRef<O extends Record<string, any> = Record<string, any>> {
67
+ /** The behavior descriptor */
68
+ descriptor: BehaviorDescriptor<O, any>;
69
+ /** Merged options (defaults + overrides) */
70
+ options: O;
71
+ /** Optional FSM instance - set lazily when entity is spawned */
72
+ fsm?: any;
73
+ }
74
+ /**
75
+ * A typed behavior descriptor that associates a symbol key with:
76
+ * - Default options (providing type inference)
77
+ * - A system factory to create the behavior system
78
+ * - An optional handle factory for behavior-specific methods
79
+ */
80
+ interface BehaviorDescriptor<O extends Record<string, any> = Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown> {
81
+ /** Unique symbol identifying this behavior */
82
+ readonly key: symbol;
83
+ /** Default options (used for type inference) */
84
+ readonly defaultOptions: O;
85
+ /** Factory to create the behavior system */
86
+ readonly systemFactory: BehaviorSystemFactory;
87
+ /**
88
+ * Optional factory to create behavior-specific handle methods.
89
+ * These methods are merged into the handle returned by entity.use().
90
+ */
91
+ readonly createHandle?: (ref: BehaviorRef<O>) => H;
92
+ }
93
+ /**
94
+ * The full handle type returned by entity.use().
95
+ * Combines base handle with behavior-specific methods.
96
+ */
97
+ type BehaviorHandle<O extends Record<string, any> = Record<string, any>, H extends Record<string, any> = Record<string, never>> = BaseBehaviorHandle<O> & H;
98
+ /**
99
+ * Configuration for defining a new behavior
100
+ */
101
+ interface DefineBehaviorConfig<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown> {
102
+ /** Human-readable name for debugging */
103
+ name: string;
104
+ /** Default options - these define the type */
105
+ defaultOptions: O;
106
+ /** Factory function to create the system */
107
+ systemFactory: BehaviorSystemFactory;
108
+ /**
109
+ * Optional factory to create behavior-specific handle methods.
110
+ * The returned object is merged into the handle returned by entity.use().
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * createHandle: (ref) => ({
115
+ * getLastHits: () => ref.fsm?.getLastHits() ?? null,
116
+ * getMovement: (moveX, moveY) => ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },
117
+ * }),
118
+ * ```
119
+ */
120
+ createHandle?: (ref: BehaviorRef<O>) => H;
121
+ }
122
+ /**
123
+ * Define a typed behavior descriptor.
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * export const WorldBoundary2DBehavior = defineBehavior({
128
+ * name: 'world-boundary-2d',
129
+ * defaultOptions: { boundaries: { top: 0, bottom: 0, left: 0, right: 0 } },
130
+ * systemFactory: (ctx) => new WorldBoundary2DSystem(ctx.world),
131
+ * createHandle: (ref) => ({
132
+ * getLastHits: () => ref.fsm?.getLastHits() ?? null,
133
+ * getMovement: (moveX: number, moveY: number) =>
134
+ * ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },
135
+ * }),
136
+ * });
137
+ *
138
+ * // Usage - handle has getLastHits and getMovement with full types
139
+ * const boundary = ship.use(WorldBoundary2DBehavior, { ... });
140
+ * const hits = boundary.getLastHits(); // Fully typed!
141
+ * ```
142
+ */
143
+ declare function defineBehavior<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown>(config: DefineBehaviorConfig<O, H, I>): BehaviorDescriptor<O, H, I>;
144
+
145
+ type Vec3 = Vector3 | Vector3$1;
146
+
147
+ declare function shortHash(objString: string): string;
148
+
149
+ type ZylemShaderObject = {
150
+ fragment: string;
151
+ vertex: string;
152
+ };
153
+ interface MaterialOptions {
154
+ path?: string;
155
+ repeat?: Vector2;
156
+ shader?: ZylemShaderObject;
157
+ color?: Color;
158
+ }
159
+ type BatchGeometryMap = Map<symbol, number>;
160
+ interface BatchMaterialMapObject {
161
+ geometryMap: BatchGeometryMap;
162
+ material: Material;
163
+ }
164
+ type BatchKey = ReturnType<typeof shortHash>;
165
+ type TexturePath = string | null;
166
+ declare class MaterialBuilder {
167
+ static batchMaterialMap: Map<BatchKey, BatchMaterialMapObject>;
168
+ materials: Material[];
169
+ batchMaterial(options: Partial<MaterialOptions>, entityType: symbol): void;
170
+ build(options: Partial<MaterialOptions>, entityType: symbol): void;
171
+ withColor(color: Color): this;
172
+ withShader(shader: ZylemShaderObject): this;
173
+ /**
174
+ * Set texture - loads in background (deferred).
175
+ * Material is created immediately with null map, texture applies when loaded.
176
+ */
177
+ setTexture(texturePath?: TexturePath, repeat?: Vector2): void;
178
+ setColor(color: Color): void;
179
+ setShader(customShader: ZylemShaderObject): void;
180
+ }
181
+
182
+ /**
183
+ * Options for configuring entity collision behavior.
184
+ */
185
+ interface CollisionOptions {
186
+ static?: boolean;
187
+ sensor?: boolean;
188
+ size?: Vector3$1;
189
+ position?: Vector3$1;
190
+ collisionType?: string;
191
+ collisionFilter?: string[];
192
+ }
193
+ declare class CollisionBuilder {
194
+ static: boolean;
195
+ sensor: boolean;
196
+ gravity: Vec3;
197
+ build(options: Partial<CollisionOptions>): [RigidBodyDesc, ColliderDesc];
198
+ withCollision(collisionOptions: Partial<CollisionOptions>): this;
199
+ collider(options: CollisionOptions): ColliderDesc;
200
+ bodyDesc({ isDynamicBody }: {
201
+ isDynamicBody?: boolean | undefined;
202
+ }): RigidBodyDesc;
203
+ }
204
+
205
+ /** Input
206
+ *
207
+ * Maximum number of local players is 8.
208
+ * All input can be mapped to a gamepad or keyboard but shares the common
209
+ * interface represented as a gamepad.
210
+ */
211
+ type InputPlayerNumber = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
212
+ type InputPlayer = `p${InputPlayerNumber}`;
213
+ interface ButtonState {
214
+ pressed: boolean;
215
+ released: boolean;
216
+ held: number;
217
+ }
218
+ interface AnalogState {
219
+ value: number;
220
+ held: number;
221
+ }
222
+ interface InputGamepad {
223
+ playerNumber: InputPlayerNumber;
224
+ buttons: {
225
+ A: ButtonState;
226
+ B: ButtonState;
227
+ X: ButtonState;
228
+ Y: ButtonState;
229
+ Start: ButtonState;
230
+ Select: ButtonState;
231
+ L: ButtonState;
232
+ R: ButtonState;
233
+ };
234
+ directions: {
235
+ Up: ButtonState;
236
+ Down: ButtonState;
237
+ Left: ButtonState;
238
+ Right: ButtonState;
239
+ };
240
+ shoulders: {
241
+ LTrigger: ButtonState;
242
+ RTrigger: ButtonState;
243
+ };
244
+ axes: {
245
+ Horizontal: AnalogState;
246
+ Vertical: AnalogState;
247
+ };
248
+ }
249
+ type Inputs = Record<InputPlayer, InputGamepad>;
250
+
251
+ type LoadingEvent = {
252
+ type: 'start' | 'progress' | 'complete';
253
+ message?: string;
254
+ progress?: number;
255
+ total?: number;
256
+ current?: number;
257
+ };
258
+ interface IGame<TGlobals extends Record<string, unknown> = any> {
259
+ start: () => Promise<this>;
260
+ nextStage: () => void;
261
+ previousStage: () => void;
262
+ reset: () => Promise<void>;
263
+ pause: () => Promise<void>;
264
+ resume: () => Promise<void>;
265
+ onLoading: (callback: (event: LoadingEvent) => void) => void;
266
+ loadStageFromId: (stageId: string) => Promise<void>;
267
+ end: () => Promise<void>;
268
+ goToStage: () => void;
269
+ }
270
+ interface IStage {
271
+ onUpdate: (callback: UpdateFunction<IStage>) => void;
272
+ onSetup: (callback: SetupFunction<IStage>) => void;
273
+ onDestroy: (callback: DestroyFunction<IStage>) => void;
274
+ }
275
+ interface ICamera {
276
+ move: (position: Vector3) => void;
277
+ rotate: (pitch: number, yaw: number, roll: number) => void;
278
+ }
279
+
280
+ type GlobalRecord = Record<string, unknown>;
281
+ /** Setup */
282
+ interface SetupContext<T, TGlobals extends GlobalRecord = any> {
283
+ me: T;
284
+ globals: TGlobals;
285
+ inputs?: Inputs;
286
+ camera?: ICamera;
287
+ stage?: IStage;
288
+ game?: IGame<TGlobals>;
289
+ }
290
+ interface SetupFunction<T, TGlobals extends GlobalRecord = any> {
291
+ (context: SetupContext<T, TGlobals>): void;
292
+ }
293
+ /** Loaded */
294
+ interface LoadedContext<T, TGlobals extends GlobalRecord = any> {
295
+ me: T;
296
+ globals: TGlobals;
297
+ }
298
+ interface LoadedFunction<T, TGlobals extends GlobalRecord = any> {
299
+ (context: LoadedContext<T, TGlobals>): void;
300
+ }
301
+ /** Update */
302
+ type UpdateContext<T, TGlobals extends GlobalRecord = any> = {
303
+ me: T;
304
+ delta: number;
305
+ inputs: Inputs;
306
+ globals: TGlobals;
307
+ camera: ICamera;
308
+ stage?: IStage;
309
+ game?: IGame<TGlobals>;
310
+ };
311
+ interface UpdateFunction<T, TGlobals extends GlobalRecord = any> {
312
+ (context: UpdateContext<T, TGlobals>): void;
313
+ }
314
+ /** Destroy */
315
+ interface DestroyContext<T, TGlobals extends GlobalRecord = any> {
316
+ me: T;
317
+ globals: TGlobals;
318
+ }
319
+ interface DestroyFunction<T, TGlobals extends GlobalRecord = any> {
320
+ (context: DestroyContext<T, TGlobals>): void;
321
+ }
322
+ /** Cleanup */
323
+ interface CleanupContext<T, TGlobals extends GlobalRecord = any> {
324
+ me: T;
325
+ globals: TGlobals;
326
+ }
327
+ interface CleanupFunction<T, TGlobals extends GlobalRecord = any> {
328
+ (context: CleanupContext<T, TGlobals>): void;
329
+ }
330
+
331
+ interface NodeInterface {
332
+ uuid: string;
333
+ name: string;
334
+ markedForRemoval: boolean;
335
+ nodeSetup(params: SetupContext<any>): void;
336
+ nodeUpdate(params: UpdateContext<any>): void;
337
+ nodeDestroy(params: DestroyContext<any>): void;
338
+ setParent(parent: NodeInterface | null): void;
339
+ getParent(): NodeInterface | null;
340
+ }
341
+
342
+ type BaseNodeOptions<T = any> = BaseNode | Partial<T>;
343
+ /**
344
+ * Lifecycle callback arrays - each lifecycle event can have multiple callbacks
345
+ * that execute in order.
346
+ */
347
+ interface LifecycleCallbacks<T> {
348
+ setup: Array<SetupFunction<T>>;
349
+ loaded: Array<LoadedFunction<T>>;
350
+ update: Array<UpdateFunction<T>>;
351
+ destroy: Array<DestroyFunction<T>>;
352
+ cleanup: Array<CleanupFunction<T>>;
353
+ }
354
+ declare abstract class BaseNode<Options = any, T = any> implements NodeInterface {
355
+ protected parent: NodeInterface | null;
356
+ protected children: NodeInterface[];
357
+ options: Options;
358
+ eid: number;
359
+ uuid: string;
360
+ name: string;
361
+ markedForRemoval: boolean;
362
+ /**
363
+ * Lifecycle callback arrays - use onSetup(), onUpdate(), etc. to add callbacks
364
+ */
365
+ protected lifecycleCallbacks: LifecycleCallbacks<this>;
366
+ constructor(args?: BaseNodeOptions[]);
367
+ /**
368
+ * Add setup callbacks to be executed in order during nodeSetup
369
+ */
370
+ onSetup(...callbacks: Array<SetupFunction<this>>): this;
371
+ /**
372
+ * Add loaded callbacks to be executed in order during nodeLoaded
373
+ */
374
+ onLoaded(...callbacks: Array<LoadedFunction<this>>): this;
375
+ /**
376
+ * Add update callbacks to be executed in order during nodeUpdate
377
+ */
378
+ onUpdate(...callbacks: Array<UpdateFunction<this>>): this;
379
+ /**
380
+ * Add destroy callbacks to be executed in order during nodeDestroy
381
+ */
382
+ onDestroy(...callbacks: Array<DestroyFunction<this>>): this;
383
+ /**
384
+ * Add cleanup callbacks to be executed in order during nodeCleanup
385
+ */
386
+ onCleanup(...callbacks: Array<CleanupFunction<this>>): this;
387
+ /**
388
+ * Prepend setup callbacks (run before existing ones)
389
+ */
390
+ prependSetup(...callbacks: Array<SetupFunction<this>>): this;
391
+ /**
392
+ * Prepend update callbacks (run before existing ones)
393
+ */
394
+ prependUpdate(...callbacks: Array<UpdateFunction<this>>): this;
395
+ setParent(parent: NodeInterface | null): void;
396
+ getParent(): NodeInterface | null;
397
+ add(baseNode: NodeInterface): void;
398
+ remove(baseNode: NodeInterface): void;
399
+ getChildren(): NodeInterface[];
400
+ isComposite(): boolean;
401
+ abstract create(): T;
402
+ protected abstract _setup(params: SetupContext<this>): void;
403
+ protected abstract _loaded(params: LoadedContext<this>): Promise<void>;
404
+ protected abstract _update(params: UpdateContext<this>): void;
405
+ protected abstract _destroy(params: DestroyContext<this>): void;
406
+ protected abstract _cleanup(params: CleanupContext<this>): Promise<void>;
407
+ nodeSetup(params: SetupContext<this>): void;
408
+ nodeUpdate(params: UpdateContext<this>): void;
409
+ nodeDestroy(params: DestroyContext<this>): void;
410
+ nodeLoaded(params: LoadedContext<this>): Promise<void>;
411
+ nodeCleanup(params: CleanupContext<this>): Promise<void>;
412
+ getOptions(): Options;
413
+ setOptions(options: Partial<Options>): void;
414
+ }
415
+
416
+ /**
417
+ * TODO: allow for multiple materials requires geometry groups
418
+ * TODO: allow for instanced uniforms
419
+ * TODO: allow for geometry groups
420
+ * TODO: allow for batched meshes
421
+ * import { InstancedUniformsMesh } from 'three-instanced-uniforms-mesh';
422
+ * may not need geometry groups for shaders though
423
+ * setGeometry<T extends BufferGeometry>(geometry: T) {
424
+ * MeshBuilder.bachedMesh = new BatchedMesh(10, 5000, 10000, material);
425
+ * }
426
+ */
427
+ type MeshBuilderOptions = Partial<Pick<GameEntityOptions, 'batched' | 'material'>>;
428
+ declare class MeshBuilder {
429
+ _build(meshOptions: MeshBuilderOptions, geometry: BufferGeometry, materials: Material[]): Mesh;
430
+ _postBuild(): void;
431
+ }
432
+
433
+ declare abstract class EntityCollisionBuilder extends CollisionBuilder {
434
+ abstract collider(options: GameEntityOptions): ColliderDesc;
435
+ }
436
+ declare abstract class EntityMeshBuilder extends MeshBuilder {
437
+ build(options: GameEntityOptions): BufferGeometry;
438
+ postBuild(): void;
439
+ }
440
+
441
+ interface Behavior {
442
+ component: IComponent;
443
+ values: any;
444
+ }
445
+
446
+ /**
447
+ * Reusable delegate for event emission and subscription.
448
+ * Use via composition in Game, Stage, and Entity classes.
449
+ *
450
+ * @example
451
+ * class Game {
452
+ * private eventDelegate = new EventEmitterDelegate<GameEvents>();
453
+ *
454
+ * dispatch<K extends keyof GameEvents>(event: K, payload: GameEvents[K]) {
455
+ * this.eventDelegate.dispatch(event, payload);
456
+ * }
457
+ * }
458
+ */
459
+ declare class EventEmitterDelegate<TEvents extends Record<string, unknown>> {
460
+ private emitter;
461
+ private unsubscribes;
462
+ constructor();
463
+ /**
464
+ * Dispatch an event to all listeners.
465
+ */
466
+ dispatch<K extends keyof TEvents>(event: K, payload: TEvents[K]): void;
467
+ /**
468
+ * Subscribe to an event. Returns an unsubscribe function.
469
+ */
470
+ listen<K extends keyof TEvents>(event: K, handler: (payload: TEvents[K]) => void): () => void;
471
+ /**
472
+ * Subscribe to all events.
473
+ */
474
+ listenAll(handler: (type: keyof TEvents, payload: TEvents[keyof TEvents]) => void): () => void;
475
+ /**
476
+ * Clean up all subscriptions.
477
+ */
478
+ dispose(): void;
479
+ }
480
+
481
+ /**
482
+ * Payload for game loading events with stage context.
483
+ */
484
+ interface GameLoadingPayload extends LoadingEvent {
485
+ stageName?: string;
486
+ stageIndex?: number;
487
+ }
488
+ /** Payload for stage configuration sent to editor. */
489
+ interface StageConfigPayload {
490
+ id: string;
491
+ backgroundColor: string;
492
+ backgroundImage: string | null;
493
+ gravity: {
494
+ x: number;
495
+ y: number;
496
+ z: number;
497
+ };
498
+ inputs: Record<string, string[]>;
499
+ variables: Record<string, unknown>;
500
+ }
501
+ /** Payload for entity configuration sent to editor. */
502
+ interface EntityConfigPayload {
503
+ uuid: string;
504
+ name: string;
505
+ type: string;
506
+ position: {
507
+ x: number;
508
+ y: number;
509
+ z: number;
510
+ };
511
+ rotation: {
512
+ x: number;
513
+ y: number;
514
+ z: number;
515
+ };
516
+ scale: {
517
+ x: number;
518
+ y: number;
519
+ z: number;
520
+ };
521
+ }
522
+ /** Payload for state dispatch events from game to editor. */
523
+ interface StateDispatchPayload {
524
+ scope: 'game' | 'stage' | 'entity';
525
+ path: string;
526
+ value: unknown;
527
+ previousValue?: unknown;
528
+ config?: {
529
+ id: string;
530
+ aspectRatio: number;
531
+ fullscreen: boolean;
532
+ bodyBackground: string | undefined;
533
+ internalResolution: {
534
+ width: number;
535
+ height: number;
536
+ } | undefined;
537
+ debug: boolean;
538
+ } | null;
539
+ stageConfig?: StageConfigPayload | null;
540
+ entities?: EntityConfigPayload[] | null;
541
+ }
542
+ type GameEvents = {
543
+ 'loading:start': GameLoadingPayload;
544
+ 'loading:progress': GameLoadingPayload;
545
+ 'loading:complete': GameLoadingPayload;
546
+ 'paused': {
547
+ paused: boolean;
548
+ };
549
+ 'debug': {
550
+ enabled: boolean;
551
+ };
552
+ 'state:dispatch': StateDispatchPayload;
553
+ };
554
+ type StageEvents = {
555
+ 'stage:loaded': {
556
+ stageId: string;
557
+ };
558
+ 'stage:unloaded': {
559
+ stageId: string;
560
+ };
561
+ 'stage:variable:changed': {
562
+ key: string;
563
+ value: unknown;
564
+ };
565
+ };
566
+ type EntityEvents = {
567
+ 'entity:spawned': {
568
+ entityId: string;
569
+ name: string;
570
+ };
571
+ 'entity:destroyed': {
572
+ entityId: string;
573
+ };
574
+ 'entity:collision': {
575
+ entityId: string;
576
+ otherId: string;
577
+ };
578
+ 'entity:model:loading': {
579
+ entityId: string;
580
+ files: string[];
581
+ };
582
+ 'entity:model:loaded': {
583
+ entityId: string;
584
+ success: boolean;
585
+ meshCount?: number;
586
+ };
587
+ 'entity:animation:loaded': {
588
+ entityId: string;
589
+ animationCount: number;
590
+ };
591
+ };
592
+ type ZylemEvents = GameEvents & StageEvents & EntityEvents;
593
+ /**
594
+ * Global event bus for cross-package communication.
595
+ *
596
+ * Usage:
597
+ * ```ts
598
+ * import { zylemEventBus } from '@zylem/game-lib';
599
+ *
600
+ * // Subscribe
601
+ * const unsub = zylemEventBus.on('loading:progress', (e) => console.log(e));
602
+ *
603
+ * // Emit
604
+ * zylemEventBus.emit('loading:progress', { type: 'progress', progress: 0.5 });
605
+ *
606
+ * // Cleanup
607
+ * unsub();
608
+ * ```
609
+ */
610
+ declare const zylemEventBus: mitt.Emitter<ZylemEvents>;
611
+
612
+ interface CollisionContext<T, O extends GameEntityOptions, TGlobals extends Record<string, unknown> = any> {
613
+ entity: T;
614
+ other: GameEntity<O | any>;
615
+ globals: TGlobals;
616
+ }
617
+ type BehaviorContext<T, O extends GameEntityOptions> = SetupContext<T, O> | UpdateContext<T, O> | CollisionContext<T, O> | DestroyContext<T, O>;
618
+ type BehaviorCallback<T, O extends GameEntityOptions> = (params: BehaviorContext<T, O>) => void;
619
+ interface CollisionDelegate<T, O extends GameEntityOptions> {
620
+ collision?: ((params: CollisionContext<any, any>) => void)[];
621
+ }
622
+ type IBuilder<BuilderOptions = any> = {
623
+ preBuild: (options: BuilderOptions) => BuilderOptions;
624
+ build: (options: BuilderOptions) => BuilderOptions;
625
+ postBuild: (options: BuilderOptions) => BuilderOptions;
626
+ };
627
+ type GameEntityOptions = {
628
+ name?: string;
629
+ color?: Color;
630
+ size?: Vec3;
631
+ position?: Vec3;
632
+ batched?: boolean;
633
+ collision?: Partial<CollisionOptions>;
634
+ material?: Partial<MaterialOptions>;
635
+ custom?: {
636
+ [key: string]: any;
637
+ };
638
+ collisionType?: string;
639
+ collisionGroup?: string;
640
+ collisionFilter?: string[];
641
+ _builders?: {
642
+ meshBuilder?: IBuilder | EntityMeshBuilder | null;
643
+ collisionBuilder?: IBuilder | EntityCollisionBuilder | null;
644
+ materialBuilder?: MaterialBuilder | null;
645
+ };
646
+ };
647
+ declare abstract class GameEntityLifeCycle {
648
+ abstract _setup(params: SetupContext<this>): void;
649
+ abstract _update(params: UpdateContext<this>): void;
650
+ abstract _destroy(params: DestroyContext<this>): void;
651
+ }
652
+ interface EntityDebugInfo {
653
+ buildInfo: () => Record<string, string>;
654
+ }
655
+ type BehaviorCallbackType = 'setup' | 'update' | 'destroy' | 'collision';
656
+ declare class GameEntity<O extends GameEntityOptions> extends BaseNode<O> implements GameEntityLifeCycle, EntityDebugInfo {
657
+ behaviors: Behavior[];
658
+ group: Group | undefined;
659
+ mesh: Mesh | undefined;
660
+ materials: Material[] | undefined;
661
+ bodyDesc: RigidBodyDesc | null;
662
+ body: RigidBody | null;
663
+ colliderDesc: ColliderDesc | undefined;
664
+ collider: Collider | undefined;
665
+ custom: Record<string, any>;
666
+ debugInfo: Record<string, any>;
667
+ debugMaterial: ShaderMaterial | undefined;
668
+ collisionDelegate: CollisionDelegate<this, O>;
669
+ collisionType?: string;
670
+ /**
671
+ * @deprecated Use the new ECS-based behavior system instead.
672
+ * Use 'any' for callback types to avoid contravariance issues
673
+ * with function parameters. Type safety is enforced where callbacks are registered.
674
+ */
675
+ behaviorCallbackMap: Record<BehaviorCallbackType, BehaviorCallback<any, any>[]>;
676
+ protected eventDelegate: EventEmitterDelegate<EntityEvents>;
677
+ private behaviorRefs;
678
+ constructor();
679
+ create(): this;
680
+ /**
681
+ * Add collision callbacks
682
+ */
683
+ onCollision(...callbacks: ((params: CollisionContext<this, O>) => void)[]): this;
684
+ /**
685
+ * Use a behavior on this entity via typed descriptor.
686
+ * Behaviors will be auto-registered as systems when the entity is spawned.
687
+ * @param descriptor The behavior descriptor (import from behaviors module)
688
+ * @param options Optional overrides for the behavior's default options
689
+ * @returns BehaviorHandle with behavior-specific methods for lazy FSM access
690
+ */
691
+ use<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>>(descriptor: BehaviorDescriptor<O, H>, options?: Partial<O>): BehaviorHandle<O, H>;
692
+ /**
693
+ * Get all behavior references attached to this entity.
694
+ * Used by the stage to auto-register required systems.
695
+ */
696
+ getBehaviorRefs(): BehaviorRef[];
697
+ /**
698
+ * Entity-specific setup - runs behavior callbacks
699
+ * (User callbacks are handled by BaseNode's lifecycleCallbacks.setup)
700
+ */
701
+ _setup(params: SetupContext<this>): void;
702
+ protected _loaded(_params: LoadedContext<this>): Promise<void>;
703
+ /**
704
+ * Entity-specific update - updates materials and runs behavior callbacks
705
+ * (User callbacks are handled by BaseNode's lifecycleCallbacks.update)
706
+ */
707
+ _update(params: UpdateContext<this>): void;
708
+ /**
709
+ * Entity-specific destroy - runs behavior callbacks
710
+ * (User callbacks are handled by BaseNode's lifecycleCallbacks.destroy)
711
+ */
712
+ _destroy(params: DestroyContext<this>): void;
713
+ protected _cleanup(_params: CleanupContext<this>): Promise<void>;
714
+ _collision(other: GameEntity<O>, globals?: any): void;
715
+ /**
716
+ * @deprecated Use the new ECS-based behavior system instead.
717
+ * See `lib/behaviors/thruster/thruster-movement.behavior.ts` for an example.
718
+ */
719
+ addBehavior(behaviorCallback: {
720
+ type: BehaviorCallbackType;
721
+ handler: any;
722
+ }): this;
723
+ /**
724
+ * @deprecated Use the new ECS-based behavior system instead.
725
+ * See `lib/behaviors/thruster/thruster-movement.behavior.ts` for an example.
726
+ */
727
+ addBehaviors(behaviorCallbacks: {
728
+ type: BehaviorCallbackType;
729
+ handler: any;
730
+ }[]): this;
731
+ protected updateMaterials(params: any): void;
732
+ buildInfo(): Record<string, string>;
733
+ /**
734
+ * Dispatch an event from this entity.
735
+ * Events are emitted both locally and to the global event bus.
736
+ */
737
+ dispatch<K extends keyof EntityEvents>(event: K, payload: EntityEvents[K]): void;
738
+ /**
739
+ * Listen for events on this entity instance.
740
+ * @returns Unsubscribe function
741
+ */
742
+ listen<K extends keyof EntityEvents>(event: K, handler: (payload: EntityEvents[K]) => void): () => void;
743
+ /**
744
+ * Clean up entity event subscriptions.
745
+ */
746
+ disposeEvents(): void;
747
+ }
748
+
749
+ /**
750
+ * Interface for entities that handle collision events.
751
+ */
752
+ interface CollisionHandlerDelegate {
753
+ handlePostCollision(params: any): boolean;
754
+ handleIntersectionEvent(params: any): void;
755
+ }
756
+ declare class ZylemWorld implements Entity<ZylemWorld> {
757
+ type: string;
758
+ world: World;
759
+ collisionMap: Map<string, GameEntity<any>>;
760
+ collisionBehaviorMap: Map<string, GameEntity<any>>;
761
+ _removalMap: Map<string, GameEntity<any>>;
762
+ static loadPhysics(gravity: Vector3): Promise<RAPIER__default.World>;
763
+ constructor(world: World);
764
+ addEntity(entity: any): void;
765
+ setForRemoval(entity: any): void;
766
+ destroyEntity(entity: GameEntity<any>): void;
767
+ setup(): void;
768
+ update(params: UpdateContext<any>): void;
769
+ updatePostCollisionBehaviors(delta: number): void;
770
+ updateColliders(delta: number): void;
771
+ destroy(): void;
772
+ }
773
+
774
+ export { type CollisionHandlerDelegate as A, BaseNode as B, type CleanupContext as C, type DestroyFunction as D, EventEmitterDelegate as E, GameEntity as G, type InputGamepad as I, type LoadingEvent as L, type MaterialOptions as M, type SetupFunction as S, type TexturePath as T, type UpdateFunction as U, type Vec3 as V, type ZylemShaderObject as Z, type SetupContext as a, type UpdateContext as b, type DestroyContext as c, ZylemWorld as d, type BehaviorSystem as e, type BehaviorSystemFactory as f, type GameEntityOptions as g, type StageEvents as h, type ZylemEvents as i, type GameEvents as j, type EntityEvents as k, type GameLoadingPayload as l, type StateDispatchPayload as m, type StageConfigPayload as n, type EntityConfigPayload as o, defineBehavior as p, type BehaviorDescriptor as q, type BehaviorRef as r, type BehaviorHandle as s, type DefineBehaviorConfig as t, type InputPlayerNumber as u, type Inputs as v, GameEntityLifeCycle as w, type IGame as x, type LoadedContext as y, zylemEventBus as z };