mani-game-engine 1.0.0-pre.7 → 1.0.0-pre.71
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/LICENSE +1 -1
- package/lib/clock.d.ts +57 -0
- package/lib/clock.js +121 -0
- package/lib/clock.js.map +1 -0
- package/lib/ecsInjector.d.ts +45 -0
- package/lib/ecsInjector.js +220 -0
- package/lib/ecsInjector.js.map +1 -0
- package/lib/entity.d.ts +37 -0
- package/lib/entity.js +176 -0
- package/lib/entity.js.map +1 -0
- package/lib/gameEngine.d.ts +96 -0
- package/lib/gameEngine.js +445 -0
- package/lib/gameEngine.js.map +1 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.js +37 -0
- package/lib/index.js.map +1 -0
- package/lib/injector.d.ts +130 -0
- package/lib/injector.js +324 -0
- package/lib/injector.js.map +1 -0
- package/lib/scope/scopeContext.d.ts +76 -0
- package/lib/scope/scopeContext.js +306 -0
- package/lib/scope/scopeContext.js.map +1 -0
- package/lib/systemContext.d.ts +15 -0
- package/lib/systemContext.js +39 -0
- package/lib/systemContext.js.map +1 -0
- package/lib/types.d.ts +83 -0
- package/lib/types.js +20 -0
- package/lib/types.js.map +1 -0
- package/lib/utils/map2k.d.ts +6 -0
- package/lib/utils/map2k.js +44 -0
- package/lib/utils/map2k.js.map +1 -0
- package/package.json +12 -15
- package/src/clock.ts +133 -81
- package/src/ecsInjector.ts +131 -36
- package/src/entity.ts +105 -5
- package/src/gameEngine.ts +483 -353
- package/src/index.ts +25 -9
- package/src/injector.ts +410 -0
- package/src/scope/scopeContext.ts +118 -32
- package/src/systemContext.ts +20 -2
- package/src/types.ts +24 -10
package/src/gameEngine.ts
CHANGED
|
@@ -1,413 +1,543 @@
|
|
|
1
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
4
|
import {EcsInjector, signalHandlers, staticSignalHandlers} from './ecsInjector';
|
|
6
5
|
import {Clock, GameClock} from './clock';
|
|
7
6
|
import {SystemContext} from './systemContext';
|
|
7
|
+
import {ID, putIfAbsent} from './injector';
|
|
8
8
|
|
|
9
9
|
type AddEntry = [Entity, () => void];
|
|
10
10
|
type RemoveEntry = [Entity, () => void];
|
|
11
11
|
|
|
12
12
|
const defaultOptions = {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
fixedDeltaTime: 1 / 60,
|
|
14
|
+
plugins: [] as GameEnginePlugin[],
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export type GameEngineOptions = Partial<typeof defaultOptions>;
|
|
18
18
|
declare global {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
interface GameEngineActions {
|
|
20
|
+
'testAction': string;
|
|
21
|
+
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
type GameEngineActionParams<K extends keyof GameEngineActions> = GameEngineActions[K];
|
|
25
25
|
type GameAction<K extends keyof GameEngineActions> = (engine: GameEngine, params: GameEngineActionParams<K>) => Promise<any> | any;
|
|
26
26
|
|
|
27
|
+
let id = 0;
|
|
27
28
|
export class GameEngine {
|
|
29
|
+
readonly id = id++;
|
|
30
|
+
readonly onPrepare: Signal;
|
|
31
|
+
readonly onStart: Signal;
|
|
32
|
+
readonly onEnd: Signal;
|
|
33
|
+
readonly onRender: Signal<OnUpdateParams>;
|
|
34
|
+
readonly onUpdate: Signal<OnUpdateParams>;
|
|
35
|
+
readonly onFixedUpdate: Signal<OnFixedUpdateParams>;
|
|
36
|
+
readonly onPrePhysicsUpdate: Signal<OnFixedUpdateParams>;
|
|
37
|
+
readonly onPhysicsUpdate: Signal<OnFixedUpdateParams>;
|
|
38
|
+
readonly onPostPhysicsUpdate: Signal<OnFixedUpdateParams>;
|
|
39
|
+
readonly onLateFixedUpdate: Signal<OnFixedUpdateParams>;
|
|
40
|
+
readonly onLateUpdate: Signal<OnUpdateParams>;
|
|
41
|
+
readonly onAddEntity: Signal<Entity>;
|
|
42
|
+
readonly onRemoveEntity: Signal<Entity>;
|
|
43
|
+
|
|
44
|
+
private readonly onEarlyUpdateSet = new Set<System>();
|
|
45
|
+
private readonly onUpdateSet = new Set<System>();
|
|
46
|
+
private readonly onFixedUpdateSet = new Set<System>();
|
|
47
|
+
private readonly onPreFixedUpdateSet = new Set<System>();
|
|
48
|
+
private readonly onPhysicsUpdateSet = new Set<System>();
|
|
49
|
+
private readonly onPrePhysicsUpdateSet = new Set<System>();
|
|
50
|
+
private readonly onPostPhysicsUpdateSet = new Set<System>();
|
|
51
|
+
private readonly onLateFixedUpdateSet = new Set<System>();
|
|
52
|
+
private readonly onLateUpdateSet = new Set<System>();
|
|
53
|
+
private readonly onRenderUpdateSet = new Set<System>();
|
|
54
|
+
private readonly onAddEntitySet = new Set<System>();
|
|
55
|
+
private readonly onRemoveEntitySet = new Set<System>();
|
|
28
56
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
readonly onRender: Signal<OnUpdateParams>;
|
|
32
|
-
readonly onUpdate: Signal<OnUpdateParams>;
|
|
33
|
-
readonly onFixedUpdate: Signal<OnFixedUpdateParams>;
|
|
34
|
-
readonly onPostPhysics: Signal<OnFixedUpdateParams>;
|
|
35
|
-
readonly onLateFixedUpdate: Signal<OnFixedUpdateParams>;
|
|
36
|
-
readonly onLateUpdate: Signal<OnUpdateParams>;
|
|
57
|
+
// TODO: for performance, we could store the systems directly in the entity
|
|
58
|
+
private readonly entitySystemMap = new Map<Entity, Set<SystemContext>>();
|
|
37
59
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
private readonly onPreFixedUpdateSet = new Set<System>();
|
|
42
|
-
private readonly onPhysicsUpdateSet = new Set<System>();
|
|
43
|
-
private readonly onPostPhysicsUpdateSet = new Set<System>();
|
|
44
|
-
private readonly onLateFixedUpdateSet = new Set<System>();
|
|
45
|
-
private readonly onLateUpdateSet = new Set<System>();
|
|
46
|
-
private readonly onRenderUpdateSet = new Set<System>();
|
|
60
|
+
private readonly registeredServices = new Set<Class<Service>>();
|
|
61
|
+
private readonly services: Service[] = [];
|
|
62
|
+
private readonly systemChildInjectors = new Map<object, EcsInjector>();
|
|
47
63
|
|
|
48
|
-
|
|
64
|
+
private framePromise!: Promise<any>;
|
|
65
|
+
private resolveFrame: () => void = () => undefined;
|
|
49
66
|
|
|
50
|
-
|
|
51
|
-
|
|
67
|
+
private addQueue: AddEntry[] = [];
|
|
68
|
+
private removeQueue: RemoveEntry[] = [];
|
|
52
69
|
|
|
53
|
-
|
|
54
|
-
private resolveFrame: () => void = () => undefined;
|
|
70
|
+
private _started = false;
|
|
55
71
|
|
|
56
|
-
|
|
57
|
-
private removeQueue: RemoveEntry[] = [];
|
|
72
|
+
get started(): boolean { return this._started; }
|
|
58
73
|
|
|
59
|
-
|
|
74
|
+
private _frameCount = 0;
|
|
75
|
+
get frameCount(): number { return this._frameCount; }
|
|
60
76
|
|
|
61
|
-
|
|
77
|
+
private _fixedFrameCount = 0;
|
|
78
|
+
get fixedFrameCount(): number { return this._fixedFrameCount; }
|
|
62
79
|
|
|
63
|
-
|
|
64
|
-
get frameCount(): number { return this._frameCount; }
|
|
80
|
+
get numEntities(): number { return this.entitySystemMap.size;}
|
|
65
81
|
|
|
66
|
-
private _fixedFrameCount = 0;
|
|
67
|
-
get fixedFrameCount(): number { return this._fixedFrameCount; }
|
|
68
82
|
|
|
69
|
-
get numEntities(): number { return this.entitySystemMap.size;}
|
|
70
83
|
|
|
71
84
|
// TODO inject clock into game engine
|
|
72
85
|
// TODO inject space into game engine
|
|
73
86
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
constructor(
|
|
88
|
+
readonly injector: EcsInjector<Class<System>>,
|
|
89
|
+
readonly clock: Clock,
|
|
90
|
+
) {
|
|
91
|
+
this.injector.map(GameEngine).toValue(this);
|
|
92
|
+
|
|
93
|
+
this.onPrepare = this.injector.getSignal(EngineSignals.OnPrepare);
|
|
94
|
+
this.onStart = this.injector.getSignal(EngineSignals.OnStart);
|
|
95
|
+
this.onEnd = this.injector.getSignal(EngineSignals.OnEnd);
|
|
96
|
+
this.onRender = this.injector.getSignal(EngineSignals.OnRender);
|
|
97
|
+
this.onFixedUpdate = this.injector.getSignal(EngineSignals.OnFixedUpdate);
|
|
98
|
+
this.onUpdate = this.injector.getSignal(EngineSignals.OnUpdate);
|
|
99
|
+
this.onLateUpdate = this.injector.getSignal(EngineSignals.OnLateUpdate);
|
|
100
|
+
this.onPrePhysicsUpdate = this.injector.getSignal(EngineSignals.OnPrePhysicsUpdate);
|
|
101
|
+
this.onPhysicsUpdate = this.injector.getSignal(EngineSignals.OnPhysicsUpdate);
|
|
102
|
+
this.onPostPhysicsUpdate = this.injector.getSignal(EngineSignals.OnPostPhysicsUpdate);
|
|
103
|
+
this.onLateFixedUpdate = this.injector.getSignal(EngineSignals.onLateFixedUpdate);
|
|
104
|
+
|
|
105
|
+
this.onAddEntity = this.injector.getSignal(EngineSignals.OnAddEntity);
|
|
106
|
+
this.onRemoveEntity = this.injector.getSignal(EngineSignals.OnRemoveEntity);
|
|
107
|
+
|
|
108
|
+
this.setupClock();
|
|
109
|
+
this.prepareFrame();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static createDefault(options?: GameEngineOptions) {
|
|
113
|
+
const opts = {...defaultOptions, ...options};
|
|
114
|
+
const clock = new GameClock({
|
|
115
|
+
fixedDeltaTime: opts.fixedDeltaTime,
|
|
116
|
+
autoStart: false,
|
|
117
|
+
});
|
|
118
|
+
const injector = new EcsInjector<Class<System>>();
|
|
119
|
+
const engine = new GameEngine(injector, clock);
|
|
120
|
+
engine.installPlugins(opts.plugins);
|
|
121
|
+
return engine;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static createDefaultWithInjector(injector: EcsInjector<Class<System>>, options?: GameEngineOptions) {
|
|
125
|
+
const opts = {...defaultOptions, ...options};
|
|
126
|
+
const clock = new GameClock({
|
|
127
|
+
fixedDeltaTime: opts.fixedDeltaTime,
|
|
128
|
+
autoStart: false,
|
|
129
|
+
});
|
|
130
|
+
const engine = new GameEngine(injector, clock);
|
|
131
|
+
engine.installPlugins(opts.plugins);
|
|
132
|
+
return engine;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// TODO: test
|
|
136
|
+
addServiceClass<T extends Class<Service>>(serviceClass: T, mapping?: (injector: EcsInjector) => void): InstanceType<T> {
|
|
137
|
+
let childInjector: EcsInjector | undefined;
|
|
138
|
+
if (mapping) {
|
|
139
|
+
childInjector = this.injector.createChild();
|
|
140
|
+
mapping(childInjector);
|
|
91
141
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
autoStart: false,
|
|
98
|
-
});
|
|
99
|
-
const injector = new EcsInjector<Class<System>>();
|
|
100
|
-
const engine = new GameEngine(injector, clock);
|
|
101
|
-
engine.installPlugins(opts.plugins);
|
|
102
|
-
return engine;
|
|
142
|
+
this.mapStaticAnnotatedSignals(serviceClass);
|
|
143
|
+
const service = childInjector?.createInstance(serviceClass) || this.injector.createInstance(serviceClass);
|
|
144
|
+
this.addService(service);
|
|
145
|
+
if (childInjector) {
|
|
146
|
+
this.systemChildInjectors.set(service, childInjector);
|
|
103
147
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
148
|
+
return service;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private addService(service: Service): void {
|
|
152
|
+
this.mapAnnotatedSignals(service);
|
|
153
|
+
service.onStart && service.onStart();
|
|
154
|
+
service.onPreFixedUpdate && this.onPreFixedUpdateSet.add(service);
|
|
155
|
+
service.onFixedUpdate && this.onFixedUpdateSet.add(service);
|
|
156
|
+
service.onUpdate && this.onUpdateSet.add(service);
|
|
157
|
+
service.onLateUpdate && this.onLateUpdateSet.add(service);
|
|
158
|
+
service.onPrePhysicsUpdate && this.onPrePhysicsUpdateSet.add(service);
|
|
159
|
+
service.onPhysicsUpdate && this.onPhysicsUpdateSet.add(service);
|
|
160
|
+
service.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(service);
|
|
161
|
+
service.onLateFixedUpdate && this.onLateFixedUpdateSet.add(service);
|
|
162
|
+
service.onRender && this.onRenderUpdateSet.add(service);
|
|
163
|
+
service.onAddEntity && this.onAddEntitySet.add(service);
|
|
164
|
+
service.onRemoveEntity && this.onRemoveEntitySet.add(service);
|
|
165
|
+
this.services.push(service);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
removeService(service: Service): void {
|
|
169
|
+
const index = this.services.indexOf(service);
|
|
170
|
+
if (index === -1) return;
|
|
171
|
+
this.services.splice(index, 1);
|
|
172
|
+
this.unmapAnnotatedSignals(service);
|
|
173
|
+
service.onPreFixedUpdate && this.onPreFixedUpdateSet.delete(service);
|
|
174
|
+
service.onFixedUpdate && this.onFixedUpdateSet.delete(service);
|
|
175
|
+
service.onUpdate && this.onUpdateSet.delete(service);
|
|
176
|
+
service.onLateUpdate && this.onLateUpdateSet.delete(service);
|
|
177
|
+
service.onPrePhysicsUpdate && this.onPrePhysicsUpdateSet.delete(service);
|
|
178
|
+
service.onPhysicsUpdate && this.onPhysicsUpdateSet.delete(service);
|
|
179
|
+
service.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.delete(service);
|
|
180
|
+
service.onLateFixedUpdate && this.onLateFixedUpdateSet.delete(service);
|
|
181
|
+
service.onRender && this.onRenderUpdateSet.delete(service);
|
|
182
|
+
service.onAddEntity && this.onAddEntitySet.delete(service);
|
|
183
|
+
service.onRemoveEntity && this.onRemoveEntitySet.delete(service);
|
|
184
|
+
service.onEnd && service.onEnd();
|
|
185
|
+
const childInjector = this.systemChildInjectors.get(service);
|
|
186
|
+
if (childInjector) {
|
|
187
|
+
childInjector.dispose();
|
|
188
|
+
this.systemChildInjectors.delete(service);
|
|
114
189
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
installPlugins(plugins: GameEnginePlugin[]) {
|
|
193
|
+
plugins.forEach(plugin => {
|
|
194
|
+
plugin.onPrepare && plugin.onPrepare(this);
|
|
195
|
+
});
|
|
196
|
+
plugins.forEach(plugin => {
|
|
197
|
+
plugin.onStart && plugin.onStart(this);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
registerSystem(systemClass: Class<System>): void {
|
|
202
|
+
this.mapStaticAnnotatedSignals(systemClass);
|
|
203
|
+
if (this._started) throw new Error('Register Systems before engine is started');
|
|
204
|
+
this.injector.registerSystem(systemClass);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
registerService(serviceClass: Class<Service>): void {
|
|
208
|
+
this.mapStaticAnnotatedSignals(serviceClass);
|
|
209
|
+
if (this._started) throw new Error('Register Services before engine is started');
|
|
210
|
+
this.injector.map(serviceClass).toSingleton();
|
|
211
|
+
this.registeredServices.add(serviceClass);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
getService<T extends Class<Service>>(serviceClass: T): InstanceType<T> {
|
|
215
|
+
return this.injector.get(serviceClass);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
start() {
|
|
219
|
+
this._started = true;
|
|
220
|
+
//TODO: throw when registering services or systems when engine is running
|
|
221
|
+
for (const serviceClass of this.registeredServices) {
|
|
222
|
+
const service = this.injector.get(serviceClass);
|
|
223
|
+
this.addService(service);
|
|
128
224
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
225
|
+
this.clock.start();
|
|
226
|
+
this.onStart.dispatch();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private setupClock() {
|
|
230
|
+
this.clock.onPrepare.add(this.prepareFrame, this);
|
|
231
|
+
|
|
232
|
+
this.clock.onEarlyUpdate.add(({time, deltaTime}) => {
|
|
233
|
+
for (const system of this.onEarlyUpdateSet) {
|
|
234
|
+
system.onEarlyUpdate!(time, deltaTime);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
this.clock.onFixedUpdate.add((params) => {
|
|
239
|
+
const {time, deltaTime} = params;
|
|
240
|
+
for (const system of this.onPreFixedUpdateSet) {
|
|
241
|
+
system.onPreFixedUpdate!(time, deltaTime);
|
|
242
|
+
}
|
|
243
|
+
this.onFixedUpdate.dispatch(params);
|
|
244
|
+
for (const system of this.onFixedUpdateSet) {
|
|
245
|
+
system.onFixedUpdate!(time, deltaTime);
|
|
246
|
+
}
|
|
247
|
+
this.onPhysicsUpdate.dispatch(params);
|
|
248
|
+
for (const system of this.onPhysicsUpdateSet) {
|
|
249
|
+
system.onPhysicsUpdate!(time, deltaTime);
|
|
250
|
+
}
|
|
251
|
+
this.onPostPhysicsUpdate.dispatch(params);
|
|
252
|
+
for (const system of this.onPostPhysicsUpdateSet) {
|
|
253
|
+
system.onPostPhysicsUpdate!(time, deltaTime);
|
|
254
|
+
}
|
|
255
|
+
this.onLateFixedUpdate.dispatch(params);
|
|
256
|
+
for (const system of this.onLateFixedUpdateSet) {
|
|
257
|
+
system.onLateFixedUpdate!(time, deltaTime);
|
|
258
|
+
}
|
|
259
|
+
this._fixedFrameCount++;
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// TODO: update from outside
|
|
263
|
+
this.clock.onUpdate.add(onUpdateParams => {
|
|
264
|
+
const {time, deltaTime, alpha} = onUpdateParams;
|
|
265
|
+
this.onUpdate.dispatch(onUpdateParams);
|
|
266
|
+
for (const system of this.onUpdateSet) {
|
|
267
|
+
system.onUpdate!(time, deltaTime, alpha);
|
|
268
|
+
}
|
|
269
|
+
//TODO: merge with framerate to single signal?
|
|
270
|
+
this.onLateUpdate.dispatch(onUpdateParams);
|
|
271
|
+
for (const system of this.onLateUpdateSet) {
|
|
272
|
+
system.onLateUpdate!(time, deltaTime, alpha);
|
|
273
|
+
}
|
|
274
|
+
this.onRender.dispatch(onUpdateParams);
|
|
275
|
+
for (const system of this.onRenderUpdateSet) {
|
|
276
|
+
system.onRender!(time, deltaTime, alpha);
|
|
277
|
+
}
|
|
278
|
+
this._frameCount++;
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
add(entity: Entity) {
|
|
283
|
+
return new Promise<void>(resolve => this.addQueue.push([entity, resolve]));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
addAll(entity: Entity[]) {
|
|
287
|
+
return Promise.all(entity.map(entity => new Promise<void>(resolve => this.addQueue.push([entity, resolve]))));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
waitFrame() {
|
|
291
|
+
return this.framePromise;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async remove(entity: Entity) {
|
|
295
|
+
if ((<any>entity).markRemoval) return;
|
|
296
|
+
(<any>entity).markRemoval = true;
|
|
297
|
+
return new Promise<void>(resolve => this.removeQueue.push([entity, resolve]));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
async removeAll(entities: Entity[]) {
|
|
301
|
+
return Promise.all(entities.map(entity => this.remove(entity)));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
stop() {
|
|
305
|
+
// this.injector.dispose();
|
|
306
|
+
this.clock.stop();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
runAction<T extends Action>(action: T): ReturnType<T> {
|
|
310
|
+
return action(this);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
getSignal<T>(signalId: ID): Signal<T> {
|
|
314
|
+
return this.injector.getSignal<T>(signalId);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private signalMappings = new Map<Class, [string, Signal][]>();
|
|
318
|
+
private staticSignalMappings = new Map<Class, [string, Signal][]>();
|
|
319
|
+
private signalMapBindings = new Map<Object, SignalBinding[]>();
|
|
320
|
+
|
|
321
|
+
// TODO: staticSignalMapBindings needed if we want to unregister Services or Systems
|
|
322
|
+
|
|
323
|
+
private mapStaticAnnotatedSignals(target: Class) {
|
|
324
|
+
let staticSignalMap = this.getStaticSignalMap(target);
|
|
325
|
+
if (staticSignalMap.length === 0) return;
|
|
326
|
+
|
|
327
|
+
const bindings = [];
|
|
328
|
+
for (const [key, signal] of staticSignalMap) {
|
|
329
|
+
bindings.push(signal.add((<any>target)[key], target));
|
|
137
330
|
}
|
|
331
|
+
// TODO: ignore bindings for now (store them if we implement unregister Service or Systems
|
|
332
|
+
}
|
|
138
333
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
this.injector.registerSystem(systemClass);
|
|
143
|
-
}
|
|
334
|
+
private mapAnnotatedSignals(target: Object) {
|
|
335
|
+
const signalMap = this.getSignalMap(target.constructor);
|
|
336
|
+
if (signalMap.length === 0) return;
|
|
144
337
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.injector.map(serviceClass).toSingleton();
|
|
149
|
-
this.serviceClasses.add(serviceClass);
|
|
338
|
+
const bindings = [];
|
|
339
|
+
for (const [key, signal] of signalMap) {
|
|
340
|
+
bindings.push(signal.add((<any>target)[key], target));
|
|
150
341
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
342
|
+
this.signalMapBindings.set(target, bindings);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
private unmapAnnotatedSignals(target: Object) {
|
|
346
|
+
const signalBindings = this.signalMapBindings.get(target);
|
|
347
|
+
if (!signalBindings) return;
|
|
348
|
+
for (const binding of signalBindings) {
|
|
349
|
+
binding.detach();
|
|
154
350
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this.
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private getSignalMap(target: Function) {
|
|
354
|
+
// TODO: we could speed thinks up by introducing "invisible" flags on the systems/services to avoid a map check
|
|
355
|
+
return putIfAbsent(this.signalMappings, target, (): [string, Signal][] => {
|
|
356
|
+
const handlers = signalHandlers.get(target);
|
|
357
|
+
if (!handlers) return [];
|
|
358
|
+
const result: [string, Signal][] = [];
|
|
359
|
+
for (const [key, signalId] of handlers) {
|
|
360
|
+
result.push([key, this.getSignal(signalId)]);
|
|
361
|
+
}
|
|
362
|
+
return result;
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private getStaticSignalMap(target: Class) {
|
|
367
|
+
// TODO: we could speed thinks up by introducing "invisible" flags on the systems/services to avoid a map check
|
|
368
|
+
return putIfAbsent(this.staticSignalMappings, target, (): [string, Signal][] => {
|
|
369
|
+
const handlers = staticSignalHandlers.get(target);
|
|
370
|
+
if (!handlers) return [];
|
|
371
|
+
const result: [string, Signal][] = [];
|
|
372
|
+
for (const [key, signalId] of handlers) {
|
|
373
|
+
result.push([key, this.getSignal(signalId)]);
|
|
374
|
+
}
|
|
375
|
+
return result;
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
dispose() {
|
|
380
|
+
this.clock.stop();
|
|
381
|
+
this.clock.dispose();
|
|
382
|
+
for (const systems of this.entitySystemMap.values()) {
|
|
383
|
+
for (const context of systems) {
|
|
384
|
+
context.system.onEnd && context.system.onEnd();
|
|
385
|
+
this.unmapAnnotatedSignals(context.system);
|
|
386
|
+
}
|
|
165
387
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
this.clock.onEarlyUpdate.add(({time, deltaTime}) => {
|
|
171
|
-
for (const system of this.onEarlyUpdateSet) {
|
|
172
|
-
system.onEarlyUpdate!(time, deltaTime);
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
this.clock.onFixedUpdate.add((params) => {
|
|
177
|
-
const {time, deltaTime} = params;
|
|
178
|
-
for (const system of this.onPreFixedUpdateSet) {
|
|
179
|
-
system.onPreFixedUpdate!();
|
|
180
|
-
}
|
|
181
|
-
for (const system of this.onFixedUpdateSet) {
|
|
182
|
-
system.onFixedUpdate!(time, deltaTime);
|
|
183
|
-
}
|
|
184
|
-
this.onFixedUpdate.dispatch(params);
|
|
185
|
-
for (const system of this.onPhysicsUpdateSet) {
|
|
186
|
-
system.onPhysicsUpdate!(time, deltaTime);
|
|
187
|
-
}
|
|
188
|
-
this.onPostPhysics.dispatch(params);
|
|
189
|
-
for (const system of this.onPostPhysicsUpdateSet) {
|
|
190
|
-
system.onPostPhysicsUpdate!(time, deltaTime);
|
|
191
|
-
}
|
|
192
|
-
this.onLateFixedUpdate.dispatch(params);
|
|
193
|
-
for (const system of this.onLateFixedUpdateSet) {
|
|
194
|
-
system.onLateFixedUpdate!(time, deltaTime);
|
|
195
|
-
}
|
|
196
|
-
this._fixedFrameCount++;
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// TODO: update from outside
|
|
200
|
-
this.clock.onUpdate.add(onUpdateParams => {
|
|
201
|
-
const {time, deltaTime, alpha} = onUpdateParams;
|
|
202
|
-
for (const system of this.onUpdateSet) {
|
|
203
|
-
system.onUpdate!(time, deltaTime, alpha);
|
|
204
|
-
}
|
|
205
|
-
//TODO: merge with framerate to single signal?
|
|
206
|
-
|
|
207
|
-
this.onUpdate.dispatch(onUpdateParams);
|
|
208
|
-
for (const system of this.onLateUpdateSet) {
|
|
209
|
-
system.onLateUpdate!(time, deltaTime, alpha);
|
|
210
|
-
}
|
|
211
|
-
this.onLateUpdate.dispatch(onUpdateParams);
|
|
212
|
-
|
|
213
|
-
for (const system of this.onRenderUpdateSet) {
|
|
214
|
-
system.onRender!(time, deltaTime, alpha);
|
|
215
|
-
}
|
|
216
|
-
this.onRender.dispatch(onUpdateParams);
|
|
217
|
-
this._frameCount++;
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
add(entity: Entity) {
|
|
222
|
-
return new Promise<void>(resolve => this.addQueue.push([entity, resolve]));
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
waitFrame() {
|
|
226
|
-
return this.framePromise;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async remove(entity: Entity) {
|
|
230
|
-
if ((<any>entity).markRemoval) return;
|
|
231
|
-
(<any>entity).markRemoval = true;
|
|
232
|
-
return new Promise<void>(resolve => this.removeQueue.push([entity, resolve]));
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
stop() {
|
|
236
|
-
// this.injector.dispose();
|
|
237
|
-
this.clock.stop();
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
runAction<T extends Action>(action: T): ReturnType<T> {
|
|
241
|
-
return action(this);
|
|
388
|
+
for (const service of this.services) {
|
|
389
|
+
service.onEnd && service.onEnd();
|
|
390
|
+
this.unmapAnnotatedSignals(service);
|
|
242
391
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
392
|
+
this.onEnd.dispatch();
|
|
393
|
+
|
|
394
|
+
this.onAddEntity.detachAll();
|
|
395
|
+
this.onRemoveEntity.detachAll();
|
|
396
|
+
this.onPrepare.detachAll();
|
|
397
|
+
this.onStart.detachAll();
|
|
398
|
+
this.onEnd.detachAll();
|
|
399
|
+
this.onRender.detachAll();
|
|
400
|
+
this.onUpdate.detachAll();
|
|
401
|
+
this.onFixedUpdate.detachAll();
|
|
402
|
+
this.onPrePhysicsUpdate.detachAll();
|
|
403
|
+
this.onPhysicsUpdate.detachAll();
|
|
404
|
+
this.onPostPhysicsUpdate.detachAll();
|
|
405
|
+
this.onLateFixedUpdate.detachAll();
|
|
406
|
+
this.onPhysicsUpdateSet.clear();
|
|
407
|
+
this.onPrePhysicsUpdateSet.clear();
|
|
408
|
+
this.onPostPhysicsUpdateSet.clear();
|
|
409
|
+
this.onLateFixedUpdateSet.clear();
|
|
410
|
+
this.onLateUpdate.detachAll();
|
|
411
|
+
this.onUpdate.detachAll();
|
|
412
|
+
this.onFixedUpdate.detachAll();
|
|
413
|
+
this.onRender.detachAll();
|
|
414
|
+
this.onAddEntity.detachAll();
|
|
415
|
+
this.onRemoveEntity.detachAll();
|
|
416
|
+
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
private prepareFrame() {
|
|
420
|
+
for (const [entity, resolve] of this.removeQueue) {
|
|
421
|
+
const entities = entity.getAllEntities();
|
|
422
|
+
for (const entity of entities) {
|
|
423
|
+
(<any>entity).markRemoval = false;
|
|
424
|
+
if (!(<any>entity).gameEngine) {
|
|
425
|
+
console.log('Entity not active', entity);
|
|
426
|
+
// throw new Error('Entity not active');
|
|
261
427
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
for (const [key, signal] of signalMap) {
|
|
271
|
-
bindings.push(signal.add((<any>target)[key], target));
|
|
428
|
+
(<any>entity).gameEngine = undefined;
|
|
429
|
+
|
|
430
|
+
const systemContexts = this.entitySystemMap.get(entity);
|
|
431
|
+
this.entitySystemMap.delete(entity);
|
|
432
|
+
if (systemContexts) {
|
|
433
|
+
for (const context of systemContexts) {
|
|
434
|
+
this.disposeContext(context);
|
|
435
|
+
}
|
|
272
436
|
}
|
|
273
|
-
|
|
274
|
-
|
|
437
|
+
entity.onRemove.dispatch();
|
|
438
|
+
entity.onRemove.detachAll();
|
|
439
|
+
entity._signalMap.forEach(signal => signal.detachAll());
|
|
275
440
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (!signalBindings) return;
|
|
279
|
-
for (const binding of signalBindings) {
|
|
280
|
-
binding.detach();
|
|
441
|
+
for (const system of this.onRemoveEntitySet) {
|
|
442
|
+
system.onRemoveEntity!(entity);
|
|
281
443
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
private getSignalMap(target: Function) {
|
|
285
|
-
// TODO: we could speed thinks up by introducing "invisible" flags on the systems/services to avoid a map check
|
|
286
|
-
return putIfAbsent(this.signalMappings, target, (): [string, Signal][] => {
|
|
287
|
-
const handlers = signalHandlers.get(target);
|
|
288
|
-
if (!handlers) return [];
|
|
289
|
-
const result: [string, Signal][] = [];
|
|
290
|
-
for (const [key, signalId] of handlers) {
|
|
291
|
-
result.push([key, this.getSignal(signalId)]);
|
|
292
|
-
}
|
|
293
|
-
return result;
|
|
294
|
-
});
|
|
295
|
-
}
|
|
444
|
+
}
|
|
296
445
|
|
|
297
|
-
|
|
298
|
-
// TODO: we could speed thinks up by introducing "invisible" flags on the systems/services to avoid a map check
|
|
299
|
-
return putIfAbsent(this.staticSignalMappings, target, (): [string, Signal][] => {
|
|
300
|
-
const handlers = staticSignalHandlers.get(target);
|
|
301
|
-
if (!handlers) return [];
|
|
302
|
-
const result: [string, Signal][] = [];
|
|
303
|
-
for (const [key, signalId] of handlers) {
|
|
304
|
-
result.push([key, this.getSignal(signalId)]);
|
|
305
|
-
}
|
|
306
|
-
return result;
|
|
307
|
-
});
|
|
446
|
+
resolve();
|
|
308
447
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
448
|
+
this.removeQueue = [];
|
|
449
|
+
|
|
450
|
+
for (const [entity, resolve] of this.addQueue) {
|
|
451
|
+
const preparePromises = [];
|
|
452
|
+
const nextSystemContexts: SystemContext[] = [];
|
|
453
|
+
const entities = entity.getAllEntities();
|
|
454
|
+
for (const entity of entities) {
|
|
455
|
+
if ((<any>entity).gameEngine) throw new Error('Entity already added to a gameEngine');
|
|
456
|
+
(<any>entity).gameEngine = this;
|
|
457
|
+
const systemContexts = this.injector.createSystemsForEntity(entity);
|
|
458
|
+
for (const context of systemContexts) {
|
|
459
|
+
// TODO: implement synced mode where async onPrepares aren't allowed
|
|
460
|
+
context.system.onPrepare && preparePromises.push(context.system.onPrepare());
|
|
461
|
+
nextSystemContexts.push(context);
|
|
319
462
|
}
|
|
320
|
-
|
|
463
|
+
this.entitySystemMap.set(entity, systemContexts);
|
|
464
|
+
}
|
|
321
465
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const entities = entity.getAllEntities();
|
|
326
|
-
for (const entity of entities) {
|
|
327
|
-
(<any>entity).markRemoval = false;
|
|
328
|
-
if (!(<any>entity).gameEngine) {
|
|
329
|
-
console.log(entity);
|
|
330
|
-
// throw new Error('Entity not active');
|
|
331
|
-
}
|
|
332
|
-
(<any>entity).gameEngine = undefined;
|
|
333
|
-
|
|
334
|
-
const systemContexts = this.entitySystemMap.get(entity);
|
|
335
|
-
this.entitySystemMap.delete(entity);
|
|
336
|
-
if (systemContexts) {
|
|
337
|
-
for (const context of systemContexts) {
|
|
338
|
-
context.dispose();
|
|
339
|
-
const system = context.system;
|
|
340
|
-
this.unmapAnnotatedSignals(system);
|
|
341
|
-
system.onEnd && system.onEnd();
|
|
342
|
-
system.onPreFixedUpdate && this.onPreFixedUpdateSet.delete(system);
|
|
343
|
-
system.onFixedUpdate && this.onFixedUpdateSet.delete(system);
|
|
344
|
-
system.onEarlyUpdate && this.onEarlyUpdateSet.delete(system);
|
|
345
|
-
system.onUpdate && this.onUpdateSet.delete(system);
|
|
346
|
-
system.onLateUpdate && this.onLateUpdateSet.delete(system);
|
|
347
|
-
system.onPhysicsUpdate && this.onPhysicsUpdateSet.delete(system);
|
|
348
|
-
system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.delete(system);
|
|
349
|
-
system.onLateFixedUpdate && this.onLateFixedUpdateSet.delete(system);
|
|
350
|
-
system.onRender && this.onRenderUpdateSet.delete(system);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
entity.onRemove.dispatch();
|
|
354
|
-
entity.onRemove.detachAll();
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
resolve();
|
|
358
|
-
}
|
|
359
|
-
this.removeQueue = [];
|
|
360
|
-
|
|
361
|
-
for (const [entity, resolve] of this.addQueue) {
|
|
362
|
-
const preparePromises = [];
|
|
363
|
-
const nexSystemContexts: SystemContext[] = [];
|
|
364
|
-
const entities = entity.getAllEntities();
|
|
365
|
-
for (const entity of entities) {
|
|
366
|
-
if ((<any>entity).gameEngine) throw new Error('Entity already added to a gameEngine');
|
|
367
|
-
(<any>entity).gameEngine = this;
|
|
368
|
-
const systemContexts = this.injector.createSystems(entity);
|
|
369
|
-
for (const context of systemContexts) {
|
|
370
|
-
// TODO: implement synced mode where async onPrepares aren't allowed
|
|
371
|
-
context.system.onPrepare && preparePromises.push(context.system.onPrepare());
|
|
372
|
-
nexSystemContexts.push(context);
|
|
373
|
-
}
|
|
374
|
-
this.entitySystemMap.set(entity, systemContexts);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const startSystems = () => {
|
|
378
|
-
// TODO: check if a "global" method is faster than this inner method
|
|
379
|
-
for (const context of nexSystemContexts) {
|
|
380
|
-
const system = context.system;
|
|
381
|
-
this.mapAnnotatedSignals(system);
|
|
382
|
-
system.onStart && system.onStart();
|
|
383
|
-
system.onPreFixedUpdate && this.onPreFixedUpdateSet.add(system);
|
|
384
|
-
system.onFixedUpdate && this.onFixedUpdateSet.add(system);
|
|
385
|
-
system.onEarlyUpdate && this.onEarlyUpdateSet.add(system);
|
|
386
|
-
system.onUpdate && this.onUpdateSet.add(system);
|
|
387
|
-
system.onLateUpdate && this.onLateUpdateSet.add(system);
|
|
388
|
-
system.onPhysicsUpdate && this.onPhysicsUpdateSet.add(system);
|
|
389
|
-
system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(system);
|
|
390
|
-
system.onLateFixedUpdate && this.onLateFixedUpdateSet.add(system);
|
|
391
|
-
system.onRender && this.onRenderUpdateSet.add(system);
|
|
392
|
-
}
|
|
393
|
-
resolve();
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
// Promise.all doesnt resolve immediately when there are no promises bu
|
|
397
|
-
if (preparePromises.length === 0) {
|
|
398
|
-
startSystems();
|
|
399
|
-
} else {
|
|
400
|
-
Promise.all(preparePromises).then(startSystems);
|
|
401
|
-
}
|
|
466
|
+
const entityWasAdded = () => {
|
|
467
|
+
for (const system of this.onAddEntitySet) {
|
|
468
|
+
system.onAddEntity!(entity);
|
|
402
469
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
470
|
+
resolve();
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// Promise.all doesnt resolve immediately when there are no promises bu
|
|
474
|
+
if (preparePromises.length === 0) {
|
|
475
|
+
this.startSystems(nextSystemContexts, entityWasAdded);
|
|
476
|
+
} else {
|
|
477
|
+
Promise.all(preparePromises).then(() => this.startSystems(nextSystemContexts, entityWasAdded));
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
this.addQueue = [];
|
|
481
|
+
// create promise for next frame
|
|
482
|
+
this.resolveFrame();
|
|
483
|
+
this.framePromise = new Promise<void>(resolve => {
|
|
484
|
+
this.resolveFrame = resolve;
|
|
485
|
+
});
|
|
486
|
+
this.onPrepare.dispatch();
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
private startSystems(contexts: Iterable<SystemContext>, then?: () => void) {
|
|
490
|
+
for (const context of contexts) {
|
|
491
|
+
const system = context.system;
|
|
492
|
+
this.mapAnnotatedSignals(system);
|
|
493
|
+
system.onStart && system.onStart();
|
|
494
|
+
system.onPreFixedUpdate && this.onPreFixedUpdateSet.add(system);
|
|
495
|
+
system.onFixedUpdate && this.onFixedUpdateSet.add(system);
|
|
496
|
+
system.onUpdate && this.onUpdateSet.add(system);
|
|
497
|
+
system.onLateUpdate && this.onLateUpdateSet.add(system);
|
|
498
|
+
system.onPhysicsUpdate && this.onPhysicsUpdateSet.add(system);
|
|
499
|
+
system.onPrePhysicsUpdate && this.onPrePhysicsUpdateSet.add(system);
|
|
500
|
+
system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(system);
|
|
501
|
+
system.onLateFixedUpdate && this.onLateFixedUpdateSet.add(system);
|
|
502
|
+
system.onRender && this.onRenderUpdateSet.add(system);
|
|
503
|
+
system.onAddEntity && this.onAddEntitySet.add(system);
|
|
504
|
+
system.onRemoveEntity && this.onRemoveEntitySet.add(system);
|
|
410
505
|
}
|
|
506
|
+
then?.();
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
getAllEntities(): Entity[] {
|
|
510
|
+
return Array.from(this.entitySystemMap.keys());
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
removeAllEntities() {
|
|
514
|
+
return this.removeAll(this.getAllEntities());
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
private disposeContext(context: SystemContext<System>) {
|
|
518
|
+
const system = context.system;
|
|
519
|
+
|
|
520
|
+
// if onEnd returns a promise, we need to wait for it to finish before we can dispose the system
|
|
521
|
+
const onEndPromise = system.onEnd && system.onEnd();
|
|
522
|
+
if (onEndPromise instanceof Promise) {
|
|
523
|
+
onEndPromise.then(() => {
|
|
524
|
+
context.dispose();
|
|
525
|
+
});
|
|
526
|
+
} else {
|
|
527
|
+
context.dispose();
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
this.unmapAnnotatedSignals(system);
|
|
531
|
+
system.onPreFixedUpdate && this.onPreFixedUpdateSet.delete(system);
|
|
532
|
+
system.onFixedUpdate && this.onFixedUpdateSet.delete(system);
|
|
533
|
+
system.onUpdate && this.onUpdateSet.delete(system);
|
|
534
|
+
system.onLateUpdate && this.onLateUpdateSet.delete(system);
|
|
535
|
+
system.onPhysicsUpdate && this.onPhysicsUpdateSet.delete(system);
|
|
536
|
+
system.onPrePhysicsUpdate && this.onPrePhysicsUpdateSet.delete(system);
|
|
537
|
+
system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.delete(system);
|
|
538
|
+
system.onLateFixedUpdate && this.onLateFixedUpdateSet.delete(system);
|
|
539
|
+
system.onRender && this.onRenderUpdateSet.delete(system);
|
|
540
|
+
}
|
|
411
541
|
}
|
|
412
542
|
//
|
|
413
543
|
// type RunSpread<T> = T extends undefined
|