@georgeluo/ecs 0.1.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 +87 -0
- package/dist/index.cjs +813 -0
- package/dist/index.d.cts +349 -0
- package/dist/index.d.ts +349 -0
- package/dist/index.mjs +764 -0
- package/package.json +53 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity identifiers represent concrete instances in the simulation.
|
|
3
|
+
* For the primitives checkpoint we model them as opaque numeric ids.
|
|
4
|
+
*/
|
|
5
|
+
type Entity = number;
|
|
6
|
+
/**
|
|
7
|
+
* Utility factory to generate new entity identifiers. Concrete creation
|
|
8
|
+
* semantics live in the EntityManager; this helper exists to clarify
|
|
9
|
+
* the shape of an entity id for implementers.
|
|
10
|
+
*/
|
|
11
|
+
declare const createEntityId: (value: number) => Entity;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Manages lifecycle of entities within the simulation. Responsible for
|
|
15
|
+
* allocating, tracking, and destroying entity identifiers.
|
|
16
|
+
*/
|
|
17
|
+
declare class EntityManager {
|
|
18
|
+
private nextId;
|
|
19
|
+
private readonly active;
|
|
20
|
+
/**
|
|
21
|
+
* Create and register a new entity identifier.
|
|
22
|
+
*
|
|
23
|
+
* @returns Entity id allocated for use in the environment.
|
|
24
|
+
*/
|
|
25
|
+
create(): Entity;
|
|
26
|
+
/**
|
|
27
|
+
* Remove an entity and return whether it existed. This should trigger
|
|
28
|
+
* component cleanup via the ComponentManager (wired externally).
|
|
29
|
+
*
|
|
30
|
+
* @param entity Entity identifier to destroy.
|
|
31
|
+
*/
|
|
32
|
+
remove(entity: Entity): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Indicates whether the manager currently tracks the entity.
|
|
35
|
+
*
|
|
36
|
+
* @param entity Entity identifier to inspect.
|
|
37
|
+
*/
|
|
38
|
+
has(entity: Entity): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Provide a snapshot list of active entities. Higher level systems
|
|
41
|
+
* may use this to iterate over the environment.
|
|
42
|
+
*/
|
|
43
|
+
list(): Entity[];
|
|
44
|
+
/**
|
|
45
|
+
* Iterate over all active entities without allocating an intermediate array.
|
|
46
|
+
*/
|
|
47
|
+
forEach(callback: (entity: Entity) => void): void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* ComponentType describes the schema for a component instance. Concrete
|
|
52
|
+
* component implementations should extend this interface with strongly
|
|
53
|
+
* typed payloads.
|
|
54
|
+
*/
|
|
55
|
+
interface ComponentType<TPayload> {
|
|
56
|
+
/** Unique identifier for the component type at runtime. */
|
|
57
|
+
readonly id: string;
|
|
58
|
+
/** Human-readable description to aid discoverability. */
|
|
59
|
+
readonly description?: string;
|
|
60
|
+
/** Runtime guard to validate payload conformance when attaching components. */
|
|
61
|
+
validate(payload: TPayload): boolean;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Represents an instance of a component bound to an entity.
|
|
65
|
+
*/
|
|
66
|
+
interface ComponentInstance<TPayload> {
|
|
67
|
+
readonly type: ComponentType<TPayload>;
|
|
68
|
+
readonly payload: TPayload;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Maintains bidirectional lookups of entities and their components.
|
|
73
|
+
* Enforces the rule of one component per type per entity.
|
|
74
|
+
*/
|
|
75
|
+
declare class ComponentManager {
|
|
76
|
+
private readonly componentsByEntity;
|
|
77
|
+
private readonly entitiesByType;
|
|
78
|
+
/**
|
|
79
|
+
* Attach a component instance to an entity. Existing component of the same
|
|
80
|
+
* type should be replaced or rejected per implementation decision.
|
|
81
|
+
*/
|
|
82
|
+
addComponent<T>(entity: Entity, type: ComponentType<T>, payload: T): void;
|
|
83
|
+
/**
|
|
84
|
+
* Remove all components for an entity, returning how many were removed.
|
|
85
|
+
*/
|
|
86
|
+
removeAll(entity: Entity): number;
|
|
87
|
+
/**
|
|
88
|
+
* Remove a specific component from an entity.
|
|
89
|
+
*/
|
|
90
|
+
removeComponent<T>(entity: Entity, type: ComponentType<T>): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Retrieve a component instance for the entity, if present.
|
|
93
|
+
*/
|
|
94
|
+
getComponent<T>(entity: Entity, type: ComponentType<T>): ComponentInstance<T> | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* Retrieve all components for the entity.
|
|
97
|
+
*/
|
|
98
|
+
getComponents(entity: Entity): ComponentInstance<unknown>[];
|
|
99
|
+
/**
|
|
100
|
+
* Populate the provided array with the component instances for the entity,
|
|
101
|
+
* returning the number of components discovered. The target array is cleared
|
|
102
|
+
* before population to support buffer reuse.
|
|
103
|
+
*/
|
|
104
|
+
collectComponents(entity: Entity, target: ComponentInstance<unknown>[]): number;
|
|
105
|
+
/**
|
|
106
|
+
* Retrieve entities that possess a component of the provided type.
|
|
107
|
+
*/
|
|
108
|
+
getEntitiesWithComponent<T>(type: ComponentType<T>): Entity[];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface TimePayload {
|
|
112
|
+
tick: number;
|
|
113
|
+
}
|
|
114
|
+
declare const TimeComponent: ComponentType<TimePayload>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Context passed into system lifecycle hooks.
|
|
118
|
+
*/
|
|
119
|
+
interface SystemContext {
|
|
120
|
+
entityManager: EntityManager;
|
|
121
|
+
componentManager: ComponentManager;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Base representation of a system within the ECS engine. Systems are
|
|
125
|
+
* stateless by design and mutate the environment via managers.
|
|
126
|
+
*/
|
|
127
|
+
declare abstract class System {
|
|
128
|
+
/** Optional hook invoked once when the system is added to the engine. */
|
|
129
|
+
initialize(_context: SystemContext): void;
|
|
130
|
+
/** Required update method executed each simulation tick. */
|
|
131
|
+
abstract update(context: SystemContext): void;
|
|
132
|
+
/** Optional hook invoked when the system is removed from the engine. */
|
|
133
|
+
destroy(_context: SystemContext): void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
declare class SystemManager {
|
|
137
|
+
private readonly systems;
|
|
138
|
+
private readonly context;
|
|
139
|
+
constructor(entityManager: EntityManager, componentManager: ComponentManager);
|
|
140
|
+
/** Register a system at the end of the execution order or specified index. */
|
|
141
|
+
addSystem(system: System, index?: number): void;
|
|
142
|
+
/** Remove a system and trigger destroy lifecycle hook. */
|
|
143
|
+
removeSystem(system: System): boolean;
|
|
144
|
+
/** Execute one update cycle across all systems in order. */
|
|
145
|
+
runCycle(): void;
|
|
146
|
+
/** Retrieve current ordered list of systems. */
|
|
147
|
+
getSystems(): System[];
|
|
148
|
+
/** Expose the context passed into systems (entity/component managers). */
|
|
149
|
+
getContext(): SystemContext;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
declare class TimeSystem extends System {
|
|
153
|
+
private timeEntity;
|
|
154
|
+
initialize(context: SystemContext): void;
|
|
155
|
+
update(context: SystemContext): void;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
interface InjectSystemPayload$1 {
|
|
159
|
+
system: System;
|
|
160
|
+
}
|
|
161
|
+
interface EjectSystemPayload$1 {
|
|
162
|
+
system?: System;
|
|
163
|
+
systemId?: string;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Base simulation player responsible for executing registered systems
|
|
167
|
+
* on a fixed interval. Subclasses can hook into the lifecycle to expose
|
|
168
|
+
* messaging or additional orchestration concerns.
|
|
169
|
+
*/
|
|
170
|
+
type PlayerState = 'running' | 'paused' | 'idle';
|
|
171
|
+
interface PlayerStatus {
|
|
172
|
+
state: PlayerState;
|
|
173
|
+
tick: number;
|
|
174
|
+
systemCount: number;
|
|
175
|
+
}
|
|
176
|
+
declare class Player {
|
|
177
|
+
protected readonly systemManager: SystemManager;
|
|
178
|
+
protected readonly cycleIntervalMs: number;
|
|
179
|
+
protected tick: number;
|
|
180
|
+
private isRunning;
|
|
181
|
+
private cycleTimer;
|
|
182
|
+
private nextSystemId;
|
|
183
|
+
private readonly systemsById;
|
|
184
|
+
private readonly idsBySystem;
|
|
185
|
+
constructor(systemManager: SystemManager, cycleIntervalMs?: number);
|
|
186
|
+
start(): void;
|
|
187
|
+
pause(): void;
|
|
188
|
+
stop(): void;
|
|
189
|
+
injectSystem(payload: InjectSystemPayload$1): string;
|
|
190
|
+
ejectSystem(payload: EjectSystemPayload$1): boolean;
|
|
191
|
+
protected getContext(): SystemContext;
|
|
192
|
+
protected executeCycle(): void;
|
|
193
|
+
protected onBeforeCycle(_tick: number): void;
|
|
194
|
+
protected onAfterCycle(_tick: number, _context: SystemContext): void;
|
|
195
|
+
private ensureTimer;
|
|
196
|
+
private clearTimer;
|
|
197
|
+
protected resetEnvironment(): void;
|
|
198
|
+
private generateSystemId;
|
|
199
|
+
private cleanupSystemRegistry;
|
|
200
|
+
describe(): PlayerStatus;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
type BusCallback<TMessage> = (message: TMessage) => void;
|
|
204
|
+
declare class Bus<TMessage> {
|
|
205
|
+
private readonly subscribers;
|
|
206
|
+
private dispatchDepth;
|
|
207
|
+
subscribe(callback: BusCallback<TMessage>): () => void;
|
|
208
|
+
publish(message: TMessage): void;
|
|
209
|
+
private compact;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interface Frame {
|
|
213
|
+
tick: number;
|
|
214
|
+
entities: Record<string, unknown>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
declare class FrameFilter {
|
|
218
|
+
private readonly blacklist;
|
|
219
|
+
constructor(componentBlacklist?: string[]);
|
|
220
|
+
apply(frame: Frame): Frame;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
type AcknowledgementStatus = 'success' | 'error';
|
|
224
|
+
interface Acknowledgement {
|
|
225
|
+
messageId: string;
|
|
226
|
+
status: AcknowledgementStatus;
|
|
227
|
+
detail?: string;
|
|
228
|
+
systemId?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
interface Operation<TContext = SystemContext, TPayload = unknown> {
|
|
232
|
+
execute(context: TContext, payload: TPayload): Acknowledgement;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
declare class MessageHandler<TContext = SystemContext, TPayload = unknown> {
|
|
236
|
+
private readonly operations;
|
|
237
|
+
constructor(operations: Operation<TContext, TPayload>[]);
|
|
238
|
+
handle(context: TContext, payload: TPayload): Acknowledgement;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
declare class InboundHandlerRegistry<TContext = unknown> {
|
|
242
|
+
private readonly handlers;
|
|
243
|
+
constructor(handlers?: Map<string, MessageHandler<TContext, unknown>>);
|
|
244
|
+
register<TPayload>(type: string, handler: MessageHandler<TContext, TPayload>): void;
|
|
245
|
+
handle(type: string, context: TContext, payload: unknown): Acknowledgement | null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
type OutboundMessage$1 = Frame | Acknowledgement;
|
|
249
|
+
declare class IOPlayer extends Player {
|
|
250
|
+
private readonly inbound;
|
|
251
|
+
private readonly outbound;
|
|
252
|
+
private readonly frameFilter;
|
|
253
|
+
private readonly handlers;
|
|
254
|
+
private readonly unsubscribeInbound;
|
|
255
|
+
private readonly componentBuffer;
|
|
256
|
+
constructor(systemManager: SystemManager, inbound: Bus<unknown>, outbound: Bus<OutboundMessage$1>, frameFilter: FrameFilter, handlers?: InboundHandlerRegistry<IOPlayer>, cycleIntervalMs?: number);
|
|
257
|
+
protected getInboundHandlers(): InboundHandlerRegistry<IOPlayer>;
|
|
258
|
+
protected onAfterCycle(tick: number, context: SystemContext): void;
|
|
259
|
+
protected handleInbound(message: unknown): void;
|
|
260
|
+
protected publishFrame(frame: Frame): void;
|
|
261
|
+
private createFrameSnapshot;
|
|
262
|
+
private collectComponents;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
type OutboundMessage = Frame | Acknowledgement;
|
|
266
|
+
declare const SimulationMessageType: {
|
|
267
|
+
readonly START: "start";
|
|
268
|
+
readonly PAUSE: "pause";
|
|
269
|
+
readonly STOP: "stop";
|
|
270
|
+
readonly INJECT_SYSTEM: "inject-system";
|
|
271
|
+
readonly EJECT_SYSTEM: "eject-system";
|
|
272
|
+
};
|
|
273
|
+
declare class SimulationPlayer extends IOPlayer {
|
|
274
|
+
private readonly componentTypes;
|
|
275
|
+
constructor(systemManager: SystemManager, inbound: Bus<unknown>, outbound: Bus<OutboundMessage>, frameFilter: FrameFilter, handlers?: InboundHandlerRegistry<IOPlayer>, cycleIntervalMs?: number);
|
|
276
|
+
registerComponent<T>(component: ComponentType<T>): void;
|
|
277
|
+
removeComponent(componentId: string): boolean;
|
|
278
|
+
getRegisteredComponents(): ComponentType<unknown>[];
|
|
279
|
+
private registerDefaultHandlers;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface FrameRecord {
|
|
283
|
+
messageId?: string;
|
|
284
|
+
frame: Frame;
|
|
285
|
+
}
|
|
286
|
+
declare const EvaluationMessageType: {
|
|
287
|
+
readonly INJECT_FRAME: "inject-frame";
|
|
288
|
+
};
|
|
289
|
+
declare class EvaluationPlayer extends IOPlayer {
|
|
290
|
+
protected readonly frames: FrameRecord[];
|
|
291
|
+
private readonly componentTypes;
|
|
292
|
+
private readonly frameComponentType;
|
|
293
|
+
private lastFrameTick;
|
|
294
|
+
constructor(systemManager: SystemManager, inbound: Bus<unknown>, outbound: Bus<Frame | Acknowledgement>, frameFilter: FrameFilter, handlers?: InboundHandlerRegistry<EvaluationPlayer>, cycleIntervalMs?: number);
|
|
295
|
+
injectFrame(payload: FrameRecord): void;
|
|
296
|
+
getFrames(): FrameRecord[];
|
|
297
|
+
registerComponent<T>(component: ComponentType<T>): void;
|
|
298
|
+
removeComponent(componentId: string): boolean;
|
|
299
|
+
getRegisteredComponents(): ComponentType<unknown>[];
|
|
300
|
+
private resetIfNewRun;
|
|
301
|
+
private registerDefaultHandlers;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
interface InjectFramePayload extends FrameRecord {
|
|
305
|
+
messageId: string;
|
|
306
|
+
}
|
|
307
|
+
declare class InjectFrame implements Operation<EvaluationPlayer, InjectFramePayload> {
|
|
308
|
+
execute(player: EvaluationPlayer, payload: InjectFramePayload): Acknowledgement;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
interface StartPayload {
|
|
312
|
+
messageId: string;
|
|
313
|
+
}
|
|
314
|
+
declare class Start implements Operation<IOPlayer, StartPayload> {
|
|
315
|
+
execute(player: IOPlayer, payload: StartPayload): Acknowledgement;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
interface PausePayload {
|
|
319
|
+
messageId: string;
|
|
320
|
+
}
|
|
321
|
+
declare class Pause implements Operation<IOPlayer, PausePayload> {
|
|
322
|
+
execute(player: IOPlayer, payload: PausePayload): Acknowledgement;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
interface StopPayload {
|
|
326
|
+
messageId: string;
|
|
327
|
+
}
|
|
328
|
+
declare class Stop implements Operation<IOPlayer, StopPayload> {
|
|
329
|
+
execute(player: IOPlayer, payload: StopPayload): Acknowledgement;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
interface InjectSystemPayload {
|
|
333
|
+
messageId: string;
|
|
334
|
+
system: System;
|
|
335
|
+
}
|
|
336
|
+
declare class InjectSystem implements Operation<IOPlayer, InjectSystemPayload> {
|
|
337
|
+
execute(player: IOPlayer, payload: InjectSystemPayload): Acknowledgement;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
interface EjectSystemPayload {
|
|
341
|
+
messageId: string;
|
|
342
|
+
system?: System;
|
|
343
|
+
systemId?: string;
|
|
344
|
+
}
|
|
345
|
+
declare class EjectSystem implements Operation<IOPlayer, EjectSystemPayload> {
|
|
346
|
+
execute(player: IOPlayer, payload: EjectSystemPayload): Acknowledgement;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export { type Acknowledgement, type AcknowledgementStatus, Bus, type BusCallback, type ComponentInstance, ComponentManager, type ComponentType, EjectSystem, type EjectSystemPayload, type Entity, EntityManager, EvaluationMessageType, EvaluationPlayer, type Frame, FrameFilter, type FrameRecord, IOPlayer, InboundHandlerRegistry, InjectFrame, type InjectFramePayload, InjectSystem, type InjectSystemPayload, MessageHandler, type Operation, Pause, type PausePayload, Player, type PlayerState, type PlayerStatus, SimulationMessageType, SimulationPlayer, Start, type StartPayload, Stop, type StopPayload, System, type SystemContext, SystemManager, TimeComponent, type TimePayload, TimeSystem, createEntityId };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity identifiers represent concrete instances in the simulation.
|
|
3
|
+
* For the primitives checkpoint we model them as opaque numeric ids.
|
|
4
|
+
*/
|
|
5
|
+
type Entity = number;
|
|
6
|
+
/**
|
|
7
|
+
* Utility factory to generate new entity identifiers. Concrete creation
|
|
8
|
+
* semantics live in the EntityManager; this helper exists to clarify
|
|
9
|
+
* the shape of an entity id for implementers.
|
|
10
|
+
*/
|
|
11
|
+
declare const createEntityId: (value: number) => Entity;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Manages lifecycle of entities within the simulation. Responsible for
|
|
15
|
+
* allocating, tracking, and destroying entity identifiers.
|
|
16
|
+
*/
|
|
17
|
+
declare class EntityManager {
|
|
18
|
+
private nextId;
|
|
19
|
+
private readonly active;
|
|
20
|
+
/**
|
|
21
|
+
* Create and register a new entity identifier.
|
|
22
|
+
*
|
|
23
|
+
* @returns Entity id allocated for use in the environment.
|
|
24
|
+
*/
|
|
25
|
+
create(): Entity;
|
|
26
|
+
/**
|
|
27
|
+
* Remove an entity and return whether it existed. This should trigger
|
|
28
|
+
* component cleanup via the ComponentManager (wired externally).
|
|
29
|
+
*
|
|
30
|
+
* @param entity Entity identifier to destroy.
|
|
31
|
+
*/
|
|
32
|
+
remove(entity: Entity): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Indicates whether the manager currently tracks the entity.
|
|
35
|
+
*
|
|
36
|
+
* @param entity Entity identifier to inspect.
|
|
37
|
+
*/
|
|
38
|
+
has(entity: Entity): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Provide a snapshot list of active entities. Higher level systems
|
|
41
|
+
* may use this to iterate over the environment.
|
|
42
|
+
*/
|
|
43
|
+
list(): Entity[];
|
|
44
|
+
/**
|
|
45
|
+
* Iterate over all active entities without allocating an intermediate array.
|
|
46
|
+
*/
|
|
47
|
+
forEach(callback: (entity: Entity) => void): void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* ComponentType describes the schema for a component instance. Concrete
|
|
52
|
+
* component implementations should extend this interface with strongly
|
|
53
|
+
* typed payloads.
|
|
54
|
+
*/
|
|
55
|
+
interface ComponentType<TPayload> {
|
|
56
|
+
/** Unique identifier for the component type at runtime. */
|
|
57
|
+
readonly id: string;
|
|
58
|
+
/** Human-readable description to aid discoverability. */
|
|
59
|
+
readonly description?: string;
|
|
60
|
+
/** Runtime guard to validate payload conformance when attaching components. */
|
|
61
|
+
validate(payload: TPayload): boolean;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Represents an instance of a component bound to an entity.
|
|
65
|
+
*/
|
|
66
|
+
interface ComponentInstance<TPayload> {
|
|
67
|
+
readonly type: ComponentType<TPayload>;
|
|
68
|
+
readonly payload: TPayload;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Maintains bidirectional lookups of entities and their components.
|
|
73
|
+
* Enforces the rule of one component per type per entity.
|
|
74
|
+
*/
|
|
75
|
+
declare class ComponentManager {
|
|
76
|
+
private readonly componentsByEntity;
|
|
77
|
+
private readonly entitiesByType;
|
|
78
|
+
/**
|
|
79
|
+
* Attach a component instance to an entity. Existing component of the same
|
|
80
|
+
* type should be replaced or rejected per implementation decision.
|
|
81
|
+
*/
|
|
82
|
+
addComponent<T>(entity: Entity, type: ComponentType<T>, payload: T): void;
|
|
83
|
+
/**
|
|
84
|
+
* Remove all components for an entity, returning how many were removed.
|
|
85
|
+
*/
|
|
86
|
+
removeAll(entity: Entity): number;
|
|
87
|
+
/**
|
|
88
|
+
* Remove a specific component from an entity.
|
|
89
|
+
*/
|
|
90
|
+
removeComponent<T>(entity: Entity, type: ComponentType<T>): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Retrieve a component instance for the entity, if present.
|
|
93
|
+
*/
|
|
94
|
+
getComponent<T>(entity: Entity, type: ComponentType<T>): ComponentInstance<T> | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* Retrieve all components for the entity.
|
|
97
|
+
*/
|
|
98
|
+
getComponents(entity: Entity): ComponentInstance<unknown>[];
|
|
99
|
+
/**
|
|
100
|
+
* Populate the provided array with the component instances for the entity,
|
|
101
|
+
* returning the number of components discovered. The target array is cleared
|
|
102
|
+
* before population to support buffer reuse.
|
|
103
|
+
*/
|
|
104
|
+
collectComponents(entity: Entity, target: ComponentInstance<unknown>[]): number;
|
|
105
|
+
/**
|
|
106
|
+
* Retrieve entities that possess a component of the provided type.
|
|
107
|
+
*/
|
|
108
|
+
getEntitiesWithComponent<T>(type: ComponentType<T>): Entity[];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface TimePayload {
|
|
112
|
+
tick: number;
|
|
113
|
+
}
|
|
114
|
+
declare const TimeComponent: ComponentType<TimePayload>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Context passed into system lifecycle hooks.
|
|
118
|
+
*/
|
|
119
|
+
interface SystemContext {
|
|
120
|
+
entityManager: EntityManager;
|
|
121
|
+
componentManager: ComponentManager;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Base representation of a system within the ECS engine. Systems are
|
|
125
|
+
* stateless by design and mutate the environment via managers.
|
|
126
|
+
*/
|
|
127
|
+
declare abstract class System {
|
|
128
|
+
/** Optional hook invoked once when the system is added to the engine. */
|
|
129
|
+
initialize(_context: SystemContext): void;
|
|
130
|
+
/** Required update method executed each simulation tick. */
|
|
131
|
+
abstract update(context: SystemContext): void;
|
|
132
|
+
/** Optional hook invoked when the system is removed from the engine. */
|
|
133
|
+
destroy(_context: SystemContext): void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
declare class SystemManager {
|
|
137
|
+
private readonly systems;
|
|
138
|
+
private readonly context;
|
|
139
|
+
constructor(entityManager: EntityManager, componentManager: ComponentManager);
|
|
140
|
+
/** Register a system at the end of the execution order or specified index. */
|
|
141
|
+
addSystem(system: System, index?: number): void;
|
|
142
|
+
/** Remove a system and trigger destroy lifecycle hook. */
|
|
143
|
+
removeSystem(system: System): boolean;
|
|
144
|
+
/** Execute one update cycle across all systems in order. */
|
|
145
|
+
runCycle(): void;
|
|
146
|
+
/** Retrieve current ordered list of systems. */
|
|
147
|
+
getSystems(): System[];
|
|
148
|
+
/** Expose the context passed into systems (entity/component managers). */
|
|
149
|
+
getContext(): SystemContext;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
declare class TimeSystem extends System {
|
|
153
|
+
private timeEntity;
|
|
154
|
+
initialize(context: SystemContext): void;
|
|
155
|
+
update(context: SystemContext): void;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
interface InjectSystemPayload$1 {
|
|
159
|
+
system: System;
|
|
160
|
+
}
|
|
161
|
+
interface EjectSystemPayload$1 {
|
|
162
|
+
system?: System;
|
|
163
|
+
systemId?: string;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Base simulation player responsible for executing registered systems
|
|
167
|
+
* on a fixed interval. Subclasses can hook into the lifecycle to expose
|
|
168
|
+
* messaging or additional orchestration concerns.
|
|
169
|
+
*/
|
|
170
|
+
type PlayerState = 'running' | 'paused' | 'idle';
|
|
171
|
+
interface PlayerStatus {
|
|
172
|
+
state: PlayerState;
|
|
173
|
+
tick: number;
|
|
174
|
+
systemCount: number;
|
|
175
|
+
}
|
|
176
|
+
declare class Player {
|
|
177
|
+
protected readonly systemManager: SystemManager;
|
|
178
|
+
protected readonly cycleIntervalMs: number;
|
|
179
|
+
protected tick: number;
|
|
180
|
+
private isRunning;
|
|
181
|
+
private cycleTimer;
|
|
182
|
+
private nextSystemId;
|
|
183
|
+
private readonly systemsById;
|
|
184
|
+
private readonly idsBySystem;
|
|
185
|
+
constructor(systemManager: SystemManager, cycleIntervalMs?: number);
|
|
186
|
+
start(): void;
|
|
187
|
+
pause(): void;
|
|
188
|
+
stop(): void;
|
|
189
|
+
injectSystem(payload: InjectSystemPayload$1): string;
|
|
190
|
+
ejectSystem(payload: EjectSystemPayload$1): boolean;
|
|
191
|
+
protected getContext(): SystemContext;
|
|
192
|
+
protected executeCycle(): void;
|
|
193
|
+
protected onBeforeCycle(_tick: number): void;
|
|
194
|
+
protected onAfterCycle(_tick: number, _context: SystemContext): void;
|
|
195
|
+
private ensureTimer;
|
|
196
|
+
private clearTimer;
|
|
197
|
+
protected resetEnvironment(): void;
|
|
198
|
+
private generateSystemId;
|
|
199
|
+
private cleanupSystemRegistry;
|
|
200
|
+
describe(): PlayerStatus;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
type BusCallback<TMessage> = (message: TMessage) => void;
|
|
204
|
+
declare class Bus<TMessage> {
|
|
205
|
+
private readonly subscribers;
|
|
206
|
+
private dispatchDepth;
|
|
207
|
+
subscribe(callback: BusCallback<TMessage>): () => void;
|
|
208
|
+
publish(message: TMessage): void;
|
|
209
|
+
private compact;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interface Frame {
|
|
213
|
+
tick: number;
|
|
214
|
+
entities: Record<string, unknown>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
declare class FrameFilter {
|
|
218
|
+
private readonly blacklist;
|
|
219
|
+
constructor(componentBlacklist?: string[]);
|
|
220
|
+
apply(frame: Frame): Frame;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
type AcknowledgementStatus = 'success' | 'error';
|
|
224
|
+
interface Acknowledgement {
|
|
225
|
+
messageId: string;
|
|
226
|
+
status: AcknowledgementStatus;
|
|
227
|
+
detail?: string;
|
|
228
|
+
systemId?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
interface Operation<TContext = SystemContext, TPayload = unknown> {
|
|
232
|
+
execute(context: TContext, payload: TPayload): Acknowledgement;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
declare class MessageHandler<TContext = SystemContext, TPayload = unknown> {
|
|
236
|
+
private readonly operations;
|
|
237
|
+
constructor(operations: Operation<TContext, TPayload>[]);
|
|
238
|
+
handle(context: TContext, payload: TPayload): Acknowledgement;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
declare class InboundHandlerRegistry<TContext = unknown> {
|
|
242
|
+
private readonly handlers;
|
|
243
|
+
constructor(handlers?: Map<string, MessageHandler<TContext, unknown>>);
|
|
244
|
+
register<TPayload>(type: string, handler: MessageHandler<TContext, TPayload>): void;
|
|
245
|
+
handle(type: string, context: TContext, payload: unknown): Acknowledgement | null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
type OutboundMessage$1 = Frame | Acknowledgement;
|
|
249
|
+
declare class IOPlayer extends Player {
|
|
250
|
+
private readonly inbound;
|
|
251
|
+
private readonly outbound;
|
|
252
|
+
private readonly frameFilter;
|
|
253
|
+
private readonly handlers;
|
|
254
|
+
private readonly unsubscribeInbound;
|
|
255
|
+
private readonly componentBuffer;
|
|
256
|
+
constructor(systemManager: SystemManager, inbound: Bus<unknown>, outbound: Bus<OutboundMessage$1>, frameFilter: FrameFilter, handlers?: InboundHandlerRegistry<IOPlayer>, cycleIntervalMs?: number);
|
|
257
|
+
protected getInboundHandlers(): InboundHandlerRegistry<IOPlayer>;
|
|
258
|
+
protected onAfterCycle(tick: number, context: SystemContext): void;
|
|
259
|
+
protected handleInbound(message: unknown): void;
|
|
260
|
+
protected publishFrame(frame: Frame): void;
|
|
261
|
+
private createFrameSnapshot;
|
|
262
|
+
private collectComponents;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
type OutboundMessage = Frame | Acknowledgement;
|
|
266
|
+
declare const SimulationMessageType: {
|
|
267
|
+
readonly START: "start";
|
|
268
|
+
readonly PAUSE: "pause";
|
|
269
|
+
readonly STOP: "stop";
|
|
270
|
+
readonly INJECT_SYSTEM: "inject-system";
|
|
271
|
+
readonly EJECT_SYSTEM: "eject-system";
|
|
272
|
+
};
|
|
273
|
+
declare class SimulationPlayer extends IOPlayer {
|
|
274
|
+
private readonly componentTypes;
|
|
275
|
+
constructor(systemManager: SystemManager, inbound: Bus<unknown>, outbound: Bus<OutboundMessage>, frameFilter: FrameFilter, handlers?: InboundHandlerRegistry<IOPlayer>, cycleIntervalMs?: number);
|
|
276
|
+
registerComponent<T>(component: ComponentType<T>): void;
|
|
277
|
+
removeComponent(componentId: string): boolean;
|
|
278
|
+
getRegisteredComponents(): ComponentType<unknown>[];
|
|
279
|
+
private registerDefaultHandlers;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface FrameRecord {
|
|
283
|
+
messageId?: string;
|
|
284
|
+
frame: Frame;
|
|
285
|
+
}
|
|
286
|
+
declare const EvaluationMessageType: {
|
|
287
|
+
readonly INJECT_FRAME: "inject-frame";
|
|
288
|
+
};
|
|
289
|
+
declare class EvaluationPlayer extends IOPlayer {
|
|
290
|
+
protected readonly frames: FrameRecord[];
|
|
291
|
+
private readonly componentTypes;
|
|
292
|
+
private readonly frameComponentType;
|
|
293
|
+
private lastFrameTick;
|
|
294
|
+
constructor(systemManager: SystemManager, inbound: Bus<unknown>, outbound: Bus<Frame | Acknowledgement>, frameFilter: FrameFilter, handlers?: InboundHandlerRegistry<EvaluationPlayer>, cycleIntervalMs?: number);
|
|
295
|
+
injectFrame(payload: FrameRecord): void;
|
|
296
|
+
getFrames(): FrameRecord[];
|
|
297
|
+
registerComponent<T>(component: ComponentType<T>): void;
|
|
298
|
+
removeComponent(componentId: string): boolean;
|
|
299
|
+
getRegisteredComponents(): ComponentType<unknown>[];
|
|
300
|
+
private resetIfNewRun;
|
|
301
|
+
private registerDefaultHandlers;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
interface InjectFramePayload extends FrameRecord {
|
|
305
|
+
messageId: string;
|
|
306
|
+
}
|
|
307
|
+
declare class InjectFrame implements Operation<EvaluationPlayer, InjectFramePayload> {
|
|
308
|
+
execute(player: EvaluationPlayer, payload: InjectFramePayload): Acknowledgement;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
interface StartPayload {
|
|
312
|
+
messageId: string;
|
|
313
|
+
}
|
|
314
|
+
declare class Start implements Operation<IOPlayer, StartPayload> {
|
|
315
|
+
execute(player: IOPlayer, payload: StartPayload): Acknowledgement;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
interface PausePayload {
|
|
319
|
+
messageId: string;
|
|
320
|
+
}
|
|
321
|
+
declare class Pause implements Operation<IOPlayer, PausePayload> {
|
|
322
|
+
execute(player: IOPlayer, payload: PausePayload): Acknowledgement;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
interface StopPayload {
|
|
326
|
+
messageId: string;
|
|
327
|
+
}
|
|
328
|
+
declare class Stop implements Operation<IOPlayer, StopPayload> {
|
|
329
|
+
execute(player: IOPlayer, payload: StopPayload): Acknowledgement;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
interface InjectSystemPayload {
|
|
333
|
+
messageId: string;
|
|
334
|
+
system: System;
|
|
335
|
+
}
|
|
336
|
+
declare class InjectSystem implements Operation<IOPlayer, InjectSystemPayload> {
|
|
337
|
+
execute(player: IOPlayer, payload: InjectSystemPayload): Acknowledgement;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
interface EjectSystemPayload {
|
|
341
|
+
messageId: string;
|
|
342
|
+
system?: System;
|
|
343
|
+
systemId?: string;
|
|
344
|
+
}
|
|
345
|
+
declare class EjectSystem implements Operation<IOPlayer, EjectSystemPayload> {
|
|
346
|
+
execute(player: IOPlayer, payload: EjectSystemPayload): Acknowledgement;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export { type Acknowledgement, type AcknowledgementStatus, Bus, type BusCallback, type ComponentInstance, ComponentManager, type ComponentType, EjectSystem, type EjectSystemPayload, type Entity, EntityManager, EvaluationMessageType, EvaluationPlayer, type Frame, FrameFilter, type FrameRecord, IOPlayer, InboundHandlerRegistry, InjectFrame, type InjectFramePayload, InjectSystem, type InjectSystemPayload, MessageHandler, type Operation, Pause, type PausePayload, Player, type PlayerState, type PlayerStatus, SimulationMessageType, SimulationPlayer, Start, type StartPayload, Stop, type StopPayload, System, type SystemContext, SystemManager, TimeComponent, type TimePayload, TimeSystem, createEntityId };
|