@woosh/meep-engine 2.60.1 → 2.61.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/build/meep.cjs +20117 -20157
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +20117 -20157
- package/package.json +1 -1
- package/src/core/binary/BitSet.js +1 -1
- package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +30 -182
- package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.spec.js +27 -1
- package/src/core/geom/ConicRay.js +16 -21
- package/src/core/geom/ConicRay.spec.js +24 -0
- package/src/core/geom/packing/miniball/Miniball.js +68 -117
- package/src/core/geom/packing/miniball/Miniball.spec.js +3 -3
- package/src/core/geom/packing/miniball/Subspan.js +47 -34
- package/src/core/geom/packing/miniball/miniball_compute_quality.js +64 -0
- package/src/core/math/bessel_3.js +1 -0
- package/src/core/math/random/randomBytes.js +2 -2
- package/src/core/math/sqr.js +8 -0
- package/src/core/model/node-graph/Connection.js +21 -23
- package/src/core/model/node-graph/DataType.js +16 -17
- package/src/core/model/node-graph/NodeGraph.js +49 -50
- package/src/core/model/node-graph/node/NodeDescription.js +42 -44
- package/src/core/model/node-graph/node/NodeInstance.js +59 -60
- package/src/core/model/node-graph/node/NodeInstancePortReference.js +27 -29
- package/src/core/model/node-graph/node/NodeRegistry.js +16 -18
- package/src/core/model/node-graph/node/Port.js +35 -37
- package/src/core/model/node-graph/node/parameter/NodeParameterDescription.js +27 -13
- package/src/core/path/computePathDirectory.spec.js +8 -0
- package/src/core/process/BaseProcess.d.ts +5 -0
- package/src/core/process/WatchDog.js +76 -75
- package/src/core/process/action/AsynchronousAction.js +24 -22
- package/src/core/process/executor/profile/Profile.js +34 -24
- package/src/core/process/executor/profile/TraceEvent.js +75 -75
- package/src/core/process/worker/OnDemandWorkerManager.js +27 -30
- package/src/core/process/worker/WorkerBuilder.js +149 -149
- package/src/core/process/worker/WorkerProxy.js +25 -21
- package/src/core/process/worker/extractTransferables.js +2 -2
- package/src/engine/Engine.js +58 -53
- package/src/engine/EngineConfiguration.d.ts +4 -4
- package/src/engine/ecs/EntityManager.js +517 -614
- package/src/engine/ecs/System.js +2 -2
- package/src/engine/ecs/transform/Transform.d.ts +7 -5
- package/src/engine/ecs/transform/Transform.js +30 -16
- package/src/engine/ecs/validateSystem.js +89 -0
- package/src/engine/graphics/GraphicsEngine.js +433 -483
- package/src/engine/graphics/camera/testClippingPlaneComputation.js +46 -48
- package/src/engine/graphics/ecs/decal/v2/FPDecalSystem.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +2 -2
- package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +60 -62
- package/src/engine/graphics/ecs/water2/shader/testWaterShader.js +20 -22
- package/src/engine/graphics/particles/particular/engine/ParticularEngine.js +156 -180
- package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +69 -71
- package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +51 -53
- package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +67 -69
- package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +56 -58
- package/src/engine/graphics/shadows/testShadowMapRendering.js +30 -34
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.spec.js +22 -20
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +10 -13
- package/src/engine/graphics/texture/virtual/VirtualTexture.spec.js +1 -1
- package/src/engine/plugin/EnginePluginManager.d.ts +6 -1
- package/src/engine/ecs/components/ClingToHeightMap.js +0 -19
- package/src/engine/ecs/components/SynchronizePosition.js +0 -15
- package/src/engine/ecs/systems/ClingToHeightMapSystem.js +0 -170
- package/src/engine/ecs/systems/SynchronizePositionSystem.js +0 -43
|
@@ -2,22 +2,23 @@
|
|
|
2
2
|
* Created by Alex on 01/04/2014.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {assert} from "../../core/assert.js";
|
|
6
|
+
import {array_copy_unique} from "../../core/collection/array/array_copy_unique.js";
|
|
6
7
|
import Signal from "../../core/events/signal/Signal.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
8
|
+
import {IllegalStateException} from "../../core/fsm/exceptions/IllegalStateException.js";
|
|
9
|
+
import {noop} from "../../core/function/Functions.js";
|
|
10
|
+
import {ResourceAccessKind} from "../../core/model/ResourceAccessKind.js";
|
|
11
|
+
import {EntityObserver} from "./EntityObserver.js";
|
|
12
|
+
import {computeSystemName, System, SystemState} from "./System.js";
|
|
13
|
+
import {computeSystemComponentDependencyGraph} from "./system/computeSystemComponentDependencyGraph.js";
|
|
14
|
+
import {validateSystem} from "./validateSystem.js";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
*
|
|
17
18
|
* @enum {string}
|
|
18
19
|
* @readonly
|
|
19
20
|
*/
|
|
20
|
-
const EventType = {
|
|
21
|
+
export const EventType = {
|
|
21
22
|
EntityRemoved: "entityRemoved",
|
|
22
23
|
ComponentAdded: "componentAdded",
|
|
23
24
|
ComponentRemoved: "componentRemoved"
|
|
@@ -36,33 +37,30 @@ export const EntityManagerState = {
|
|
|
36
37
|
Stopped: 5
|
|
37
38
|
};
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* @constructor
|
|
42
|
-
*/
|
|
43
|
-
function EntityManager() {
|
|
40
|
+
export class EntityManager {
|
|
41
|
+
|
|
44
42
|
/**
|
|
45
43
|
* @readonly
|
|
46
44
|
* @type {System[]}
|
|
47
45
|
*/
|
|
48
|
-
|
|
46
|
+
systems = [];
|
|
49
47
|
|
|
50
48
|
/**
|
|
51
49
|
* @readonly
|
|
52
50
|
* @type {System[]}
|
|
53
51
|
*/
|
|
54
|
-
|
|
52
|
+
systemsExecutionOrder = [];
|
|
55
53
|
|
|
56
54
|
/**
|
|
57
55
|
* @readonly
|
|
58
56
|
* @type {EntityObserver[]}
|
|
59
57
|
*/
|
|
60
|
-
|
|
58
|
+
systemObservers = [];
|
|
61
59
|
|
|
62
60
|
/**
|
|
63
61
|
* @readonly
|
|
64
62
|
*/
|
|
65
|
-
|
|
63
|
+
on = {
|
|
66
64
|
systemStarted: new Signal(),
|
|
67
65
|
systemStopped: new Signal(),
|
|
68
66
|
systemAdded: new Signal(),
|
|
@@ -73,819 +71,724 @@ function EntityManager() {
|
|
|
73
71
|
*
|
|
74
72
|
* @type {EntityManagerState}
|
|
75
73
|
*/
|
|
76
|
-
|
|
74
|
+
state = EntityManagerState.Initial;
|
|
77
75
|
|
|
78
76
|
/**
|
|
79
77
|
* @private
|
|
80
78
|
* @readonly
|
|
81
79
|
* @type {Map<System, number>}
|
|
82
80
|
*/
|
|
83
|
-
|
|
81
|
+
systemAccumulatedFixedStepTime = new Map();
|
|
84
82
|
|
|
85
83
|
/**
|
|
84
|
+
* Value used to execute {@link System#fixedUpdate}
|
|
86
85
|
* In seconds
|
|
87
86
|
* @type {number}
|
|
88
87
|
*/
|
|
89
|
-
|
|
88
|
+
fixedUpdateStepSize = 0.015;
|
|
90
89
|
|
|
91
90
|
/**
|
|
92
91
|
*
|
|
93
92
|
* @type {EntityComponentDataset}
|
|
94
93
|
*/
|
|
95
|
-
|
|
94
|
+
dataset = null;
|
|
96
95
|
|
|
97
96
|
/**
|
|
98
97
|
*
|
|
99
98
|
* @type {boolean}
|
|
100
99
|
* @private
|
|
101
100
|
*/
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Rebuild execution order
|
|
107
|
-
*/
|
|
108
|
-
EntityManager.prototype.updateExecutionOrder = function () {
|
|
109
|
-
// console.time('updateExecutionOrder')
|
|
110
|
-
|
|
111
|
-
const order = this.systemsExecutionOrder;
|
|
112
|
-
|
|
113
|
-
order.splice(0, order.length);
|
|
114
|
-
|
|
115
|
-
const systems = this.systems;
|
|
116
|
-
const system_count = systems.length;
|
|
117
|
-
|
|
118
|
-
let executable_system_count = 0;
|
|
119
|
-
|
|
120
|
-
for (let i = 0; i < system_count; i++) {
|
|
121
|
-
const system = systems[i];
|
|
122
|
-
|
|
123
|
-
if (system.update === noop && system.fixedUpdate === noop) {
|
|
124
|
-
// not a simulation system
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
order[executable_system_count++] = system;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// build dependency graphs amongst components
|
|
132
|
-
const dependency_graph = computeSystemComponentDependencyGraph(executable_system_count, order);
|
|
133
|
-
|
|
101
|
+
__execution_order_needs_update = true;
|
|
134
102
|
|
|
135
103
|
/**
|
|
136
|
-
*
|
|
137
|
-
* @
|
|
138
|
-
* @returns {number} higher values means it should be scheduled before others
|
|
104
|
+
* Rebuild execution order
|
|
105
|
+
* @private
|
|
139
106
|
*/
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const components = system.referenced_components;
|
|
144
|
-
const component_count = components.length;
|
|
107
|
+
updateExecutionOrder() {
|
|
108
|
+
// console.time('updateExecutionOrder')
|
|
145
109
|
|
|
146
|
-
|
|
147
|
-
const component = components[i];
|
|
110
|
+
const order = this.systemsExecutionOrder;
|
|
148
111
|
|
|
149
|
-
|
|
112
|
+
order.splice(0, order.length);
|
|
150
113
|
|
|
114
|
+
const systems = this.systems;
|
|
115
|
+
const system_count = systems.length;
|
|
151
116
|
|
|
152
|
-
|
|
153
|
-
const attached_edge_count = dependency_graph.getNodeContainer(component).getIncomingEdgeCount();
|
|
117
|
+
let executable_system_count = 0;
|
|
154
118
|
|
|
155
|
-
|
|
119
|
+
for (let i = 0; i < system_count; i++) {
|
|
120
|
+
const system = systems[i];
|
|
156
121
|
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
result += attached_edge_count * 2
|
|
161
|
-
} else {
|
|
162
|
-
result += attached_edge_count;
|
|
122
|
+
if (system.update === noop && system.fixedUpdate === noop) {
|
|
123
|
+
// not a simulation system
|
|
124
|
+
continue;
|
|
163
125
|
}
|
|
164
126
|
|
|
127
|
+
order[executable_system_count++] = system;
|
|
165
128
|
}
|
|
166
129
|
|
|
167
|
-
|
|
168
|
-
|
|
130
|
+
// build dependency graphs amongst components
|
|
131
|
+
const dependency_graph = computeSystemComponentDependencyGraph(executable_system_count, order);
|
|
169
132
|
|
|
170
|
-
// pre-score systems for faster sorting
|
|
171
|
-
const scores = new Map();
|
|
172
133
|
|
|
173
|
-
|
|
174
|
-
|
|
134
|
+
/**
|
|
135
|
+
*
|
|
136
|
+
* @param {System} system
|
|
137
|
+
* @returns {number} higher values means it should be scheduled before others
|
|
138
|
+
*/
|
|
139
|
+
function scoreSystem(system) {
|
|
140
|
+
let result = 0;
|
|
175
141
|
|
|
176
|
-
|
|
177
|
-
|
|
142
|
+
const components = system.referenced_components;
|
|
143
|
+
const component_count = components.length;
|
|
178
144
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
});
|
|
145
|
+
for (let i = 0; i < component_count; i++) {
|
|
146
|
+
const component = components[i];
|
|
182
147
|
|
|
183
|
-
|
|
184
|
-
this.__execution_order_needs_update = false;
|
|
185
|
-
// console.timeEnd('updateExecutionOrder')
|
|
186
|
-
};
|
|
148
|
+
result += 0.0001;
|
|
187
149
|
|
|
188
|
-
EntityManager.prototype.detachDataSet = function () {
|
|
189
|
-
const dataset = this.dataset;
|
|
190
150
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
151
|
+
// count number of incoming edges
|
|
152
|
+
const attached_edge_count = dependency_graph.getNodeContainer(component).getIncomingEdgeCount();
|
|
195
153
|
|
|
196
|
-
|
|
197
|
-
this.systemObservers.forEach(function (observer) {
|
|
198
|
-
dataset.removeObserver(observer, true);
|
|
199
|
-
});
|
|
154
|
+
const access = system.getAccessForComponent(component);
|
|
200
155
|
|
|
201
|
-
|
|
202
|
-
|
|
156
|
+
if ((access & ResourceAccessKind.Create) !== 0) {
|
|
157
|
+
result += attached_edge_count * 4
|
|
158
|
+
} else if ((access & ResourceAccessKind.Write) !== 0) {
|
|
159
|
+
result += attached_edge_count * 2
|
|
160
|
+
} else {
|
|
161
|
+
result += attached_edge_count;
|
|
162
|
+
}
|
|
203
163
|
|
|
204
|
-
|
|
205
|
-
* Get list of all components referenced by active systems
|
|
206
|
-
* @returns {Class[]}
|
|
207
|
-
*/
|
|
208
|
-
EntityManager.prototype.getComponentTypeMap = function () {
|
|
209
|
-
const componentTypes = [];
|
|
164
|
+
}
|
|
210
165
|
|
|
211
|
-
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
212
168
|
|
|
213
|
-
|
|
169
|
+
// pre-score systems for faster sorting
|
|
170
|
+
const scores = new Map();
|
|
214
171
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
*
|
|
218
|
-
* @type {System}
|
|
219
|
-
*/
|
|
220
|
-
const system = systems[i];
|
|
172
|
+
for (let i = 0; i < executable_system_count; i++) {
|
|
173
|
+
const system = order[i];
|
|
221
174
|
|
|
175
|
+
scores.set(system, scoreSystem(system));
|
|
176
|
+
}
|
|
222
177
|
|
|
223
|
-
|
|
178
|
+
order.sort((a, b) => {
|
|
179
|
+
return scores.get(b) - scores.get(a);
|
|
180
|
+
});
|
|
224
181
|
|
|
225
|
-
|
|
182
|
+
// clear update flag
|
|
183
|
+
this.__execution_order_needs_update = false;
|
|
184
|
+
// console.timeEnd('updateExecutionOrder')
|
|
226
185
|
}
|
|
227
186
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
*
|
|
233
|
-
* @param {EntityComponentDataset} dataset
|
|
234
|
-
* @throws {Error} if another dataset is attached
|
|
235
|
-
* @throws {Error} if dataset is incompatible with current system set
|
|
236
|
-
*/
|
|
237
|
-
EntityManager.prototype.attachDataSet = function (dataset) {
|
|
238
|
-
//check if another dataset is attached
|
|
239
|
-
if (this.dataset !== null) {
|
|
187
|
+
detachDataSet() {
|
|
188
|
+
const dataset = this.dataset;
|
|
240
189
|
|
|
241
|
-
if (
|
|
242
|
-
//
|
|
190
|
+
if (dataset === null) {
|
|
191
|
+
//no dataset attached
|
|
243
192
|
return;
|
|
244
193
|
}
|
|
245
194
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
//ensure compatibility with system-used component map
|
|
252
|
-
dataset.registerManyComponentTypes(localComponentTypeMap);
|
|
253
|
-
|
|
254
|
-
this.dataset = dataset;
|
|
255
|
-
|
|
256
|
-
this.systemObservers.forEach(function (observer) {
|
|
257
|
-
dataset.addObserver(observer, true);
|
|
258
|
-
});
|
|
259
|
-
};
|
|
260
|
-
|
|
195
|
+
//remove system observers
|
|
196
|
+
this.systemObservers.forEach(function (observer) {
|
|
197
|
+
dataset.removeObserver(observer, true);
|
|
198
|
+
});
|
|
261
199
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
* @param {Class<T>} systemClass
|
|
265
|
-
* @returns {boolean}
|
|
266
|
-
*/
|
|
267
|
-
EntityManager.prototype.hasSystem = function (systemClass) {
|
|
268
|
-
return this.getSystem(systemClass) !== null;
|
|
269
|
-
};
|
|
200
|
+
this.dataset = null;
|
|
201
|
+
}
|
|
270
202
|
|
|
271
|
-
/**
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const systems = this.systems;
|
|
278
|
-
const numSystems = systems.length;
|
|
203
|
+
/**
|
|
204
|
+
* Get list of all components referenced by active systems
|
|
205
|
+
* @returns {Class[]}
|
|
206
|
+
*/
|
|
207
|
+
getComponentTypeMap() {
|
|
208
|
+
const componentTypes = [];
|
|
279
209
|
|
|
280
|
-
|
|
281
|
-
const system = systems[i];
|
|
210
|
+
const systems = this.systems;
|
|
282
211
|
|
|
283
|
-
|
|
284
|
-
return system;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
212
|
+
const systemCount = systems.length;
|
|
287
213
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
214
|
+
for (let i = 0; i < systemCount; i++) {
|
|
215
|
+
/**
|
|
216
|
+
*
|
|
217
|
+
* @type {System}
|
|
218
|
+
*/
|
|
219
|
+
const system = systems[i];
|
|
291
220
|
|
|
292
221
|
|
|
293
|
-
|
|
294
|
-
* @deprecated use {@link EntityComponentDataset.getComponentClassByName} instead
|
|
295
|
-
* @template T
|
|
296
|
-
* @param {string} className
|
|
297
|
-
* @returns {null|Class<T>}
|
|
298
|
-
*/
|
|
299
|
-
EntityManager.prototype.getComponentClassByName = function (className) {
|
|
300
|
-
const componentTypes = this.getComponentTypeMap();
|
|
222
|
+
const referencedComponents = system.referenced_components;
|
|
301
223
|
|
|
302
|
-
|
|
303
|
-
const l = componentTypes.length;
|
|
304
|
-
for (; i < l; i++) {
|
|
305
|
-
const componentClass = componentTypes[i];
|
|
306
|
-
const name = componentClass.typeName;
|
|
307
|
-
if (name === className) {
|
|
308
|
-
return componentClass;
|
|
224
|
+
array_copy_unique(referencedComponents, 0, componentTypes, componentTypes.length, referencedComponents.length);
|
|
309
225
|
}
|
|
310
|
-
}
|
|
311
|
-
return null;
|
|
312
|
-
};
|
|
313
226
|
|
|
314
|
-
|
|
315
|
-
* Advance simulation forward by a specified amount of time
|
|
316
|
-
* @param {number} timeDelta in seconds, real number
|
|
317
|
-
*/
|
|
318
|
-
EntityManager.prototype.simulate = function (timeDelta) {
|
|
319
|
-
assert.isNumber(timeDelta, 'timeDelta');
|
|
320
|
-
assert.notNaN(timeDelta, 'timeDelta');
|
|
321
|
-
assert.greaterThanOrEqual(timeDelta, 0, 'timeDelta must be >= 0');
|
|
322
|
-
|
|
323
|
-
if (this.__execution_order_needs_update) {
|
|
324
|
-
this.updateExecutionOrder();
|
|
227
|
+
return componentTypes;
|
|
325
228
|
}
|
|
326
229
|
|
|
327
|
-
|
|
328
230
|
/**
|
|
329
231
|
*
|
|
330
|
-
* @
|
|
232
|
+
* @param {EntityComponentDataset} dataset
|
|
233
|
+
* @throws {Error} if another dataset is attached
|
|
234
|
+
* @throws {Error} if dataset is incompatible with current system set
|
|
331
235
|
*/
|
|
332
|
-
|
|
236
|
+
attachDataSet(dataset) {
|
|
237
|
+
//check if another dataset is attached
|
|
238
|
+
if (this.dataset !== null) {
|
|
333
239
|
|
|
334
|
-
|
|
240
|
+
if (this.dataset === dataset) {
|
|
241
|
+
// special case, we already have this dataset attached. Nothing to more to do
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
335
244
|
|
|
336
|
-
|
|
337
|
-
|
|
245
|
+
throw new Error("Illegal status, another dataset is currently attached");
|
|
246
|
+
}
|
|
338
247
|
|
|
339
|
-
|
|
340
|
-
assert.greaterThan(fixed_step, 0, 'fixed_step must be greater than 0');
|
|
248
|
+
const localComponentTypeMap = this.getComponentTypeMap();
|
|
341
249
|
|
|
342
|
-
|
|
250
|
+
//ensure compatibility with system-used component map
|
|
251
|
+
dataset.registerManyComponentTypes(localComponentTypeMap);
|
|
343
252
|
|
|
344
|
-
|
|
253
|
+
this.dataset = dataset;
|
|
345
254
|
|
|
346
|
-
|
|
347
|
-
|
|
255
|
+
this.systemObservers.forEach(function (observer) {
|
|
256
|
+
dataset.addObserver(observer, true);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
348
259
|
|
|
260
|
+
/**
|
|
261
|
+
* @template T
|
|
262
|
+
* @param {Class<T>} systemClass
|
|
263
|
+
* @returns {boolean}
|
|
264
|
+
*/
|
|
265
|
+
hasSystem(systemClass) {
|
|
266
|
+
return this.getSystem(systemClass) !== null;
|
|
267
|
+
}
|
|
349
268
|
|
|
350
|
-
|
|
269
|
+
/**
|
|
270
|
+
* @template T
|
|
271
|
+
* @param {Class<T>} systemClass
|
|
272
|
+
* @returns {T|null}
|
|
273
|
+
*/
|
|
274
|
+
getSystem(systemClass) {
|
|
275
|
+
const systems = this.systems;
|
|
276
|
+
const numSystems = systems.length;
|
|
351
277
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
} catch (e) {
|
|
355
|
-
console.error(`Failed during fixedUpdate of system '${computeSystemName(system)}': `, e);
|
|
356
|
-
}
|
|
278
|
+
for (let i = 0; i < numSystems; i++) {
|
|
279
|
+
const system = systems[i];
|
|
357
280
|
|
|
358
|
-
|
|
281
|
+
if (system instanceof systemClass) {
|
|
282
|
+
return system;
|
|
359
283
|
}
|
|
360
|
-
|
|
361
|
-
// record whatever remains
|
|
362
|
-
accumulatedTime.set(system, accumulated_time);
|
|
363
|
-
|
|
364
284
|
}
|
|
365
285
|
|
|
366
|
-
|
|
286
|
+
//not found
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
367
289
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
290
|
+
/**
|
|
291
|
+
* @deprecated use {@link EntityComponentDataset.getComponentClassByName} instead
|
|
292
|
+
* @template T
|
|
293
|
+
* @param {string} className
|
|
294
|
+
* @returns {null|Class<T>}
|
|
295
|
+
*/
|
|
296
|
+
getComponentClassByName(className) {
|
|
297
|
+
const componentTypes = this.getComponentTypeMap();
|
|
298
|
+
|
|
299
|
+
let i = 0;
|
|
300
|
+
const l = componentTypes.length;
|
|
301
|
+
for (; i < l; i++) {
|
|
302
|
+
const componentClass = componentTypes[i];
|
|
303
|
+
const name = componentClass.typeName;
|
|
304
|
+
if (name === className) {
|
|
305
|
+
return componentClass;
|
|
372
306
|
}
|
|
373
|
-
|
|
374
307
|
}
|
|
375
|
-
|
|
308
|
+
return null;
|
|
376
309
|
}
|
|
377
|
-
};
|
|
378
310
|
|
|
379
|
-
/**
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
}
|
|
311
|
+
/**
|
|
312
|
+
* Advance simulation forward by a specified amount of time
|
|
313
|
+
* @param {number} timeDelta in seconds
|
|
314
|
+
*/
|
|
315
|
+
simulate(timeDelta) {
|
|
316
|
+
assert.isNumber(timeDelta, 'timeDelta');
|
|
317
|
+
assert.notNaN(timeDelta, 'timeDelta');
|
|
318
|
+
assert.greaterThanOrEqual(timeDelta, 0, 'timeDelta must be >= 0');
|
|
388
319
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
320
|
+
if (this.__execution_order_needs_update) {
|
|
321
|
+
this.updateExecutionOrder();
|
|
322
|
+
}
|
|
392
323
|
|
|
393
|
-
if (!(system instanceof System)) {
|
|
394
|
-
throw new TypeError("System does not inherit from \"System\" class");
|
|
395
|
-
}
|
|
396
324
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
325
|
+
/**
|
|
326
|
+
*
|
|
327
|
+
* @type {System[]}
|
|
328
|
+
*/
|
|
329
|
+
const systems = this.systems;
|
|
400
330
|
|
|
401
|
-
|
|
402
|
-
throw new Error(`uses deprecated 'remove' method, should use 'unlink' instead`);
|
|
403
|
-
}
|
|
331
|
+
const system_count = systems.length;
|
|
404
332
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const components_used_count = components_used.length;
|
|
333
|
+
const fixed_step = this.fixedUpdateStepSize;
|
|
334
|
+
const accumulatedTime = this.systemAccumulatedFixedStepTime;
|
|
408
335
|
|
|
409
|
-
|
|
410
|
-
|
|
336
|
+
assert.notNaN(fixed_step, 'fixed_step');
|
|
337
|
+
assert.greaterThan(fixed_step, 0, 'fixed_step must be greater than 0');
|
|
411
338
|
|
|
412
|
-
|
|
413
|
-
throw new Error(`Invalid access specification[${i}], expected an instance of ResourceAccessSpecification, but got something else`);
|
|
414
|
-
}
|
|
339
|
+
for (let i = 0; i < system_count; i++) {
|
|
415
340
|
|
|
416
|
-
|
|
417
|
-
throw new Error(`No component specified for element [${i}]`);
|
|
418
|
-
}
|
|
341
|
+
const system = systems[i];
|
|
419
342
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
343
|
+
if (system.fixedUpdate !== noop) {
|
|
344
|
+
let accumulated_time = accumulatedTime.get(system) + timeDelta;
|
|
423
345
|
|
|
424
|
-
// backtrace to make sure there are no duplicates
|
|
425
|
-
for (let j = 0; j < i - 1; j++) {
|
|
426
|
-
const spec_other = components_used[j];
|
|
427
346
|
|
|
428
|
-
|
|
429
|
-
throw new Error(`Duplicate specification of component [${j}] and [${i}]`);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
347
|
+
while (accumulated_time >= fixed_step) {
|
|
433
348
|
|
|
434
|
-
|
|
435
|
-
|
|
349
|
+
try {
|
|
350
|
+
system.fixedUpdate(fixed_step)
|
|
351
|
+
} catch (e) {
|
|
352
|
+
console.error(`Failed during fixedUpdate of system '${computeSystemName(system)}': `, e);
|
|
353
|
+
}
|
|
436
354
|
|
|
437
|
-
|
|
355
|
+
accumulated_time -= fixed_step;
|
|
356
|
+
}
|
|
438
357
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
358
|
+
// record whatever remains
|
|
359
|
+
accumulatedTime.set(system, accumulated_time);
|
|
442
360
|
|
|
443
|
-
if (numDependencies > 1) {
|
|
444
|
-
//check for duplicates
|
|
445
|
-
for (let i = 0; i < numDependencies; i++) {
|
|
446
|
-
const dependencyA = dependencies[i];
|
|
447
|
-
for (let j = i + 1; j < numDependencies; j++) {
|
|
448
|
-
if (dependencyA === dependencies[j]) {
|
|
449
|
-
throw new Error(`Detected duplicate dependency: ${dependencyA.constructor.typeName}`);
|
|
450
|
-
}
|
|
451
361
|
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
362
|
|
|
363
|
+
if (system.update !== noop) {
|
|
455
364
|
|
|
456
|
-
|
|
365
|
+
try {
|
|
366
|
+
system.update(timeDelta);
|
|
367
|
+
} catch (e) {
|
|
368
|
+
console.error(`Failed during update of system '${computeSystemName(system)}': `, e);
|
|
369
|
+
}
|
|
457
370
|
|
|
458
|
-
|
|
459
|
-
throw new Error(`'link' method declares ${system.link.length} instead of expected ${linkArgumentCount} based on it's ${numDependencies} dependencies`);
|
|
460
|
-
}
|
|
371
|
+
}
|
|
461
372
|
|
|
462
|
-
|
|
463
|
-
throw new Error(`'unlink' method declares ${system.unlink.length} instead of expected ${linkArgumentCount} based on it's ${numDependencies} dependencies`);
|
|
373
|
+
}
|
|
464
374
|
}
|
|
465
|
-
}
|
|
466
375
|
|
|
376
|
+
/**
|
|
377
|
+
* If the {@link EntityManager} is already started, the system will be started automatically before being added
|
|
378
|
+
* @param {System} system
|
|
379
|
+
* @returns {Promise}
|
|
380
|
+
* @throws {IllegalStateException}
|
|
381
|
+
*/
|
|
382
|
+
addSystem(system) {
|
|
383
|
+
assert.defined(system, "system");
|
|
384
|
+
assert.isInstanceOf(system, System, 'system', 'System');
|
|
467
385
|
|
|
468
|
-
|
|
469
|
-
* If the {@link EntityManager} is already started, the system will be started automatically before being added
|
|
470
|
-
* @param {System} system
|
|
471
|
-
* @returns {Promise}
|
|
472
|
-
* @throws {IllegalStateException}
|
|
473
|
-
*/
|
|
474
|
-
EntityManager.prototype.addSystem = function (system) {
|
|
475
|
-
assert.defined(system, "system");
|
|
476
|
-
assert.isInstanceOf(system, System, 'system', 'System');
|
|
477
|
-
|
|
478
|
-
const existing = this.getSystem(Object.getPrototypeOf(system).constructor);
|
|
386
|
+
const existing = this.getSystem(Object.getPrototypeOf(system).constructor);
|
|
479
387
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
388
|
+
if (existing !== null) {
|
|
389
|
+
if (existing === system) {
|
|
390
|
+
//system already added, do nothing
|
|
391
|
+
return Promise.resolve();
|
|
392
|
+
} else {
|
|
393
|
+
throw new IllegalStateException(`Another instance of system '${computeSystemName(system)}' is already registered`);
|
|
394
|
+
}
|
|
486
395
|
}
|
|
487
|
-
}
|
|
488
396
|
|
|
489
397
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
398
|
+
try {
|
|
399
|
+
validateSystem(system);
|
|
400
|
+
} catch (e) {
|
|
401
|
+
console.error(`System validation failed '${computeSystemName(system)}' : `, e, system);
|
|
402
|
+
}
|
|
495
403
|
|
|
496
|
-
|
|
497
|
-
|
|
404
|
+
//check system state
|
|
405
|
+
const systemState = system.state.getValue();
|
|
498
406
|
|
|
499
|
-
|
|
407
|
+
const legalStates = [SystemState.INITIAL, SystemState.STOPPED];
|
|
500
408
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
409
|
+
if (legalStates.indexOf(systemState) === -1) {
|
|
410
|
+
//illegal state
|
|
411
|
+
throw new IllegalStateException(`System must be in one of these states: [${legalStates.join(",")}], instead was ${systemState}`);
|
|
412
|
+
}
|
|
505
413
|
|
|
506
|
-
|
|
507
|
-
|
|
414
|
+
const systems = this.systems;
|
|
415
|
+
const systemIndex = systems.length;
|
|
508
416
|
|
|
509
|
-
|
|
417
|
+
systems[systemIndex] = system;
|
|
510
418
|
|
|
511
|
-
|
|
512
|
-
|
|
419
|
+
// request exec order update
|
|
420
|
+
this.__execution_order_needs_update = true;
|
|
513
421
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
422
|
+
//build observer
|
|
423
|
+
const linkObserver = new EntityObserver(system.dependencies, system.link, system.unlink, system);
|
|
424
|
+
this.systemObservers[systemIndex] = linkObserver;
|
|
517
425
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
426
|
+
let startup_promise;
|
|
427
|
+
if (this.state === EntityManagerState.Running) {
|
|
428
|
+
//initialize the system
|
|
429
|
+
startup_promise = new Promise((resolve, reject) => {
|
|
430
|
+
this.startSystem(system, resolve, reject);
|
|
431
|
+
});
|
|
432
|
+
} else {
|
|
433
|
+
startup_promise = Promise.resolve();
|
|
434
|
+
}
|
|
527
435
|
|
|
528
|
-
|
|
436
|
+
if (this.dataset !== null) {
|
|
529
437
|
|
|
530
|
-
|
|
531
|
-
|
|
438
|
+
// link dependency components
|
|
439
|
+
this.dataset.registerManyComponentTypes(system.referenced_components);
|
|
532
440
|
|
|
533
|
-
|
|
534
|
-
|
|
441
|
+
this.dataset.addObserver(linkObserver);
|
|
442
|
+
}
|
|
535
443
|
|
|
536
|
-
|
|
444
|
+
this.systemAccumulatedFixedStepTime.set(system, 0);
|
|
537
445
|
|
|
538
|
-
|
|
446
|
+
this.on.systemAdded.send1(system);
|
|
539
447
|
|
|
540
|
-
|
|
541
|
-
}
|
|
448
|
+
return startup_promise;
|
|
449
|
+
}
|
|
542
450
|
|
|
543
|
-
/**
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
451
|
+
/**
|
|
452
|
+
*
|
|
453
|
+
* @param {System} system
|
|
454
|
+
* @returns {Promise<boolean>}
|
|
455
|
+
*/
|
|
456
|
+
async removeSystem(system) {
|
|
457
|
+
assert.defined(system, "system");
|
|
458
|
+
assert.isInstanceOf(system, System, 'system', 'System');
|
|
551
459
|
|
|
552
460
|
|
|
553
|
-
|
|
461
|
+
const systemIndex = this.systems.indexOf(system);
|
|
554
462
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
463
|
+
if (systemIndex === -1) {
|
|
464
|
+
//system not found
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
559
467
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
468
|
+
//unlink system observer
|
|
469
|
+
const systemObserver = this.systemObservers[systemIndex];
|
|
470
|
+
this.systemObservers.splice(systemIndex, 1);
|
|
563
471
|
|
|
564
|
-
|
|
472
|
+
assert.notEqual(systemObserver, undefined, "System observer is undefined, it was possibly removed illegally or was not created");
|
|
565
473
|
|
|
566
474
|
|
|
567
|
-
|
|
568
|
-
|
|
475
|
+
//shutdown system
|
|
476
|
+
this.systems.splice(systemIndex, 1);
|
|
569
477
|
|
|
570
|
-
|
|
571
|
-
|
|
478
|
+
// request exec order update
|
|
479
|
+
this.__execution_order_needs_update = true;
|
|
572
480
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
481
|
+
if (this.dataset !== null) {
|
|
482
|
+
this.dataset.removeObserver(systemObserver);
|
|
483
|
+
}
|
|
576
484
|
|
|
577
|
-
|
|
578
|
-
|
|
485
|
+
await new Promise((resolve, reject) => {
|
|
486
|
+
this.stopSystem(system, resolve, (reason) => {
|
|
579
487
|
|
|
580
|
-
|
|
488
|
+
reject(`system ${computeSystemName(system)} shutdown failed: ${reason}`);
|
|
489
|
+
});
|
|
581
490
|
});
|
|
582
|
-
});
|
|
583
491
|
|
|
584
|
-
|
|
492
|
+
this.systemAccumulatedFixedStepTime.delete(system);
|
|
585
493
|
|
|
586
|
-
|
|
494
|
+
this.on.systemRemoved.send1(system);
|
|
587
495
|
|
|
588
|
-
|
|
589
|
-
}
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
590
498
|
|
|
499
|
+
/**
|
|
500
|
+
* @private
|
|
501
|
+
* @param {System} system
|
|
502
|
+
* @param {function(system: System)} successCallback
|
|
503
|
+
* @param {function(reason:*)} errorCallback
|
|
504
|
+
*/
|
|
505
|
+
stopSystem(system, successCallback, errorCallback) {
|
|
506
|
+
const self = this;
|
|
591
507
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
const self = this;
|
|
600
|
-
|
|
601
|
-
try {
|
|
602
|
-
system.state.set(System.State.STOPPING);
|
|
603
|
-
} catch (e) {
|
|
604
|
-
console.error(`Failed to set system state to STOPPING`, e);
|
|
605
|
-
errorCallback(e);
|
|
606
|
-
return;
|
|
607
|
-
}
|
|
508
|
+
try {
|
|
509
|
+
system.state.set(SystemState.STOPPING);
|
|
510
|
+
} catch (e) {
|
|
511
|
+
console.error(`Failed to set system state to STOPPING`, e);
|
|
512
|
+
errorCallback(e);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
608
515
|
|
|
609
|
-
|
|
610
|
-
|
|
516
|
+
function systemReady() {
|
|
517
|
+
system.state.set(SystemState.STOPPED);
|
|
611
518
|
|
|
612
|
-
|
|
519
|
+
self.on.systemStopped.send1(system);
|
|
613
520
|
|
|
614
|
-
|
|
615
|
-
|
|
521
|
+
successCallback(system);
|
|
522
|
+
}
|
|
616
523
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
524
|
+
function systemFailed(reason) {
|
|
525
|
+
errorCallback(reason);
|
|
526
|
+
}
|
|
620
527
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
528
|
+
try {
|
|
529
|
+
system.shutdown(self, systemReady, systemFailed);
|
|
530
|
+
} catch (e) {
|
|
531
|
+
console.error(`Failed to execute system shutdown`, e);
|
|
532
|
+
errorCallback(e);
|
|
533
|
+
}
|
|
626
534
|
}
|
|
627
|
-
};
|
|
628
535
|
|
|
629
|
-
/**
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
536
|
+
/**
|
|
537
|
+
* @private
|
|
538
|
+
* @param {System} system
|
|
539
|
+
* @param {function(system: System)} successCallback
|
|
540
|
+
* @param {function(reason:*)} errorCallback
|
|
541
|
+
*/
|
|
542
|
+
startSystem(system, successCallback, errorCallback) {
|
|
543
|
+
assert.defined(system, "system");
|
|
544
|
+
assert.isFunction(successCallback, "successCallback");
|
|
545
|
+
assert.isFunction(errorCallback, "errorCallback");
|
|
546
|
+
|
|
547
|
+
if (system.state.getValue() === SystemState.RUNNING) {
|
|
548
|
+
//system is already running
|
|
549
|
+
console.warn(`System '${computeSystemName(system)}' is already running, nothing to do`);
|
|
550
|
+
successCallback(system);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
646
553
|
|
|
647
|
-
|
|
554
|
+
const self = this;
|
|
648
555
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
556
|
+
try {
|
|
557
|
+
system.state.set(SystemState.STARTING);
|
|
558
|
+
} catch (e) {
|
|
559
|
+
console.error(`Failed to set system state to STARTING`, e);
|
|
560
|
+
errorCallback(e);
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
656
563
|
|
|
657
|
-
|
|
658
|
-
|
|
564
|
+
function systemReady() {
|
|
565
|
+
system.state.set(SystemState.RUNNING);
|
|
659
566
|
|
|
660
|
-
|
|
567
|
+
self.on.systemStarted.dispatch(system);
|
|
661
568
|
|
|
662
|
-
|
|
663
|
-
|
|
569
|
+
successCallback(system);
|
|
570
|
+
}
|
|
664
571
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
572
|
+
function systemFailed(reason) {
|
|
573
|
+
errorCallback(reason);
|
|
574
|
+
}
|
|
668
575
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
576
|
+
try {
|
|
577
|
+
system.startup(self, systemReady, systemFailed);
|
|
578
|
+
} catch (e) {
|
|
579
|
+
console.error(`Failed to execute system startup`, e);
|
|
580
|
+
systemFailed(e);
|
|
581
|
+
}
|
|
674
582
|
}
|
|
675
|
-
};
|
|
676
583
|
|
|
677
|
-
/**
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
584
|
+
/**
|
|
585
|
+
*
|
|
586
|
+
* @param {function} readyCallback executed once entity manager successfully completes startup
|
|
587
|
+
* @param {function} errorCallback executed if entity manager encounters an error during startup
|
|
588
|
+
*/
|
|
589
|
+
startup(readyCallback, errorCallback) {
|
|
590
|
+
if (this.state === EntityManagerState.Starting) {
|
|
591
|
+
throw new IllegalStateException(`System is currently in starting state`);
|
|
592
|
+
}
|
|
686
593
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
594
|
+
if (this.state === EntityManagerState.Running) {
|
|
595
|
+
// already running, do nothing
|
|
596
|
+
readyCallback();
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
692
599
|
|
|
693
|
-
|
|
694
|
-
|
|
600
|
+
assert.isFunction(readyCallback, 'readyCallback');
|
|
601
|
+
assert.isFunction(errorCallback, 'errorCallback');
|
|
695
602
|
|
|
696
|
-
|
|
603
|
+
this.state = EntityManagerState.Starting;
|
|
697
604
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
605
|
+
const self = this;
|
|
606
|
+
const systems = this.systems;
|
|
607
|
+
let readyCount = 0;
|
|
608
|
+
const expectedReadyCount = systems.length;
|
|
702
609
|
|
|
703
|
-
|
|
610
|
+
console.log(`EntityManager startup initialized, starting ${expectedReadyCount} systems.`);
|
|
704
611
|
|
|
705
|
-
|
|
706
|
-
|
|
612
|
+
function finalizeStartup() {
|
|
613
|
+
self.state = EntityManagerState.Running;
|
|
707
614
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
615
|
+
console.log(`EntityManager startup finished, all systems started`);
|
|
616
|
+
try {
|
|
617
|
+
readyCallback();
|
|
618
|
+
} catch (e) {
|
|
619
|
+
console.error("All systems were started OK, but readyCallback failed.", e);
|
|
620
|
+
}
|
|
713
621
|
}
|
|
714
|
-
}
|
|
715
622
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
623
|
+
function systemReady() {
|
|
624
|
+
//startup all systems
|
|
625
|
+
readyCount++;
|
|
719
626
|
|
|
720
|
-
|
|
721
|
-
|
|
627
|
+
if (readyCount === expectedReadyCount) {
|
|
628
|
+
finalizeStartup();
|
|
629
|
+
}
|
|
722
630
|
}
|
|
723
|
-
}
|
|
724
631
|
|
|
725
|
-
|
|
632
|
+
let firstFailure = true;
|
|
726
633
|
|
|
727
|
-
|
|
728
|
-
|
|
634
|
+
function systemError(system, error) {
|
|
635
|
+
console.error("Failed to start system", system, 'Error:', error);
|
|
729
636
|
|
|
730
|
-
|
|
731
|
-
|
|
637
|
+
if (firstFailure) {
|
|
638
|
+
firstFailure = false;
|
|
732
639
|
|
|
733
|
-
|
|
640
|
+
self.state = EntityManagerState.Failed;
|
|
734
641
|
|
|
735
|
-
|
|
642
|
+
errorCallback(error);
|
|
643
|
+
}
|
|
736
644
|
}
|
|
737
|
-
}
|
|
738
645
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
646
|
+
if (expectedReadyCount === 0) {
|
|
647
|
+
//no systems registered, we're done
|
|
648
|
+
finalizeStartup();
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
744
651
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
652
|
+
systems.forEach(function (system) {
|
|
653
|
+
//ensure eventManager are there
|
|
654
|
+
//start the system
|
|
655
|
+
const cbOK = systemReady.bind(null, system);
|
|
656
|
+
const cbError = systemError.bind(null, system);
|
|
750
657
|
|
|
751
|
-
|
|
658
|
+
self.startSystem(system, cbOK, cbError);
|
|
752
659
|
|
|
753
|
-
|
|
754
|
-
}
|
|
660
|
+
});
|
|
661
|
+
}
|
|
755
662
|
|
|
756
|
-
/**
|
|
757
|
-
*
|
|
758
|
-
* @param {Class} systemClass
|
|
759
|
-
* @returns {Promise.<System>}
|
|
760
|
-
*/
|
|
761
|
-
EntityManager.prototype.promiseSystem = function (systemClass) {
|
|
762
663
|
/**
|
|
763
664
|
*
|
|
764
|
-
* @
|
|
665
|
+
* @param {Class} systemClass
|
|
666
|
+
* @returns {Promise.<System>}
|
|
765
667
|
*/
|
|
766
|
-
|
|
668
|
+
promiseSystem(systemClass) {
|
|
669
|
+
/**
|
|
670
|
+
*
|
|
671
|
+
* @type {EntityManager}
|
|
672
|
+
*/
|
|
673
|
+
const em = this;
|
|
767
674
|
|
|
768
|
-
|
|
675
|
+
return new Promise(function (resolve, reject) {
|
|
769
676
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
677
|
+
function systemAdded(s) {
|
|
678
|
+
if (s instanceof systemClass) {
|
|
679
|
+
//unregister listener
|
|
680
|
+
em.on.systemAdded.remove(systemAdded);
|
|
681
|
+
resolve(s);
|
|
682
|
+
}
|
|
775
683
|
}
|
|
776
|
-
}
|
|
777
684
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
}
|
|
685
|
+
const system = em.getSystem(systemClass);
|
|
686
|
+
if (system !== null) {
|
|
687
|
+
resolve(system);
|
|
688
|
+
} else {
|
|
689
|
+
em.on.systemAdded.add(systemAdded);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
786
693
|
|
|
787
|
-
/**
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
694
|
+
/**
|
|
695
|
+
*
|
|
696
|
+
* @param {Class} systemClass
|
|
697
|
+
* @param {SystemState} state
|
|
698
|
+
* @returns {Promise.<System>}
|
|
699
|
+
*/
|
|
700
|
+
promiseSystemInState(systemClass, state) {
|
|
701
|
+
const em = this;
|
|
795
702
|
|
|
796
|
-
|
|
703
|
+
return new Promise(function (resolve, reject) {
|
|
797
704
|
|
|
798
|
-
|
|
705
|
+
const pSystem = em.promiseSystem(systemClass);
|
|
799
706
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
707
|
+
pSystem.then(function (system) {
|
|
708
|
+
function tryProcessSystem() {
|
|
709
|
+
if (system.state.get() !== state) {
|
|
710
|
+
system.state.onChanged.addOne(tryProcessSystem);
|
|
711
|
+
} else {
|
|
712
|
+
resolve(system);
|
|
713
|
+
}
|
|
806
714
|
}
|
|
807
|
-
}
|
|
808
715
|
|
|
809
|
-
|
|
810
|
-
|
|
716
|
+
tryProcessSystem();
|
|
717
|
+
}, reject);
|
|
811
718
|
|
|
812
|
-
|
|
813
|
-
}
|
|
719
|
+
});
|
|
720
|
+
}
|
|
814
721
|
|
|
815
|
-
/**
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
722
|
+
/**
|
|
723
|
+
*
|
|
724
|
+
* @param {function} readyCallback
|
|
725
|
+
* @param {function} errorCallback
|
|
726
|
+
*/
|
|
727
|
+
shutdown(readyCallback, errorCallback) {
|
|
728
|
+
this.state = EntityManagerState.Stopping;
|
|
822
729
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
730
|
+
if (this.dataset !== null) {
|
|
731
|
+
// a dataset is still attached, to properly dispose of all the component-bound resources, we first detach the dataset
|
|
732
|
+
this.detachDataSet();
|
|
733
|
+
}
|
|
827
734
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
735
|
+
const self = this;
|
|
736
|
+
const systems = this.systems;
|
|
737
|
+
let readyCount = 0;
|
|
738
|
+
const expectedReadyCount = systems.length;
|
|
832
739
|
|
|
833
|
-
|
|
834
|
-
|
|
740
|
+
function finalizeShutdown() {
|
|
741
|
+
self.state = EntityManagerState.Stopped;
|
|
835
742
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
743
|
+
try {
|
|
744
|
+
readyCallback();
|
|
745
|
+
} catch (e) {
|
|
746
|
+
console.error("All systems were shutdown OK, but readyCallback failed.", e);
|
|
747
|
+
}
|
|
840
748
|
}
|
|
841
|
-
}
|
|
842
749
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
750
|
+
function systemReady(system) {
|
|
751
|
+
//startup all systems
|
|
752
|
+
readyCount++;
|
|
846
753
|
|
|
847
|
-
|
|
754
|
+
system.state.set(SystemState.STOPPED);
|
|
848
755
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
756
|
+
self.on.systemStopped.send1(system);
|
|
757
|
+
if (readyCount === expectedReadyCount) {
|
|
758
|
+
finalizeShutdown();
|
|
759
|
+
}
|
|
852
760
|
}
|
|
853
|
-
}
|
|
854
761
|
|
|
855
|
-
|
|
762
|
+
let firstFailure = true;
|
|
856
763
|
|
|
857
|
-
|
|
858
|
-
|
|
764
|
+
function systemError(system) {
|
|
765
|
+
console.error("Failed to shutdown system", system);
|
|
859
766
|
|
|
860
|
-
|
|
861
|
-
|
|
767
|
+
if (firstFailure) {
|
|
768
|
+
firstFailure = false;
|
|
862
769
|
|
|
863
|
-
|
|
770
|
+
self.state = EntityManagerState.Failed;
|
|
864
771
|
|
|
865
|
-
|
|
772
|
+
errorCallback();
|
|
773
|
+
}
|
|
866
774
|
}
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
if (expectedReadyCount === 0) {
|
|
870
|
-
//no systems registered, we're done
|
|
871
|
-
finalizeShutdown();
|
|
872
|
-
}
|
|
873
775
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const cbOK = systemReady.bind(null, system);
|
|
878
|
-
const cbError = systemError.bind(null, system);
|
|
879
|
-
try {
|
|
880
|
-
system.shutdown(self, cbOK, cbError);
|
|
881
|
-
} catch (e) {
|
|
882
|
-
//failure in shutdown function
|
|
883
|
-
cbError(e);
|
|
776
|
+
if (expectedReadyCount === 0) {
|
|
777
|
+
//no systems registered, we're done
|
|
778
|
+
finalizeShutdown();
|
|
884
779
|
}
|
|
885
|
-
});
|
|
886
|
-
};
|
|
887
780
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
781
|
+
systems.forEach(function (system) {
|
|
782
|
+
system.state.set(SystemState.STOPPING);
|
|
783
|
+
//start the system
|
|
784
|
+
const cbOK = systemReady.bind(null, system);
|
|
785
|
+
const cbError = systemError.bind(null, system);
|
|
786
|
+
try {
|
|
787
|
+
system.shutdown(self, cbOK, cbError);
|
|
788
|
+
} catch (e) {
|
|
789
|
+
//failure in shutdown function
|
|
790
|
+
cbError(e);
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|