mani-game-engine 1.0.0-pre.3 → 1.0.0-pre.30

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/src/gameEngine.ts CHANGED
@@ -1,16 +1,16 @@
1
- import {Action, Class, GameEnginePlugin, GameService, GameSystem, OnUpdateParams} from './types';
1
+ import {Action, Class, EngineSignals, GameEnginePlugin, OnFixedUpdateParams, OnUpdateParams, Service, System} from './types';
2
2
  import {Signal, SignalBinding} from 'mani-signal';
3
3
  import {Entity} from './entity';
4
- import {ID, putIfAbsent} from 'mani-injector';
5
- import {EcsInjector, signalHandlers} from './ecsInjector';
6
- import {Clock} from './clock';
4
+ import {EcsInjector, signalHandlers, staticSignalHandlers} from './ecsInjector';
5
+ import {Clock, GameClock} from './clock';
6
+ import {SystemContext} from './systemContext';
7
+ import {ID, putIfAbsent} from './injector';
7
8
 
8
- type AddEntry = [Entity[], () => void];
9
- type RemoveEntry = [Entity[], () => void];
9
+ type AddEntry = [Entity, () => void];
10
+ type RemoveEntry = [Entity, () => void];
10
11
 
11
12
  const defaultOptions = {
12
13
  fixedDeltaTime: 1 / 60,
13
- autoStart: true,
14
14
  plugins: [] as GameEnginePlugin[],
15
15
  };
16
16
 
@@ -25,55 +25,151 @@ type GameEngineActionParams<K extends keyof GameEngineActions> = GameEngineActio
25
25
  type GameAction<K extends keyof GameEngineActions> = (engine: GameEngine, params: GameEngineActionParams<K>) => Promise<any> | any;
26
26
 
