@needle-tools/engine 2.67.8-pre → 2.67.9-pre
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/CHANGELOG.md +7 -0
- package/dist/needle-engine.js +2763 -2779
- package/dist/needle-engine.umd.cjs +79 -79
- package/lib/engine/engine_mainloop_utils.js +11 -4
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine-components/SpriteRenderer.d.ts +6 -10
- package/lib/engine-components/SpriteRenderer.js +26 -48
- package/lib/engine-components/SpriteRenderer.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +1 -0
- package/lib/engine-components/codegen/components.js +1 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/package.json +2 -2
- package/src/engine/engine_mainloop_utils.ts +395 -387
- package/src/engine-components/SpriteRenderer.ts +27 -44
- package/src/engine-components/codegen/components.ts +1 -0
|
@@ -1,388 +1,396 @@
|
|
|
1
|
-
import * as utils from "./engine_generic_utils";
|
|
2
|
-
import * as constants from "./engine_constants";
|
|
3
|
-
import { getParam } from './engine_utils';
|
|
4
|
-
import { CubeCamera, Object3D, WebGLCubeRenderTarget } from 'three';
|
|
5
|
-
import { IComponent, IContext } from './engine_types';
|
|
6
|
-
import { isActiveSelf } from './engine_gameobject';
|
|
7
|
-
import { ContextRegistry } from "./engine_context_registry";
|
|
8
|
-
|
|
9
|
-
const debug = getParam("debugnewscripts");
|
|
10
|
-
const debugHierarchy = getParam("debughierarchy");
|
|
11
|
-
|
|
12
|
-
// if some other script adds new scripts in onEnable or awake
|
|
13
|
-
// the original array should be cleared before processing it
|
|
14
|
-
// so we use this copy buffer
|
|
15
|
-
const new_scripts_buffer: any[] = [];
|
|
16
|
-
|
|
17
|
-
export function processNewScripts(context: IContext) {
|
|
18
|
-
if (context.new_scripts.length <= 0) return;
|
|
19
|
-
if (debug)
|
|
20
|
-
console.log("Register new components", context.new_scripts.length, [...context.new_scripts], context.alias ? ("element: " + context.alias) : context["hash"], context);
|
|
21
|
-
|
|
22
|
-
// if(new_scripts_post_setup_callbacks.length > 0) console.log(new_scripts_post_setup_callbacks);
|
|
23
|
-
if (context.new_scripts_pre_setup_callbacks.length > 0) {
|
|
24
|
-
for (const cb of context.new_scripts_pre_setup_callbacks) {
|
|
25
|
-
if (!cb) continue;
|
|
26
|
-
cb();
|
|
27
|
-
}
|
|
28
|
-
context.new_scripts_pre_setup_callbacks.length = 0;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// TODO: update all the code from above to use this logic
|
|
32
|
-
// basically code gen should add the scripts to new scripts
|
|
33
|
-
// and this code below should go into some util method
|
|
34
|
-
new_scripts_buffer.length = 0;
|
|
35
|
-
if (context.new_scripts.length > 0) {
|
|
36
|
-
new_scripts_buffer.push(...context.new_scripts);
|
|
37
|
-
}
|
|
38
|
-
context.new_scripts.length = 0;
|
|
39
|
-
|
|
40
|
-
// Check valid scripts and add all valid to the scripts array
|
|
41
|
-
for (let i = 0; i < new_scripts_buffer.length; i++) {
|
|
42
|
-
try {
|
|
43
|
-
const script: IComponent = new_scripts_buffer[i];
|
|
44
|
-
if (script.destroyed) continue;
|
|
45
|
-
if (!script.gameObject) {
|
|
46
|
-
console.error("MISSING GAMEOBJECT - will ignore", script);
|
|
47
|
-
new_scripts_buffer.splice(i, 1);
|
|
48
|
-
i--;
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
script.context = context;
|
|
52
|
-
updateActiveInHierarchyWithoutEventCall(script.gameObject);
|
|
53
|
-
addScriptToArrays(script, context);
|
|
54
|
-
}
|
|
55
|
-
catch (err) {
|
|
56
|
-
console.error(err);
|
|
57
|
-
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
58
|
-
new_scripts_buffer.splice(i, 1);
|
|
59
|
-
i--;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Awake
|
|
64
|
-
for (let i = 0; i < new_scripts_buffer.length; i++) {
|
|
65
|
-
try {
|
|
66
|
-
const script: IComponent = new_scripts_buffer[i];
|
|
67
|
-
if (script.destroyed) {
|
|
68
|
-
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
69
|
-
new_scripts_buffer.splice(i, 1);
|
|
70
|
-
i--; continue;
|
|
71
|
-
}
|
|
72
|
-
if (script.registering) {
|
|
73
|
-
try {
|
|
74
|
-
script.registering();
|
|
75
|
-
}
|
|
76
|
-
catch (err) { console.error(err); }
|
|
77
|
-
}
|
|
78
|
-
// console.log(script, script.gameObject)
|
|
79
|
-
// TODO: we should not call awake on components with inactive gameobjects
|
|
80
|
-
if (script.__internalAwake !== undefined) {
|
|
81
|
-
if (!script.gameObject) {
|
|
82
|
-
console.error("MISSING GAMEOBJECT", script, script.gameObject);
|
|
83
|
-
}
|
|
84
|
-
updateActiveInHierarchyWithoutEventCall(script.gameObject);
|
|
85
|
-
if (script.activeAndEnabled)
|
|
86
|
-
utils.safeInvoke(script.__internalAwake.bind(script));
|
|
87
|
-
|
|
88
|
-
// registerPrewarmObject(script.gameObject, context);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (err) {
|
|
92
|
-
console.error(err);
|
|
93
|
-
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
94
|
-
new_scripts_buffer.splice(i, 1);
|
|
95
|
-
i--;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// OnEnable
|
|
100
|
-
for (let i = 0; i < new_scripts_buffer.length; i++) {
|
|
101
|
-
try {
|
|
102
|
-
const script: IComponent = new_scripts_buffer[i];
|
|
103
|
-
if (script.destroyed) continue;
|
|
104
|
-
// console.log(script, script.enabled, script.activeAndEnabled);
|
|
105
|
-
if (script.enabled === false) continue;
|
|
106
|
-
updateActiveInHierarchyWithoutEventCall(script.gameObject);
|
|
107
|
-
if (script.activeAndEnabled === false) continue;
|
|
108
|
-
if (script.__internalEnable !== undefined) {
|
|
109
|
-
script.enabled = true;
|
|
110
|
-
utils.safeInvoke(script.__internalEnable.bind(script));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
catch (err) {
|
|
114
|
-
console.error(err);
|
|
115
|
-
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
116
|
-
new_scripts_buffer.splice(i, 1);
|
|
117
|
-
i--;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Enqueue Start
|
|
122
|
-
for (let i = 0; i < new_scripts_buffer.length; i++) {
|
|
123
|
-
try {
|
|
124
|
-
const script = new_scripts_buffer[i];
|
|
125
|
-
if (script.destroyed) continue;
|
|
126
|
-
if (!script.gameObject) continue;
|
|
127
|
-
context.new_script_start.push(script);
|
|
128
|
-
}
|
|
129
|
-
catch (err) {
|
|
130
|
-
console.error(err);
|
|
131
|
-
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
132
|
-
new_scripts_buffer.splice(i, 1);
|
|
133
|
-
i--;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// for (const script of new_scripts_buffer) {
|
|
138
|
-
// if (script.destroyed) continue;
|
|
139
|
-
// context.scripts.push(script);
|
|
140
|
-
// }
|
|
141
|
-
new_scripts_buffer.length = 0;
|
|
142
|
-
|
|
143
|
-
// if(new_scripts_post_setup_callbacks.length > 0) console.log(new_scripts_post_setup_callbacks);
|
|
144
|
-
for (const cb of context.new_scripts_post_setup_callbacks) {
|
|
145
|
-
if (cb)
|
|
146
|
-
cb();
|
|
147
|
-
}
|
|
148
|
-
context.new_scripts_post_setup_callbacks.length = 0;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function processRemoveFromScene(script: IComponent) {
|
|
152
|
-
if (!script) return;
|
|
153
|
-
script.__internalDisable();
|
|
154
|
-
removeScriptFromContext(script, script.context);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function processStart(context: IContext, object?: Object3D) {
|
|
158
|
-
// Call start on scripts
|
|
159
|
-
for (let i = 0; i < context.new_script_start.length; i++) {
|
|
160
|
-
try {
|
|
161
|
-
const script = context.new_script_start[i];
|
|
162
|
-
if (object !== undefined && script.gameObject !== object) continue;
|
|
163
|
-
if (script.destroyed) continue;
|
|
164
|
-
if (script.activeAndEnabled === false) {
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
// keep them in queue until script has started
|
|
168
|
-
// call awake if the script was inactive before
|
|
169
|
-
utils.safeInvoke(script.__internalAwake.bind(script));
|
|
170
|
-
utils.safeInvoke(script.__internalEnable.bind(script));
|
|
171
|
-
// now call start
|
|
172
|
-
utils.safeInvoke(script.__internalStart.bind(script));
|
|
173
|
-
context.new_script_start.splice(i, 1);
|
|
174
|
-
i--;
|
|
175
|
-
}
|
|
176
|
-
catch (err) {
|
|
177
|
-
console.error(err);
|
|
178
|
-
removeScriptFromContext(context.new_script_start[i], context);
|
|
179
|
-
context.new_script_start.splice(i, 1);
|
|
180
|
-
i--;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
export function addScriptToArrays(script: any, context: IContext) {
|
|
187
|
-
// TODO: not sure if this is ideal - maybe we should add a map if we have many scripts?
|
|
188
|
-
const index = context.scripts.indexOf(script);
|
|
189
|
-
if (index !== -1) return;
|
|
190
|
-
context.scripts.push(script);
|
|
191
|
-
if (script.earlyUpdate) context.scripts_earlyUpdate.push(script);
|
|
192
|
-
if (script.update) context.scripts_update.push(script);
|
|
193
|
-
if (script.lateUpdate) context.scripts_lateUpdate.push(script);
|
|
194
|
-
if (script.onBeforeRender) context.scripts_onBeforeRender.push(script);
|
|
195
|
-
if (script.onAfterRender) context.scripts_onAfterRender.push(script);
|
|
196
|
-
if (script.onPausedChanged) context.scripts_pausedChanged.push(script);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
export function removeScriptFromContext(script: any, context: IContext) {
|
|
201
|
-
removeFromArray(script, context.new_scripts);
|
|
202
|
-
removeFromArray(script, context.new_script_start);
|
|
203
|
-
removeFromArray(script, context.scripts);
|
|
204
|
-
removeFromArray(script, context.scripts_earlyUpdate);
|
|
205
|
-
removeFromArray(script, context.scripts_update);
|
|
206
|
-
removeFromArray(script, context.scripts_lateUpdate);
|
|
207
|
-
removeFromArray(script, context.scripts_onBeforeRender);
|
|
208
|
-
removeFromArray(script, context.scripts_onAfterRender);
|
|
209
|
-
removeFromArray(script, context.scripts_pausedChanged);
|
|
210
|
-
context.stopAllCoroutinesFrom(script);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function removeFromArray(script: any, array: any[]) {
|
|
214
|
-
const index = array.indexOf(script);
|
|
215
|
-
if (index >= 0) array.splice(index, 1);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
export function updateIsActive(obj?: Object3D) {
|
|
220
|
-
if (!obj) obj = ContextRegistry.Current.scene;
|
|
221
|
-
if (!obj) {
|
|
222
|
-
console.trace("Invalid call - no current context.");
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const activeSelf = isActiveSelf(obj);
|
|
226
|
-
const wasSuccessful = updateIsActiveInHierarchyRecursiveRuntime(obj, activeSelf, true);
|
|
227
|
-
if (!wasSuccessful) {
|
|
228
|
-
console.error("Failed to update active state in hierarchy of \"" + obj.name + "\"", obj);
|
|
229
|
-
console.warn(" ↑ this error might be caused by circular references. Please make sure you don't have files with circular references (e.g. one GLB 1 is loading GLB 2 which is then loading GLB 1 again).")
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function updateIsActiveInHierarchyRecursiveRuntime(go: THREE.Object3D, activeInHierarchy: boolean, allowEventCall: boolean, level: number = 0) {
|
|
234
|
-
if (level > 1000) {
|
|
235
|
-
console.warn("Hierarchy is too deep (> 1000 level) - will abort updating active state");
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const isActive = isActiveSelf(go);
|
|
240
|
-
if (activeInHierarchy) {
|
|
241
|
-
activeInHierarchy = isActive;
|
|
242
|
-
// IF we update activeInHierarchy within a disabled hierarchy we need to check the parent
|
|
243
|
-
if (activeInHierarchy && go.parent) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
comp.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (go
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
1
|
+
import * as utils from "./engine_generic_utils";
|
|
2
|
+
import * as constants from "./engine_constants";
|
|
3
|
+
import { getParam } from './engine_utils';
|
|
4
|
+
import { CubeCamera, Object3D, Scene, WebGLCubeRenderTarget } from 'three';
|
|
5
|
+
import { IComponent, IContext } from './engine_types';
|
|
6
|
+
import { isActiveSelf } from './engine_gameobject';
|
|
7
|
+
import { ContextRegistry } from "./engine_context_registry";
|
|
8
|
+
|
|
9
|
+
const debug = getParam("debugnewscripts");
|
|
10
|
+
const debugHierarchy = getParam("debughierarchy");
|
|
11
|
+
|
|
12
|
+
// if some other script adds new scripts in onEnable or awake
|
|
13
|
+
// the original array should be cleared before processing it
|
|
14
|
+
// so we use this copy buffer
|
|
15
|
+
const new_scripts_buffer: any[] = [];
|
|
16
|
+
|
|
17
|
+
export function processNewScripts(context: IContext) {
|
|
18
|
+
if (context.new_scripts.length <= 0) return;
|
|
19
|
+
if (debug)
|
|
20
|
+
console.log("Register new components", context.new_scripts.length, [...context.new_scripts], context.alias ? ("element: " + context.alias) : context["hash"], context);
|
|
21
|
+
|
|
22
|
+
// if(new_scripts_post_setup_callbacks.length > 0) console.log(new_scripts_post_setup_callbacks);
|
|
23
|
+
if (context.new_scripts_pre_setup_callbacks.length > 0) {
|
|
24
|
+
for (const cb of context.new_scripts_pre_setup_callbacks) {
|
|
25
|
+
if (!cb) continue;
|
|
26
|
+
cb();
|
|
27
|
+
}
|
|
28
|
+
context.new_scripts_pre_setup_callbacks.length = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// TODO: update all the code from above to use this logic
|
|
32
|
+
// basically code gen should add the scripts to new scripts
|
|
33
|
+
// and this code below should go into some util method
|
|
34
|
+
new_scripts_buffer.length = 0;
|
|
35
|
+
if (context.new_scripts.length > 0) {
|
|
36
|
+
new_scripts_buffer.push(...context.new_scripts);
|
|
37
|
+
}
|
|
38
|
+
context.new_scripts.length = 0;
|
|
39
|
+
|
|
40
|
+
// Check valid scripts and add all valid to the scripts array
|
|
41
|
+
for (let i = 0; i < new_scripts_buffer.length; i++) {
|
|
42
|
+
try {
|
|
43
|
+
const script: IComponent = new_scripts_buffer[i];
|
|
44
|
+
if (script.destroyed) continue;
|
|
45
|
+
if (!script.gameObject) {
|
|
46
|
+
console.error("MISSING GAMEOBJECT - will ignore", script);
|
|
47
|
+
new_scripts_buffer.splice(i, 1);
|
|
48
|
+
i--;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
script.context = context;
|
|
52
|
+
updateActiveInHierarchyWithoutEventCall(script.gameObject);
|
|
53
|
+
addScriptToArrays(script, context);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error(err);
|
|
57
|
+
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
58
|
+
new_scripts_buffer.splice(i, 1);
|
|
59
|
+
i--;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Awake
|
|
64
|
+
for (let i = 0; i < new_scripts_buffer.length; i++) {
|
|
65
|
+
try {
|
|
66
|
+
const script: IComponent = new_scripts_buffer[i];
|
|
67
|
+
if (script.destroyed) {
|
|
68
|
+
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
69
|
+
new_scripts_buffer.splice(i, 1);
|
|
70
|
+
i--; continue;
|
|
71
|
+
}
|
|
72
|
+
if (script.registering) {
|
|
73
|
+
try {
|
|
74
|
+
script.registering();
|
|
75
|
+
}
|
|
76
|
+
catch (err) { console.error(err); }
|
|
77
|
+
}
|
|
78
|
+
// console.log(script, script.gameObject)
|
|
79
|
+
// TODO: we should not call awake on components with inactive gameobjects
|
|
80
|
+
if (script.__internalAwake !== undefined) {
|
|
81
|
+
if (!script.gameObject) {
|
|
82
|
+
console.error("MISSING GAMEOBJECT", script, script.gameObject);
|
|
83
|
+
}
|
|
84
|
+
updateActiveInHierarchyWithoutEventCall(script.gameObject);
|
|
85
|
+
if (script.activeAndEnabled)
|
|
86
|
+
utils.safeInvoke(script.__internalAwake.bind(script));
|
|
87
|
+
|
|
88
|
+
// registerPrewarmObject(script.gameObject, context);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
console.error(err);
|
|
93
|
+
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
94
|
+
new_scripts_buffer.splice(i, 1);
|
|
95
|
+
i--;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// OnEnable
|
|
100
|
+
for (let i = 0; i < new_scripts_buffer.length; i++) {
|
|
101
|
+
try {
|
|
102
|
+
const script: IComponent = new_scripts_buffer[i];
|
|
103
|
+
if (script.destroyed) continue;
|
|
104
|
+
// console.log(script, script.enabled, script.activeAndEnabled);
|
|
105
|
+
if (script.enabled === false) continue;
|
|
106
|
+
updateActiveInHierarchyWithoutEventCall(script.gameObject);
|
|
107
|
+
if (script.activeAndEnabled === false) continue;
|
|
108
|
+
if (script.__internalEnable !== undefined) {
|
|
109
|
+
script.enabled = true;
|
|
110
|
+
utils.safeInvoke(script.__internalEnable.bind(script));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error(err);
|
|
115
|
+
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
116
|
+
new_scripts_buffer.splice(i, 1);
|
|
117
|
+
i--;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Enqueue Start
|
|
122
|
+
for (let i = 0; i < new_scripts_buffer.length; i++) {
|
|
123
|
+
try {
|
|
124
|
+
const script = new_scripts_buffer[i];
|
|
125
|
+
if (script.destroyed) continue;
|
|
126
|
+
if (!script.gameObject) continue;
|
|
127
|
+
context.new_script_start.push(script);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
console.error(err);
|
|
131
|
+
removeScriptFromContext(new_scripts_buffer[i], context);
|
|
132
|
+
new_scripts_buffer.splice(i, 1);
|
|
133
|
+
i--;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// for (const script of new_scripts_buffer) {
|
|
138
|
+
// if (script.destroyed) continue;
|
|
139
|
+
// context.scripts.push(script);
|
|
140
|
+
// }
|
|
141
|
+
new_scripts_buffer.length = 0;
|
|
142
|
+
|
|
143
|
+
// if(new_scripts_post_setup_callbacks.length > 0) console.log(new_scripts_post_setup_callbacks);
|
|
144
|
+
for (const cb of context.new_scripts_post_setup_callbacks) {
|
|
145
|
+
if (cb)
|
|
146
|
+
cb();
|
|
147
|
+
}
|
|
148
|
+
context.new_scripts_post_setup_callbacks.length = 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function processRemoveFromScene(script: IComponent) {
|
|
152
|
+
if (!script) return;
|
|
153
|
+
script.__internalDisable();
|
|
154
|
+
removeScriptFromContext(script, script.context);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function processStart(context: IContext, object?: Object3D) {
|
|
158
|
+
// Call start on scripts
|
|
159
|
+
for (let i = 0; i < context.new_script_start.length; i++) {
|
|
160
|
+
try {
|
|
161
|
+
const script = context.new_script_start[i];
|
|
162
|
+
if (object !== undefined && script.gameObject !== object) continue;
|
|
163
|
+
if (script.destroyed) continue;
|
|
164
|
+
if (script.activeAndEnabled === false) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// keep them in queue until script has started
|
|
168
|
+
// call awake if the script was inactive before
|
|
169
|
+
utils.safeInvoke(script.__internalAwake.bind(script));
|
|
170
|
+
utils.safeInvoke(script.__internalEnable.bind(script));
|
|
171
|
+
// now call start
|
|
172
|
+
utils.safeInvoke(script.__internalStart.bind(script));
|
|
173
|
+
context.new_script_start.splice(i, 1);
|
|
174
|
+
i--;
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
console.error(err);
|
|
178
|
+
removeScriptFromContext(context.new_script_start[i], context);
|
|
179
|
+
context.new_script_start.splice(i, 1);
|
|
180
|
+
i--;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
export function addScriptToArrays(script: any, context: IContext) {
|
|
187
|
+
// TODO: not sure if this is ideal - maybe we should add a map if we have many scripts?
|
|
188
|
+
const index = context.scripts.indexOf(script);
|
|
189
|
+
if (index !== -1) return;
|
|
190
|
+
context.scripts.push(script);
|
|
191
|
+
if (script.earlyUpdate) context.scripts_earlyUpdate.push(script);
|
|
192
|
+
if (script.update) context.scripts_update.push(script);
|
|
193
|
+
if (script.lateUpdate) context.scripts_lateUpdate.push(script);
|
|
194
|
+
if (script.onBeforeRender) context.scripts_onBeforeRender.push(script);
|
|
195
|
+
if (script.onAfterRender) context.scripts_onAfterRender.push(script);
|
|
196
|
+
if (script.onPausedChanged) context.scripts_pausedChanged.push(script);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
export function removeScriptFromContext(script: any, context: IContext) {
|
|
201
|
+
removeFromArray(script, context.new_scripts);
|
|
202
|
+
removeFromArray(script, context.new_script_start);
|
|
203
|
+
removeFromArray(script, context.scripts);
|
|
204
|
+
removeFromArray(script, context.scripts_earlyUpdate);
|
|
205
|
+
removeFromArray(script, context.scripts_update);
|
|
206
|
+
removeFromArray(script, context.scripts_lateUpdate);
|
|
207
|
+
removeFromArray(script, context.scripts_onBeforeRender);
|
|
208
|
+
removeFromArray(script, context.scripts_onAfterRender);
|
|
209
|
+
removeFromArray(script, context.scripts_pausedChanged);
|
|
210
|
+
context.stopAllCoroutinesFrom(script);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function removeFromArray(script: any, array: any[]) {
|
|
214
|
+
const index = array.indexOf(script);
|
|
215
|
+
if (index >= 0) array.splice(index, 1);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
export function updateIsActive(obj?: Object3D) {
|
|
220
|
+
if (!obj) obj = ContextRegistry.Current.scene;
|
|
221
|
+
if (!obj) {
|
|
222
|
+
console.trace("Invalid call - no current context.");
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const activeSelf = isActiveSelf(obj);
|
|
226
|
+
const wasSuccessful = updateIsActiveInHierarchyRecursiveRuntime(obj, activeSelf, true);
|
|
227
|
+
if (!wasSuccessful) {
|
|
228
|
+
console.error("Failed to update active state in hierarchy of \"" + obj.name + "\"", obj);
|
|
229
|
+
console.warn(" ↑ this error might be caused by circular references. Please make sure you don't have files with circular references (e.g. one GLB 1 is loading GLB 2 which is then loading GLB 1 again).")
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function updateIsActiveInHierarchyRecursiveRuntime(go: THREE.Object3D, activeInHierarchy: boolean, allowEventCall: boolean, level: number = 0) {
|
|
234
|
+
if (level > 1000) {
|
|
235
|
+
console.warn("Hierarchy is too deep (> 1000 level) - will abort updating active state");
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const isActive = isActiveSelf(go);
|
|
240
|
+
if (activeInHierarchy) {
|
|
241
|
+
activeInHierarchy = isActive;
|
|
242
|
+
// IF we update activeInHierarchy within a disabled hierarchy we need to check the parent
|
|
243
|
+
if (activeInHierarchy && go.parent) {
|
|
244
|
+
const parent = go.parent;
|
|
245
|
+
activeInHierarchy = parent[constants.activeInHierarchyFieldName];
|
|
246
|
+
if (activeInHierarchy === undefined) {
|
|
247
|
+
// TODO: come up with a better solution for this. When we are in a r3f hierarchy (externally managed) and the parent flag is undefined we set it to true if the parent is NOT a scene. This activates the object by default. We should probably walk up the stack and check if we can find either the root Scene or any object that is disabled and use that to set the activeInHierarchy flag.
|
|
248
|
+
if (parent instanceof Scene) {
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
activeInHierarchy = true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const prevActive = go[constants.activeInHierarchyFieldName];
|
|
258
|
+
const changed = prevActive !== activeInHierarchy;
|
|
259
|
+
go[constants.activeInHierarchyFieldName] = activeInHierarchy;
|
|
260
|
+
|
|
261
|
+
// only raise events here if we didnt call enable etc already
|
|
262
|
+
if (changed) {
|
|
263
|
+
if (debugHierarchy)
|
|
264
|
+
console.warn("ACTIVE CHANGE", go.name, isActive, go.visible, activeInHierarchy, "changed?" + changed, go);
|
|
265
|
+
if (allowEventCall) {
|
|
266
|
+
perComponent(go, comp => {
|
|
267
|
+
if (activeInHierarchy) {
|
|
268
|
+
if (comp.enabled) {
|
|
269
|
+
utils.safeInvoke(comp.__internalAwake.bind(comp));
|
|
270
|
+
comp["__didEnable"] = true;
|
|
271
|
+
comp.onEnable();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
if (comp["__didAwake"]) {
|
|
276
|
+
comp["__didEnable"] = false;
|
|
277
|
+
comp.onDisable();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let success = true;
|
|
285
|
+
if (go.children) {
|
|
286
|
+
const nextLevel = level + 1;
|
|
287
|
+
for (const ch of go.children) {
|
|
288
|
+
const res = updateIsActiveInHierarchyRecursiveRuntime(ch, activeInHierarchy, allowEventCall, nextLevel);
|
|
289
|
+
if (res === false) success = false;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return success;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// let isRunning = false;
|
|
296
|
+
// // Prevent: https://github.com/needle-tools/needle-tiny/issues/641
|
|
297
|
+
// const temporyChildArrayBuffer: Array<Array<THREE.Object3D>> = [];
|
|
298
|
+
// export function* iterateChildrenSafe(obj: Object3D) {
|
|
299
|
+
// if (!obj || !obj.children) yield null;
|
|
300
|
+
// // if(isRunning) return;
|
|
301
|
+
// // isRunning = true;
|
|
302
|
+
// const arr = temporyChildArrayBuffer.pop() || [];
|
|
303
|
+
// arr.push(...obj.children);
|
|
304
|
+
// for (const ch of arr) {
|
|
305
|
+
// yield ch;
|
|
306
|
+
// }
|
|
307
|
+
// // isRunning = false;
|
|
308
|
+
// arr.length = 0;
|
|
309
|
+
// temporyChildArrayBuffer.push(arr);
|
|
310
|
+
// }
|
|
311
|
+
|
|
312
|
+
export function updateActiveInHierarchyWithoutEventCall(go: THREE.Object3D) {
|
|
313
|
+
let activeInHierarchy = true;
|
|
314
|
+
let current: THREE.Object3D | null = go;
|
|
315
|
+
let foundScene: boolean = false;
|
|
316
|
+
while (current) {
|
|
317
|
+
if (!current) break;
|
|
318
|
+
if (current.type === "Scene") foundScene = true;
|
|
319
|
+
if (!isActiveSelf(current)) {
|
|
320
|
+
activeInHierarchy = false;
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
current = current.parent;
|
|
324
|
+
}
|
|
325
|
+
if (!go) {
|
|
326
|
+
console.error("GO is null");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
go[constants.activeInHierarchyFieldName] = activeInHierarchy && foundScene;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function perComponent(go: THREE.Object3D, evt: (comp: IComponent) => void) {
|
|
333
|
+
if (go.userData?.components) {
|
|
334
|
+
for (const comp of go.userData.components) {
|
|
335
|
+
evt(comp);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
const prewarmList: Map<IContext, Object3D[]> = new Map();
|
|
342
|
+
const $prewarmedFlag = Symbol("prewarmFlag");
|
|
343
|
+
const $waitingForPrewarm = Symbol("waitingForPrewarm");
|
|
344
|
+
const debugPrewarm = getParam("debugprewarm");
|
|
345
|
+
|
|
346
|
+
export function registerPrewarmObject(obj: Object3D, context: IContext) {
|
|
347
|
+
if (!obj) return;
|
|
348
|
+
// allow objects to be marked as prewarmed in which case we dont need to register them again
|
|
349
|
+
if (obj[$prewarmedFlag] === true) return;
|
|
350
|
+
if (obj[$waitingForPrewarm] === true) return;
|
|
351
|
+
if (!prewarmList.has(context)) {
|
|
352
|
+
prewarmList.set(context, []);
|
|
353
|
+
}
|
|
354
|
+
obj[$waitingForPrewarm] = true;
|
|
355
|
+
const list = prewarmList.get(context);
|
|
356
|
+
list!.push(obj);
|
|
357
|
+
if (debugPrewarm) console.debug("register prewarm", obj.name);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
let prewarmTarget: WebGLCubeRenderTarget | null = null;
|
|
361
|
+
let prewarmCamera: CubeCamera | null = null;
|
|
362
|
+
|
|
363
|
+
// called by the engine to remove scroll or animation hiccup when objects are rendered/compiled for the first time
|
|
364
|
+
export function runPrewarm(context: IContext) {
|
|
365
|
+
if (!context) return;
|
|
366
|
+
const list = prewarmList.get(context);
|
|
367
|
+
if (!list?.length) return;
|
|
368
|
+
|
|
369
|
+
const cam = context.mainCamera;
|
|
370
|
+
if (cam) {
|
|
371
|
+
if (debugPrewarm) console.log("prewarm", list.length, "objects", [...list]);
|
|
372
|
+
const renderer = context.renderer;
|
|
373
|
+
const scene = context.scene;
|
|
374
|
+
renderer.compile(scene, cam!)
|
|
375
|
+
prewarmTarget ??= new WebGLCubeRenderTarget(64)
|
|
376
|
+
prewarmCamera ??= new CubeCamera(0.001, 9999999, prewarmTarget);
|
|
377
|
+
prewarmCamera.update(renderer, scene);
|
|
378
|
+
for (const obj of list) {
|
|
379
|
+
obj[$prewarmedFlag] = true;
|
|
380
|
+
obj[$waitingForPrewarm] = false;
|
|
381
|
+
}
|
|
382
|
+
list.length = 0;
|
|
383
|
+
if (debugPrewarm) console.log("prewarm done");
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export function clearPrewarmList(context: IContext) {
|
|
388
|
+
const list = prewarmList.get(context);
|
|
389
|
+
if (list) {
|
|
390
|
+
for (const obj of list) {
|
|
391
|
+
obj[$waitingForPrewarm] = false;
|
|
392
|
+
}
|
|
393
|
+
list.length = 0;
|
|
394
|
+
}
|
|
395
|
+
prewarmList.delete(context);
|
|
388
396
|
}
|