27
27
  export class GameEngine {
28
- readonly onRender = new Signal();
29
- readonly onUpdate = new Signal<OnUpdateParams>();
30
28
 
31
- private readonly onEarlyUpdateSet = new Set<GameSystem>();
32
- private readonly onUpdateSet = new Set<GameSystem>();
33
- private readonly onFixedUpdateSet = new Set<GameSystem>();
34
- private readonly onPreFixedUpdateSet = new Set<GameSystem>();
35
- private readonly onPhysicsUpdateSet = new Set<GameSystem>();
36
- private readonly onPostPhysicsUpdateSet = new Set<GameSystem>();
37
- private readonly onLateUpdateSet = new Set<GameSystem>();
38
- private readonly onRenderUpdateSet = new Set<GameSystem>();
39
-
40
- private readonly entitySystemMap = new Map<Object, GameSystem[]>();
29
+ readonly onPrepare: Signal;
30
+ readonly onStart: Signal;
31
+ readonly onEnd: Signal;
32
+ readonly onRender: Signal<OnUpdateParams>;
33
+ readonly onUpdate: Signal<OnUpdateParams>;
34
+ readonly onFixedUpdate: Signal<OnFixedUpdateParams>;
35
+ readonly onPrePhysicsUpdate: Signal<OnFixedUpdateParams>;
36
+ readonly onPhysicsUpdate: Signal<OnFixedUpdateParams>;
37
+ readonly onPostPhysicsUpdate: Signal<OnFixedUpdateParams>;
38
+ readonly onLateFixedUpdate: Signal<OnFixedUpdateParams>;
39
+ readonly onLateUpdate: Signal<OnUpdateParams>;
40
+
41
+ private readonly onEarlyUpdateSet = new Set<System>();
42
+ private readonly onUpdateSet = new Set<System>();
43
+ private readonly onFixedUpdateSet = new Set<System>();
44
+ private readonly onPreFixedUpdateSet = new Set<System>();
45
+ private readonly onPhysicsUpdateSet = new Set<System>();
46
+ private readonly onPrePhysicsUpdateSet = new Set<System>();
47
+ private readonly onPostPhysicsUpdateSet = new Set<System>();
48
+ private readonly onLateFixedUpdateSet = new Set<System>();
49
+ private readonly onLateUpdateSet = new Set<System>();
50
+ private readonly onRenderUpdateSet = new Set<System>();
51
+
52
+ private readonly entitySystemMap = new Map<Entity, SystemContext[]>();
53
+
54
+ private readonly serviceClasses = new Set<Class<Service>>();
55
+ private readonly services: Service[] = [];
41
56
 
42
57
  private framePromise!: Promise<any>;
43
58
  private resolveFrame: () => void = () => undefined;
44
59
 
60
+ private addQueue: AddEntry[] = [];
61
+ private removeQueue: RemoveEntry[] = [];
62
+
63
+ private _started = false;
64
+
65
+ get started(): boolean { return this._started; }
66
+
45
67
  private _frameCount = 0;
68
+ get frameCount(): number { return this._frameCount; }
46
69
 
47
- get frameCount(): number {
48
- return this._frameCount;
49
- }
70
+ private _fixedFrameCount = 0;
71
+ get fixedFrameCount(): number { return this._fixedFrameCount; }
50
72
 
51
- get numEntities(): number {
52
- return 0;
53
- }
73
+ get numEntities(): number { return this.entitySystemMap.size;}
54
74
 
55
75
  // TODO inject clock into game engine
56
76
  // TODO inject space into game engine
57
77
 
78
+ constructor(
79
+ readonly injector: EcsInjector<Class<System>>,
80
+ readonly clock: Clock,
81
+ ) {
82
+ this.injector.map(GameEngine).toValue(this);
83
+
84
+ this.onPrepare = this.injector.getSignal(EngineSignals.OnPrepare);
85
+ this.onStart = this.injector.getSignal(EngineSignals.OnStart);
86
+ this.onEnd = this.injector.getSignal(EngineSignals.OnEnd);
87
+ this.onRender = this.injector.getSignal(EngineSignals.OnRender);
88
+ this.onFixedUpdate = this.injector.getSignal(EngineSignals.OnFixedUpdate);
89
+ this.onUpdate = this.injector.getSignal(EngineSignals.OnUpdate);
90
+ this.onLateUpdate = this.injector.getSignal(EngineSignals.OnLateUpdate);
91
+ this.onPrePhysicsUpdate = this.injector.getSignal(EngineSignals.OnPrePhysicsUpdate);
92
+ this.onPhysicsUpdate = this.injector.getSignal(EngineSignals.OnPhysicsUpdate);
93
+ this.onPostPhysicsUpdate = this.injector.getSignal(EngineSignals.OnPostPhysicsUpdate);
94
+ this.onLateFixedUpdate = this.injector.getSignal(EngineSignals.onLateFixedUpdate);
95
+
96
+ this.setupClock();
97
+ this.prepareFrame();
98
+ }
99
+
58
100
  static createDefault(options?: GameEngineOptions) {
59
101
  const opts = {...defaultOptions, ...options};
60
- const clock = new Clock({
102
+ const clock = new GameClock({
61
103
  fixedDeltaTime: opts.fixedDeltaTime,
62
- autoStart: opts.autoStart
104
+ autoStart: false,
63
105
  });
64
- const injector = new EcsInjector<Class<GameSystem>>();
106
+ const injector = new EcsInjector<Class<System>>();
65
107
  const engine = new GameEngine(injector, clock);
66
108
  engine.installPlugins(opts.plugins);
67
109
  return engine;
68
110
  }
69
111
 
70
- constructor(
71
- readonly injector: EcsInjector<Class<GameSystem>>,
72
- readonly clock: Clock,
73
- ) {
74
- this.injector.map(GameEngine).toValue(this);
75
- this.setupClock();
76
- this.prepareFrame();
112
+ static createDefaultWithInjector(injector: EcsInjector<Class<System>>, options?: GameEngineOptions) {
113
+ const opts = {...defaultOptions, ...options};
114
+ const clock = new GameClock({
115
+ fixedDeltaTime: opts.fixedDeltaTime,
116
+ autoStart: false,
117
+ });
118
+ const engine = new GameEngine(injector, clock);
119
+ engine.installPlugins(opts.plugins);
120
+ return engine;
121
+ }
122
+
123
+ addService(service: Service): void {
124
+ this.mapAnnotatedSignals(service);
125
+ service.onStart && service.onStart();
126
+ service.onPreFixedUpdate && this.onPreFixedUpdateSet.add(service);
127
+ service.onFixedUpdate && this.onFixedUpdateSet.add(service);
128
+ service.onUpdate && this.onUpdateSet.add(service);
129
+ service.onLateUpdate && this.onLateUpdateSet.add(service);
130
+ service.onPrePhysicsUpdate && this.onPrePhysicsUpdateSet.add(service);
131
+ service.onPhysicsUpdate && this.onPhysicsUpdateSet.add(service);
132
+ service.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(service);
133
+ service.onLateFixedUpdate && this.onLateFixedUpdateSet.add(service);
134
+ service.onRender && this.onRenderUpdateSet.add(service);
135
+ this.services.push(service);
136
+ }
137
+
138
+ private installPlugins(plugins: GameEnginePlugin[]) {
139
+ plugins.forEach(plugin => {
140
+ plugin.onPrepare && plugin.onPrepare(this);
141
+ });
142
+ plugins.forEach(plugin => {
143
+ plugin.onStart && plugin.onStart(this);
144
+ });
145
+ }
146
+
147
+ registerSystem(systemClass: Class<System>): void {
148
+ this.mapStaticAnnotatedSignals(systemClass);
149
+ if (this._started) throw new Error('Register Systems before engine is started');
150
+ this.injector.registerSystem(systemClass);
151
+ }
152
+
153
+ registerService(serviceClass: Class<Service>): void {
154
+ this.mapStaticAnnotatedSignals(serviceClass);
155
+ if (this._started) throw new Error('Register Services before engine is started');
156
+ this.injector.map(serviceClass).toSingleton();
157
+ this.serviceClasses.add(serviceClass);
158
+ }
159
+
160
+ getService<T extends Class<Service>>(serviceClass: T): InstanceType<T> {
161
+ return this.injector.get(serviceClass);
162
+ }
163
+
164
+ start() {
165
+ this._started = true;
166
+ //TODO: throw when registering services or systems when engine is running
167
+ for (const serviceClass of this.serviceClasses) {
168
+ const service = this.injector.get(serviceClass);
169
+ this.addService(service);
170
+ }
171
+ this.clock.start();
172
+ this.onStart.dispatch();
77
173
  }
78
174
 
79
175
  private setupClock() {
@@ -85,143 +181,223 @@ export class GameEngine {
85
181
  }
86
182
  });
87
183
 
88
- this.clock.onFixedUpdate.add(({time, deltaTime}) => {
184
+ this.clock.onFixedUpdate.add((params) => {
185
+ const {time, deltaTime} = params;
89
186
  for (const system of this.onPreFixedUpdateSet) {
90
- system.onPreFixedUpdate!();
187
+ system.onPreFixedUpdate!(time, deltaTime);
91
188
  }
92
189
  for (const system of this.onFixedUpdateSet) {
93
190
  system.onFixedUpdate!(time, deltaTime);
94
191
  }
192
+ this.onFixedUpdate.dispatch(params);
95
193
  for (const system of this.onPhysicsUpdateSet) {
96
194
  system.onPhysicsUpdate!(time, deltaTime);
97
195
  }
196
+ this.onPhysicsUpdate.dispatch(params);
197
+ this.onPostPhysicsUpdate.dispatch(params);
98
198
  for (const system of this.onPostPhysicsUpdateSet) {
99
199
  system.onPostPhysicsUpdate!(time, deltaTime);
100
200
  }
201
+ this.onLateFixedUpdate.dispatch(params);
202
+ for (const system of this.onLateFixedUpdateSet) {
203
+ system.onLateFixedUpdate!(time, deltaTime);
204
+ }
205
+ this._fixedFrameCount++;
101
206
  });
102
207
 
103
- this.clock.onUpdate.add(({time, deltaTime, alpha}) => {
208
+ // TODO: update from outside
209
+ this.clock.onUpdate.add(onUpdateParams => {
210
+ const {time, deltaTime, alpha} = onUpdateParams;
104
211
  for (const system of this.onUpdateSet) {
105
-
106
212
  system.onUpdate!(time, deltaTime, alpha);
107
213
  }
214
+ //TODO: merge with framerate to single signal?
215
+
216
+ this.onUpdate.dispatch(onUpdateParams);
108
217
  for (const system of this.onLateUpdateSet) {
109
218
  system.onLateUpdate!(time, deltaTime, alpha);
110
219
  }
111
- //TODO: merge with framerate to single signal?
112
- this.onUpdate.dispatch({time, deltaTime, alpha});
113
- //
114
- // const drawTime = 1 / 30;
115
- // while (performance.now() < ts + drawTime * 1000) {
116
- //
117
- // }
220
+ this.onLateUpdate.dispatch(onUpdateParams);
221
+
118
222
  for (const system of this.onRenderUpdateSet) {
119
- system.onRender!();
223
+ system.onRender!(time, deltaTime, alpha);
120
224
  }
121
- this.onRender.dispatch();
225
+ this.onRender.dispatch(onUpdateParams);
122
226
  this._frameCount++;
123
227
  });
124
228
  }
125
229
 
126
- private installPlugins(plugins: GameEnginePlugin[]) {
127
- plugins.forEach(plugin => {
128
- plugin.onPrepare && plugin.onPrepare(this);
129
- });
130
- plugins.forEach(plugin => {
131
- plugin.onStart && plugin.onStart(this);
132
- });
230
+ add(entity: Entity) {
231
+ return new Promise<void>(resolve => this.addQueue.push([entity, resolve]));
133
232
  }
134
233
 
135
- registerSystem(systemClass: Class<GameSystem>): void {
136
- this.injector.registerSystem(systemClass);
234
+ waitFrame() {
235
+ return this.framePromise;
137
236
  }
138
237
 
139
- addService(service: GameService): void {
140
- this.mapAnnotatedSignals(service);
141
- service.onStart && service.onStart();
142
- service.onPreFixedUpdate && this.onPreFixedUpdateSet.add(service);
143
- service.onFixedUpdate && this.onFixedUpdateSet.add(service);
144
- service.onUpdate && this.onUpdateSet.add(service);
145
- service.onLateUpdate && this.onLateUpdateSet.add(service);
146
- service.onPhysicsUpdate && this.onPhysicsUpdateSet.add(service);
147
- service.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(service);
148
- service.onRender && this.onRenderUpdateSet.add(service);
238
+ async remove(entity: Entity) {
239
+ if ((<any>entity).markRemoval) return;
240
+ (<any>entity).markRemoval = true;
241
+ return new Promise<void>(resolve => this.removeQueue.push([entity, resolve]));
149
242
  }
150
243
 
151
- private addQueue: AddEntry[] = [];
152
- private removeQueue: RemoveEntry[] = [];
244
+ stop() {
245
+ // this.injector.dispose();
246
+ this.clock.stop();
247
+ }
153
248
 
154
- addEntity(entity: Entity) {
155
- return new Promise(resolve => this.addQueue.push([entity.getAllChildren(), resolve]));
249
+ runAction<T extends Action>(action: T): ReturnType<T> {
250
+ return action(this);
156
251
  }
157
252
 
158
- waitFrame() {
159
- return this.framePromise;
253
+ getSignal<T>(signalId: ID): Signal<T> {
254
+ return this.injector.getSignal<T>(signalId);
160
255
  }
161
256
 
162
- async removeEntity(entity: Entity) {
163
- if ((<any>entity).markRemoval) return;
164
- (<any>entity).markRemoval = true;
165
- return new Promise(resolve => this.removeQueue.push([entity.getAllChildren(), resolve]));
257
+ private signalMappings = new Map<Class, [string, Signal][]>();
258
+ private staticSignalMappings = new Map<Class, [string, Signal][]>();
259
+ private signalMapBindings = new Map<Object, SignalBinding[]>();
260
+
261
+ // TODO: staticSignalMapBindings needed if we want to unregister Services or Systems
262
+
263
+ private mapStaticAnnotatedSignals(target: Class) {
264
+ let staticSignalMap = this.getStaticSignalMap(target);
265
+ if (staticSignalMap.length === 0) return;
266
+
267
+ const bindings = [];
268
+ for (const [key, signal] of staticSignalMap) {
269
+ bindings.push(signal.add((<any>target)[key], target));
270
+ }
271
+ // TODO: ignore bindings for now (store them if we implement unregister Service or Systems
166
272
  }
167
273
 
168
- private prepareFrame() {
274
+ private mapAnnotatedSignals(target: Object) {
275
+ const signalMap = this.getSignalMap(target.constructor);
276
+ if (signalMap.length === 0) return;
277
+
278
+ const bindings = [];
279
+ for (const [key, signal] of signalMap) {
280
+ bindings.push(signal.add((<any>target)[key], target));
281
+ }
282
+ this.signalMapBindings.set(target, bindings);
283
+ }
284
+
285
+ private unmapAnnotatedSignals(target: Object) {
286
+ const signalBindings = this.signalMapBindings.get(target);
287
+ if (!signalBindings) return;
288
+ for (const binding of signalBindings) {
289
+ binding.detach();
290
+ }
291
+ }
292
+
293
+ private getSignalMap(target: Function) {
294
+ // TODO: we could speed thinks up by introducing "invisible" flags on the systems/services to avoid a map check
295
+ return putIfAbsent(this.signalMappings, target, (): [string, Signal][] => {
296
+ const handlers = signalHandlers.get(target);
297
+ if (!handlers) return [];
298
+ const result: [string, Signal][] = [];
299
+ for (const [key, signalId] of handlers) {
300
+ result.push([key, this.getSignal(signalId)]);
301
+ }
302
+ return result;
303
+ });
304
+ }
305
+
306
+ private getStaticSignalMap(target: Class) {
307
+ // TODO: we could speed thinks up by introducing "invisible" flags on the systems/services to avoid a map check
308
+ return putIfAbsent(this.staticSignalMappings, target, (): [string, Signal][] => {
309
+ const handlers = staticSignalHandlers.get(target);
310
+ if (!handlers) return [];
311
+ const result: [string, Signal][] = [];
312
+ for (const [key, signalId] of handlers) {
313
+ result.push([key, this.getSignal(signalId)]);
314
+ }
315
+ return result;
316
+ });
317
+ }
169
318
 
170
- for (const [entities, resolve] of this.removeQueue) {
319
+ dispose() {
320
+ this.clock.stop();
321
+ this.clock.dispose();
322
+ for (const systems of this.entitySystemMap.values()) {
323
+ for (const system of systems) {
324
+ system.system.onEnd && system.system.onEnd();
325
+ }
326
+ }
327
+ for (const service of this.services) {
328
+ service.onEnd && service.onEnd();
329
+ }
330
+ this.onEnd.dispatch();
331
+ }
332
+
333
+ private prepareFrame() {
334
+ for (const [entity, resolve] of this.removeQueue) {
335
+ const entities = entity.getAllEntities();
171
336
  for (const entity of entities) {
172
337
  (<any>entity).markRemoval = false;
173
- if (!(<any>entity).gameEngine) throw new Error('Entity not active');
338
+ if (!(<any>entity).gameEngine) {
339
+ console.log(entity);
340
+ // throw new Error('Entity not active');
341
+ }
174
342
  (<any>entity).gameEngine = undefined;
175
343
 
176
- const systems = this.entitySystemMap.get(entity);
344
+ const systemContexts = this.entitySystemMap.get(entity);
177
345
  this.entitySystemMap.delete(entity);
178
- if (systems) {
179
- for (const system of systems) {
346
+ if (systemContexts) {
347
+ for (const context of systemContexts) {
348
+ context.dispose();
349
+ const system = context.system;
180
350
  this.unmapAnnotatedSignals(system);
181
351
  system.onEnd && system.onEnd();
182
352
  system.onPreFixedUpdate && this.onPreFixedUpdateSet.delete(system);
183
353
  system.onFixedUpdate && this.onFixedUpdateSet.delete(system);
184
- system.onEarlyUpdate && this.onEarlyUpdateSet.delete(system);
185
354
  system.onUpdate && this.onUpdateSet.delete(system);
186
355
  system.onLateUpdate && this.onLateUpdateSet.delete(system);
187
356
  system.onPhysicsUpdate && this.onPhysicsUpdateSet.delete(system);
357
+ system.onPrePhysicsUpdate && this.onPrePhysicsUpdateSet.delete(system);
188
358
  system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.delete(system);
359
+ system.onLateFixedUpdate && this.onLateFixedUpdateSet.delete(system);
189
360
  system.onRender && this.onRenderUpdateSet.delete(system);
190
361
  }
191
362
  }
192
363
  entity.onRemove.dispatch();
364
+ entity.onRemove.detachAll();
193
365
  }
194
366
 
195
367
  resolve();
196
368
  }
197
369
  this.removeQueue = [];
198
370
 
199
- for (const [entities, resolve] of this.addQueue) {
371
+ for (const [entity, resolve] of this.addQueue) {
200
372
  const preparePromises = [];
201
- const newSystems: GameSystem[] = [];
373
+ const nexSystemContexts: SystemContext[] = [];
374
+ const entities = entity.getAllEntities();
202
375
  for (const entity of entities) {
203
376
  if ((<any>entity).gameEngine) throw new Error('Entity already added to a gameEngine');
204
377
  (<any>entity).gameEngine = this;
205
- const systems = this.injector.createSystems(entity);
206
- for (const system of systems) {
207
- system.onPrepare && preparePromises.push(system.onPrepare());
208
- newSystems.push(system);
378
+ const systemContexts = this.injector.createSystems(entity);
379
+ for (const context of systemContexts) {
380
+ // TODO: implement synced mode where async onPrepares aren't allowed
381
+ context.system.onPrepare && preparePromises.push(context.system.onPrepare());
382
+ nexSystemContexts.push(context);
209
383
  }
210
- this.entitySystemMap.set(entity, systems);
384
+ this.entitySystemMap.set(entity, systemContexts);
211
385
  }
212
386
 
213
387
  const startSystems = () => {
214
388
  // TODO: check if a "global" method is faster than this inner method
215
- for (const system of newSystems) {
389
+ for (const context of nexSystemContexts) {
390
+ const system = context.system;
216
391
  this.mapAnnotatedSignals(system);
217
392
  system.onStart && system.onStart();
218
393
  system.onPreFixedUpdate && this.onPreFixedUpdateSet.add(system);
219
394
  system.onFixedUpdate && this.onFixedUpdateSet.add(system);
220
- system.onEarlyUpdate && this.onEarlyUpdateSet.add(system);
221
395
  system.onUpdate && this.onUpdateSet.add(system);
222
396
  system.onLateUpdate && this.onLateUpdateSet.add(system);
223
397
  system.onPhysicsUpdate && this.onPhysicsUpdateSet.add(system);
398
+ system.onPrePhysicsUpdate && this.onPrePhysicsUpdateSet.add(system);
224
399
  system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(system);
400
+ system.onLateFixedUpdate && this.onLateFixedUpdateSet.add(system);
225
401
  system.onRender && this.onRenderUpdateSet.add(system);
226
402
  }
227
403
  resolve();
@@ -237,52 +413,10 @@ export class GameEngine {
237
413
  this.addQueue = [];
238
414
  // create promise for next frame
239
415
  this.resolveFrame();
240
- this.framePromise = new Promise<any>(resolve => {
416
+ this.framePromise = new Promise<void>(resolve => {
241
417
  this.resolveFrame = resolve;
242
418
  });
243
- }
244
-
245
- runAction<T extends Action>(action: T): ReturnType<T> {
246
- return action(this);
247
- }
248
-
249
- getSignal<T>(signalId: ID): Signal<T> {
250
- return this.injector.getSignal<T>(signalId);
251
- }
252
-
253
- signalMappings = new Map<Class, [string, Signal][]>();
254
- signalMapBindings = new Map<Object, SignalBinding[]>();
255
-
256
- private mapAnnotatedSignals(target: Object) {
257
- const signalMap = this.getSignalMap(target.constructor);
258
- if (signalMap.length === 0) return;
259
-
260
- const bindings = [];
261
- for (const [key, signal] of signalMap) {
262
- bindings.push(signal.add((<any>target)[key], target));
263
- }
264
- this.signalMapBindings.set(target, bindings);
265
- }
266
-
267
- private unmapAnnotatedSignals(target: Object) {
268
- const signalBindings = this.signalMapBindings.get(target);
269
- if (!signalBindings) return;
270
- for (const binding of signalBindings) {
271
- binding.detach();
272
- }
273
- }
274
-
275
- private getSignalMap(target: Function) {
276
- // TODO: we could speed thinks up by introducing "invisible" flags on the systems/services to avoid a map check
277
- return putIfAbsent(this.signalMappings, target, (): [string, Signal][] => {
278
- const handlers = signalHandlers.get(target);
279
- if (!handlers) return [];
280
- const result: [string, Signal][] = [];
281
- for (const [key, signalId] of handlers) {
282
- result.push([key, this.getSignal(signalId)]);
283
- }
284
- return result;
285
- });
419
+ this.onPrepare.dispatch();
286
420
  }
287
421
  }
288
422
  //
package/src/index.ts CHANGED
@@ -1,9 +1,18 @@
1
1
  export * from './gameEngine';
2
2
  export * from './entity';
3
3
  export * from './types';
4
- export {EcsInjector, EntityComponent, GetComponent, GetEntity} from './ecsInjector';
4
+ export * from './scope/scopeContext';
5
+ export * from './systemContext';
6
+ export {EcsInjector, EntityComponent, GetComponent, GetEntity, GetContext, GetSignal, OnSignal} from './ecsInjector';
5
7
 
6
8
  // intellij doesnt auto resolve imports if we just export * from an external dependency
7
- import {Inject, InjectId, Injector, InjectType} from 'mani-injector';
8
9
 
9
- export {Injector, InjectType, InjectId, Inject};
10
+ import {ID, Inject, InjectId, Injector, InjectType, putIfAbsent} from './injector';
11
+ import {Signal, SignalBinding, SignalCallback} from 'mani-signal';
12
+ import {Clock} from './clock';
13
+
14
+ export {Injector, InjectType, InjectId, Inject, putIfAbsent, ID};
15
+
16
+ export {Clock};
17
+
18
+ export {Signal, SignalBinding, SignalCallback};