@needle-tools/engine 2.63.3-pre → 2.64.0-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 +13 -0
- package/dist/needle-engine.js +9760 -9635
- package/dist/needle-engine.umd.cjs +237 -236
- package/lib/engine/engine_application.d.ts +7 -1
- package/lib/engine/engine_application.js +11 -0
- package/lib/engine/engine_application.js.map +1 -1
- package/lib/engine/engine_constants.d.ts +1 -1
- package/lib/engine/engine_constants.js +1 -1
- package/lib/engine/engine_constants.js.map +1 -1
- package/lib/engine/engine_gameobject.js +2 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_instancing.d.ts +1 -0
- package/lib/engine/engine_instancing.js +3 -2
- package/lib/engine/engine_instancing.js.map +1 -1
- package/lib/engine/engine_license.js +14 -13
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +27 -52
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +1 -0
- package/lib/engine/engine_physics.js +30 -0
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.d.ts +1 -0
- package/lib/engine/engine_serialization_builtin_serializer.js +30 -25
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/engine_serialization_core.js +8 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +1 -1
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_time.d.ts +1 -0
- package/lib/engine/engine_time.js +5 -1
- package/lib/engine/engine_time.js.map +1 -1
- package/lib/engine/engine_types.d.ts +12 -0
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine-components/Animation.js +6 -6
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +2 -0
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioListener.js +2 -0
- package/lib/engine-components/AudioListener.js.map +1 -1
- package/lib/engine-components/AudioSource.d.ts +2 -1
- package/lib/engine-components/AudioSource.js +19 -4
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/Component.d.ts +1 -0
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/GridHelper.d.ts +1 -0
- package/lib/engine-components/GridHelper.js +7 -0
- package/lib/engine-components/GridHelper.js.map +1 -1
- package/lib/engine-components/ParticleSystem.js +13 -1
- package/lib/engine-components/ParticleSystem.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +5 -1
- package/lib/engine-components/Renderer.js +78 -29
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/WebARSessionRoot.d.ts +1 -0
- package/lib/engine-components/WebARSessionRoot.js +10 -0
- package/lib/engine-components/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/js-extensions/Object3D.js +11 -1
- package/lib/engine-components/js-extensions/Object3D.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +5 -0
- package/lib/engine-components/timeline/PlayableDirector.js +36 -23
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +9 -0
- package/lib/engine-components/timeline/TimelineTracks.js +121 -21
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/engine/engine_application.ts +14 -3
- package/src/engine/engine_constants.ts +1 -1
- package/src/engine/engine_gameobject.ts +2 -2
- package/src/engine/engine_instancing.ts +3 -3
- package/src/engine/engine_license.ts +14 -13
- package/src/engine/engine_mainloop_utils.ts +32 -58
- package/src/engine/engine_physics.ts +23 -0
- package/src/engine/engine_serialization_builtin_serializer.ts +36 -27
- package/src/engine/engine_serialization_core.ts +8 -1
- package/src/engine/engine_setup.ts +1 -1
- package/src/engine/engine_time.ts +9 -4
- package/src/engine/engine_types.ts +36 -22
- package/src/engine-components/Animation.ts +6 -5
- package/src/engine-components/AnimatorController.ts +1 -0
- package/src/engine-components/AudioListener.ts +1 -0
- package/src/engine-components/AudioSource.ts +20 -6
- package/src/engine-components/Component.ts +3 -0
- package/src/engine-components/GridHelper.ts +10 -2
- package/src/engine-components/ParticleSystem.ts +15 -2
- package/src/engine-components/Renderer.ts +92 -33
- package/src/engine-components/WebARSessionRoot.ts +14 -0
- package/src/engine-components/js-extensions/Object3D.ts +11 -3
- package/src/engine-components/timeline/PlayableDirector.ts +35 -24
- package/src/engine-components/timeline/TimelineTracks.ts +132 -22
- package/src/tsconfig.json +33 -0
- package/src/engine/codegen/license.js +0 -1
- /package/{src/plugins → plugins}/vite/build.js +0 -0
- /package/{src/plugins → plugins}/vite/config.js +0 -0
- /package/{src/plugins → plugins}/vite/gzip.js +0 -0
- /package/{src/plugins → plugins}/vite/index.js +0 -0
- /package/{src/plugins → plugins}/vite/meta.js +0 -0
- /package/{src/plugins → plugins}/vite/poster-client.js +0 -0
- /package/{src/plugins → plugins}/vite/poster.js +0 -0
- /package/{src/plugins → plugins}/vite/reload-client.js +0 -0
- /package/{src/plugins → plugins}/vite/reload.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.64.0-pre",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally.",
|
|
5
5
|
"main": "dist/needle-engine.umd.cjs",
|
|
6
6
|
"module": "dist/needle-engine.js",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"src",
|
|
27
27
|
"dist",
|
|
28
28
|
"lib",
|
|
29
|
+
"plugins",
|
|
29
30
|
"license-2447137e.js"
|
|
30
31
|
],
|
|
31
32
|
"keywords": [
|
|
@@ -3,13 +3,24 @@ import { Context } from "./engine_setup";
|
|
|
3
3
|
export enum ApplicationEvents {
|
|
4
4
|
Visible = "application-visible",
|
|
5
5
|
Hidden = "application-hidden",
|
|
6
|
+
MuteChanged = "application-mutechanged",
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export class Application extends EventTarget {
|
|
9
10
|
|
|
10
|
-
private
|
|
11
|
+
private _mute: boolean = false;
|
|
12
|
+
/** audio muted? */
|
|
13
|
+
get muted() { return this._mute; }
|
|
14
|
+
/** set global audio mute */
|
|
15
|
+
set muted(value) {
|
|
16
|
+
if (value === this._mute) return;
|
|
17
|
+
this._mute = value;
|
|
18
|
+
this.dispatchEvent(new Event(ApplicationEvents.MuteChanged));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private context: Context;
|
|
11
22
|
|
|
12
|
-
public get hasFocus()
|
|
23
|
+
public get hasFocus(): boolean {
|
|
13
24
|
return document.hasFocus();
|
|
14
25
|
}
|
|
15
26
|
|
|
@@ -19,7 +30,7 @@ export class Application extends EventTarget {
|
|
|
19
30
|
|
|
20
31
|
private _isVisible: boolean = true;
|
|
21
32
|
|
|
22
|
-
constructor(context
|
|
33
|
+
constructor(context: Context) {
|
|
23
34
|
super();
|
|
24
35
|
this.context = context;
|
|
25
36
|
// console.log("APP");
|
|
@@ -6,7 +6,7 @@ import { logHierarchy, setWorldPosition, setWorldQuaternion } from "./engine_thr
|
|
|
6
6
|
import { GuidsMap, IComponent as Component, IComponent, IGameObject as GameObject, UIDProvider } from "./engine_types";
|
|
7
7
|
import { getParam, tryFindObject } from "./engine_utils";
|
|
8
8
|
import { apply } from "../engine-components/js-extensions/Object3D";
|
|
9
|
-
import { InstancingUtil } from "./engine_instancing";
|
|
9
|
+
import { $isUsingInstancing, InstancingUtil } from "./engine_instancing";
|
|
10
10
|
import { activeInHierarchyFieldName } from "./engine_constants";
|
|
11
11
|
import { assign } from "./engine_serialization_core";
|
|
12
12
|
|
|
@@ -75,7 +75,7 @@ export function isActiveInHierarchy(go: Object3D): boolean {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export function markAsInstancedRendered(go: THREE.Object3D, instanced: boolean) {
|
|
78
|
-
go[
|
|
78
|
+
go[$isUsingInstancing] = instanced;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export function isUsingInstancing(instance: THREE.Object3D): boolean { return InstancingUtil.isUsingInstancing(instance); }
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
export const NEED_UPDATE_INSTANCE_KEY = Symbol("NEEDLE_NEED_UPDATE_INSTANCE");
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export const $isUsingInstancing = Symbol("isUsingInstancing");
|
|
4
4
|
|
|
5
5
|
export class InstancingUtil {
|
|
6
6
|
|
|
7
|
-
static isUsingInstancing(instance: THREE.Object3D): boolean { return instance[
|
|
7
|
+
static isUsingInstancing(instance: THREE.Object3D): boolean { return instance[$isUsingInstancing] === true; }
|
|
8
8
|
|
|
9
9
|
// TODO: change this so it does not set matrix world directly but some flag that is only used by instancing
|
|
10
10
|
static markDirty(go: THREE.Object3D | null, recursive: boolean = true) {
|
|
11
11
|
if (!go) return;
|
|
12
12
|
// potential optimization:
|
|
13
13
|
// if(go.matrixWorldNeedsUpdate) return;
|
|
14
|
-
// console.
|
|
14
|
+
// console.warn("UPDATE", go);
|
|
15
15
|
if (this.isUsingInstancing(go)) {
|
|
16
16
|
go[NEED_UPDATE_INSTANCE_KEY] = true;
|
|
17
17
|
go.matrixWorldNeedsUpdate = true;
|
|
@@ -42,7 +42,7 @@ async function showLicenseInfo(ctx: IContext) {
|
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
const _licenseText = "🌵 <span class=\"text\">Made with <a href=\"https://needle.tools\" target=\"_blank\">Needle</a></span>";
|
|
45
|
-
const
|
|
45
|
+
const licenseElementIdentifier = "needle-license-element";
|
|
46
46
|
const licenseDuration = 30000;
|
|
47
47
|
const licenseDelay = 600;
|
|
48
48
|
|
|
@@ -78,6 +78,7 @@ function insertNonCommercialUseHint(ctx: IContext) {
|
|
|
78
78
|
setTimeout(() => {
|
|
79
79
|
clearInterval(interval);
|
|
80
80
|
licenseElement?.remove();
|
|
81
|
+
style?.remove();
|
|
81
82
|
}, removeDelay);
|
|
82
83
|
|
|
83
84
|
}
|
|
@@ -97,8 +98,7 @@ async function logNonCommercialUse(_logo?: string) {
|
|
|
97
98
|
|
|
98
99
|
function createLicenseElement() {
|
|
99
100
|
const licenseElement = document.createElement("div");
|
|
100
|
-
licenseElement.
|
|
101
|
-
licenseElement.setAttribute("data-needle_engine_license_element", "");
|
|
101
|
+
licenseElement.setAttribute(licenseElementIdentifier, "");
|
|
102
102
|
licenseElement.style.position = "fixed";
|
|
103
103
|
licenseElement.style.bottom = "12px";
|
|
104
104
|
licenseElement.style.right = "15px";
|
|
@@ -112,10 +112,8 @@ function createLicenseElement() {
|
|
|
112
112
|
// TODO: would be better to put this into a web element and use shadow dom
|
|
113
113
|
function createLicenseStyle() {
|
|
114
114
|
const licenseStyle = document.createElement("style");
|
|
115
|
-
const selector =
|
|
115
|
+
const selector = `div[${licenseElementIdentifier}]`;
|
|
116
116
|
licenseStyle.innerHTML = `
|
|
117
|
-
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;500&display=swap');
|
|
118
|
-
|
|
119
117
|
${selector} {
|
|
120
118
|
font-family: 'Roboto', sans-serif !important;
|
|
121
119
|
font-weight: 300;
|
|
@@ -145,23 +143,26 @@ function createLicenseStyle() {
|
|
|
145
143
|
opacity: .9;
|
|
146
144
|
}
|
|
147
145
|
2% {
|
|
148
|
-
transform: translate(0,
|
|
146
|
+
transform: translate(0, 2.5px);
|
|
149
147
|
}
|
|
150
|
-
|
|
148
|
+
3% {
|
|
151
149
|
transform: translate(0, 0px);
|
|
152
150
|
pointer-events: all;
|
|
153
151
|
opacity: 1;
|
|
154
152
|
}
|
|
155
|
-
|
|
153
|
+
4% {
|
|
156
154
|
transform: scale(1)
|
|
157
155
|
}
|
|
158
|
-
|
|
159
|
-
transform: scale(1.
|
|
156
|
+
4.5% {
|
|
157
|
+
transform: scale(1.3)
|
|
158
|
+
}
|
|
159
|
+
6% {
|
|
160
|
+
transform: scale(1.32)
|
|
160
161
|
}
|
|
161
|
-
|
|
162
|
+
7% {
|
|
162
163
|
transform: scale(1)
|
|
163
164
|
}
|
|
164
|
-
|
|
165
|
+
98% {
|
|
165
166
|
opacity: 1;
|
|
166
167
|
pointer-events: all;
|
|
167
168
|
transform: scale(1)
|
|
@@ -7,6 +7,7 @@ import { isActiveSelf } from './engine_gameobject';
|
|
|
7
7
|
import { ContextRegistry } from "./engine_context_registry";
|
|
8
8
|
|
|
9
9
|
const debug = getParam("debugnewscripts");
|
|
10
|
+
const debugHierarchy = getParam("debughierarchy");
|
|
10
11
|
|
|
11
12
|
// if some other script adds new scripts in onEnable or awake
|
|
12
13
|
// the original array should be cleared before processing it
|
|
@@ -214,8 +215,6 @@ function removeFromArray(script: any, array: any[]) {
|
|
|
214
215
|
if (index >= 0) array.splice(index, 1);
|
|
215
216
|
}
|
|
216
217
|
|
|
217
|
-
const previousActiveMap: { [key: string]: boolean } = {};
|
|
218
|
-
const previousActiveInHierarchyMap: { [key: string]: boolean } = {};
|
|
219
218
|
|
|
220
219
|
export function updateIsActive(obj?: Object3D) {
|
|
221
220
|
if (!obj) obj = ContextRegistry.Current.scene;
|
|
@@ -226,67 +225,43 @@ export function updateIsActive(obj?: Object3D) {
|
|
|
226
225
|
updateIsActiveInHierarchyRecursiveRuntime(obj, isActiveSelf(obj), true);
|
|
227
226
|
}
|
|
228
227
|
|
|
229
|
-
// const $wasSetVisibleBefore = Symbol("wasSetVisibleBefore");
|
|
230
228
|
|
|
231
229
|
function updateIsActiveInHierarchyRecursiveRuntime(go: THREE.Object3D, activeInHierarchy: boolean, allowEventCall: boolean) {
|
|
232
|
-
let activeStateChanged: boolean = false;
|
|
233
|
-
|
|
234
|
-
const active = isActiveSelf(go);
|
|
235
|
-
|
|
236
|
-
// this is a test if we dont control active state from visibility and set
|
|
237
|
-
// active to true by default (even if the object is invisible) in engine_gameobjects:isActiveSelf
|
|
238
|
-
// then we need to check if the object is set to visible for the first time
|
|
239
|
-
// const visible = go.visible;
|
|
240
|
-
// if (!active && visible) {
|
|
241
|
-
// if (!go[$wasSetVisibleBefore]) {
|
|
242
|
-
// go[$wasSetVisibleBefore] = true;
|
|
243
|
-
// setActive(go, true);
|
|
244
|
-
// }
|
|
245
|
-
// }
|
|
246
|
-
|
|
247
|
-
// if (activeInHierarchy) {
|
|
248
|
-
// const prevActive = previousActiveMap[go.uuid];
|
|
249
|
-
// if (prevActive !== undefined) {
|
|
250
|
-
// if (prevActive !== active) {
|
|
251
|
-
// activeStateChanged = true;
|
|
252
|
-
// if (allowEventCall) {
|
|
253
|
-
// perComponent(go, comp => {
|
|
254
|
-
// if (active) {
|
|
255
|
-
// utils.safeInvoke(comp.__internalAwake.bind(comp));
|
|
256
|
-
// comp.onEnable();
|
|
257
|
-
// }
|
|
258
|
-
// else comp.onDisable();
|
|
259
|
-
// });
|
|
260
|
-
// }
|
|
261
|
-
// }
|
|
262
|
-
// }
|
|
263
|
-
// }
|
|
264
|
-
previousActiveMap[go.uuid] = active;
|
|
265
230
|
|
|
231
|
+
if (activeInHierarchy) {
|
|
232
|
+
activeInHierarchy = isActiveSelf(go);
|
|
233
|
+
// IF we update activeInHierarchy within a disabled hierarchy we need to check the parent
|
|
234
|
+
if (activeInHierarchy && go.parent) {
|
|
235
|
+
activeInHierarchy = go.parent[constants.activeInHierarchyFieldName]
|
|
236
|
+
}
|
|
237
|
+
}
|
|
266
238
|
|
|
267
|
-
|
|
239
|
+
const prevActive = go[constants.activeInHierarchyFieldName];
|
|
240
|
+
const changed = prevActive !== activeInHierarchy;
|
|
268
241
|
go[constants.activeInHierarchyFieldName] = activeInHierarchy;
|
|
269
242
|
|
|
270
243
|
// only raise events here if we didnt call enable etc already
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
else comp.enabled = false;
|
|
284
|
-
});
|
|
244
|
+
if (changed) {
|
|
245
|
+
if (debugHierarchy)
|
|
246
|
+
console.warn("ACTIVE CHANGE", go.name, activeInHierarchy, "changed?" + changed, go.userData.components, go.children, go);
|
|
247
|
+
if (allowEventCall) {
|
|
248
|
+
perComponent(go, comp => {
|
|
249
|
+
if (activeInHierarchy) {
|
|
250
|
+
if (comp.enabled) {
|
|
251
|
+
utils.safeInvoke(comp.__internalAwake.bind(comp));
|
|
252
|
+
comp["__didEnable"] = true;
|
|
253
|
+
comp.onEnable();
|
|
254
|
+
}
|
|
285
255
|
}
|
|
286
|
-
|
|
256
|
+
else {
|
|
257
|
+
if (comp["__didAwake"]) {
|
|
258
|
+
comp["__didEnable"] = false;
|
|
259
|
+
comp.onDisable();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
});
|
|
287
263
|
}
|
|
288
264
|
}
|
|
289
|
-
previousActiveInHierarchyMap[go.uuid] = activeInHierarchy;
|
|
290
265
|
|
|
291
266
|
if (go.children) {
|
|
292
267
|
for (const ch of go.children) {
|
|
@@ -312,7 +287,6 @@ export function updateActiveInHierarchyWithoutEventCall(go: THREE.Object3D) {
|
|
|
312
287
|
console.error("GO is null");
|
|
313
288
|
return;
|
|
314
289
|
}
|
|
315
|
-
previousActiveInHierarchyMap[go.uuid] = activeInHierarchy;
|
|
316
290
|
go[constants.activeInHierarchyFieldName] = activeInHierarchy && foundScene;
|
|
317
291
|
}
|
|
318
292
|
|
|
@@ -341,7 +315,7 @@ export function registerPrewarmObject(obj: Object3D, context: IContext) {
|
|
|
341
315
|
obj[$waitingForPrewarm] = true;
|
|
342
316
|
const list = prewarmList.get(context);
|
|
343
317
|
list!.push(obj);
|
|
344
|
-
if(debugPrewarm) console.debug("register prewarm", obj.name);
|
|
318
|
+
if (debugPrewarm) console.debug("register prewarm", obj.name);
|
|
345
319
|
}
|
|
346
320
|
|
|
347
321
|
let prewarmTarget: WebGLCubeRenderTarget | null = null;
|
|
@@ -355,7 +329,7 @@ export function runPrewarm(context: IContext) {
|
|
|
355
329
|
|
|
356
330
|
const cam = context.mainCamera;
|
|
357
331
|
if (cam) {
|
|
358
|
-
if(debugPrewarm) console.log("prewarm", list.length, "objects", [...list]);
|
|
332
|
+
if (debugPrewarm) console.log("prewarm", list.length, "objects", [...list]);
|
|
359
333
|
const renderer = context.renderer;
|
|
360
334
|
const scene = context.scene;
|
|
361
335
|
renderer.compile(scene, cam!)
|
|
@@ -364,10 +338,10 @@ export function runPrewarm(context: IContext) {
|
|
|
364
338
|
prewarmCamera.update(renderer, scene);
|
|
365
339
|
for (const obj of list) {
|
|
366
340
|
obj[$prewarmedFlag] = true;
|
|
367
|
-
obj[$waitingForPrewarm] = false;
|
|
341
|
+
obj[$waitingForPrewarm] = false;
|
|
368
342
|
}
|
|
369
343
|
list.length = 0;
|
|
370
|
-
if(debugPrewarm) console.log("prewarm done");
|
|
344
|
+
if (debugPrewarm) console.log("prewarm done");
|
|
371
345
|
}
|
|
372
346
|
}
|
|
373
347
|
|
|
@@ -26,6 +26,7 @@ const debugPhysics = getParam("debugphysics");
|
|
|
26
26
|
const debugColliderPlacement = getParam("debugphysicscolliders");
|
|
27
27
|
const debugCollisions = getParam("debugcollisions");
|
|
28
28
|
const showColliders = getParam("showcolliders");
|
|
29
|
+
const noPhysics = getParam("nophysics");
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
declare type PhysicsBody = {
|
|
@@ -286,6 +287,8 @@ export class Physics {
|
|
|
286
287
|
|
|
287
288
|
// physics simulation
|
|
288
289
|
|
|
290
|
+
enabled: boolean = true;
|
|
291
|
+
|
|
289
292
|
private _tempPosition: Vector3 = new Vector3();
|
|
290
293
|
private _tempQuaternion: Quaternion = new Quaternion();
|
|
291
294
|
private _tempScale: Vector3 = new Vector3();
|
|
@@ -325,6 +328,7 @@ export class Physics {
|
|
|
325
328
|
Physics._didLoadPhysicsEngine = true;
|
|
326
329
|
}
|
|
327
330
|
this.world = new World(this._gravity);
|
|
331
|
+
if (noPhysics) this.enabled = false;
|
|
328
332
|
}
|
|
329
333
|
|
|
330
334
|
private _gravity = { x: 0.0, y: -9.81, z: 0.0 };
|
|
@@ -347,6 +351,10 @@ export class Physics {
|
|
|
347
351
|
}
|
|
348
352
|
|
|
349
353
|
addBoxCollider(collider: ICollider, center: Vector3, size: Vector3) {
|
|
354
|
+
if (!this.enabled) {
|
|
355
|
+
if(debugPhysics) console.warn("Physics is disabled");
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
350
358
|
const obj = collider.gameObject;
|
|
351
359
|
const scale = getWorldScale(obj, this._tempPosition).multiply(size);
|
|
352
360
|
scale.multiplyScalar(0.5);
|
|
@@ -355,6 +363,10 @@ export class Physics {
|
|
|
355
363
|
}
|
|
356
364
|
|
|
357
365
|
addSphereCollider(collider: ICollider, center: Vector3, radius: number) {
|
|
366
|
+
if (!this.enabled) {
|
|
367
|
+
if(debugPhysics) console.warn("Physics is disabled");
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
358
370
|
const obj = collider.gameObject;
|
|
359
371
|
const scale = getWorldScale(obj, this._tempPosition).multiplyScalar(radius);
|
|
360
372
|
const desc = ColliderDesc.ball(scale.x);
|
|
@@ -362,6 +374,10 @@ export class Physics {
|
|
|
362
374
|
}
|
|
363
375
|
|
|
364
376
|
addCapsuleCollider(collider: ICollider, center: Vector3, height: number, radius: number) {
|
|
377
|
+
if (!this.enabled) {
|
|
378
|
+
if(debugPhysics) console.warn("Physics is disabled");
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
365
381
|
const obj = collider.gameObject;
|
|
366
382
|
const scale = getWorldScale(obj, this._tempPosition);
|
|
367
383
|
if (debugPhysics) console.log("capsule scale", scale, height, radius);
|
|
@@ -370,6 +386,10 @@ export class Physics {
|
|
|
370
386
|
}
|
|
371
387
|
|
|
372
388
|
addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale: Vector3) {
|
|
389
|
+
if (!this.enabled) {
|
|
390
|
+
if(debugPhysics) console.warn("Physics is disabled");
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
373
393
|
const geo = mesh.geometry;
|
|
374
394
|
if (!geo) {
|
|
375
395
|
if (debugPhysics) console.warn("Missing mesh geometry", mesh.name);
|
|
@@ -575,6 +595,7 @@ export class Physics {
|
|
|
575
595
|
}
|
|
576
596
|
|
|
577
597
|
updateBody(comp: ICollider | IRigidbody, translation: boolean, rotation: boolean) {
|
|
598
|
+
if (!this.enabled) return;
|
|
578
599
|
if (comp.destroyed || !comp.gameObject) return;
|
|
579
600
|
if (!translation && !rotation) return;
|
|
580
601
|
|
|
@@ -637,6 +658,7 @@ export class Physics {
|
|
|
637
658
|
|
|
638
659
|
public step(dt?: number) {
|
|
639
660
|
if (!this.world) return;
|
|
661
|
+
if (!this.enabled) return;
|
|
640
662
|
this._isUpdatingPhysicsWorld = true;
|
|
641
663
|
if (!this.eventQueue) {
|
|
642
664
|
this.eventQueue = new EventQueue(false);
|
|
@@ -670,6 +692,7 @@ export class Physics {
|
|
|
670
692
|
|
|
671
693
|
public postStep() {
|
|
672
694
|
if (!this.world) return;
|
|
695
|
+
if (!this.enabled) return;
|
|
673
696
|
this._isUpdatingPhysicsWorld = true;
|
|
674
697
|
this.syncObjects();
|
|
675
698
|
this._isUpdatingPhysicsWorld = false;
|
|
@@ -206,6 +206,8 @@ declare type EventListCall = {
|
|
|
206
206
|
enabled?: boolean,
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
const $eventListDebugInfo = Symbol("eventListDebugInfo");
|
|
210
|
+
|
|
209
211
|
class EventListSerializer extends TypeSerializer {
|
|
210
212
|
constructor() {
|
|
211
213
|
super([EventList]);
|
|
@@ -238,13 +240,18 @@ class EventListSerializer extends TypeSerializer {
|
|
|
238
240
|
const hasMethod = call.method?.length > 0;
|
|
239
241
|
if (target && hasMethod) {
|
|
240
242
|
const printWarningMethodNotFound = () => console.warn(`Could not find method ${call.method} on object ${target.name}`, target, typeof target[call.method]);
|
|
241
|
-
|
|
243
|
+
const method = target[call.method];
|
|
244
|
+
if (typeof method !== "function") {
|
|
242
245
|
let foundMethod = false;
|
|
246
|
+
let currentPrototype = target;
|
|
243
247
|
// test if the target method is actually a property setter
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
+
while (currentPrototype) {
|
|
249
|
+
const desc = Object.getOwnPropertyDescriptor(currentPrototype, call.method);
|
|
250
|
+
if (desc && (desc.writable === true || desc.set)) {
|
|
251
|
+
foundMethod = true;
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
currentPrototype = Object.getPrototypeOf(currentPrototype);
|
|
248
255
|
}
|
|
249
256
|
if (!foundMethod && (isDevEnvironment() || debugExtension))
|
|
250
257
|
printWarningMethodNotFound();
|
|
@@ -252,38 +259,23 @@ class EventListSerializer extends TypeSerializer {
|
|
|
252
259
|
}
|
|
253
260
|
let fn: CallInfo | undefined;
|
|
254
261
|
let args = call.argument;
|
|
262
|
+
|
|
263
|
+
// This is the final method we pass to the call info (or undefined if the method couldnt be resolved)
|
|
264
|
+
const eventMethod = hasMethod ? this.createEventMethod(target, call.method, args) : undefined;
|
|
265
|
+
|
|
255
266
|
if (call.argument !== undefined) {
|
|
256
267
|
if (typeof args === "object") {
|
|
257
268
|
args = objectSerializer.onDeserialize(call.argument, context);
|
|
258
269
|
if (!args) args = componentSerializer.onDeserialize(call.argument, context);
|
|
259
270
|
}
|
|
260
|
-
fn = new CallInfo(
|
|
271
|
+
fn = new CallInfo(eventMethod, call.enabled);
|
|
261
272
|
}
|
|
262
273
|
else
|
|
263
|
-
fn = new CallInfo(
|
|
274
|
+
fn = new CallInfo(eventMethod, call.enabled);
|
|
264
275
|
|
|
265
276
|
|
|
266
|
-
// TODO: move this into the event list directly
|
|
267
|
-
// this scope should not stay in the serializer.
|
|
268
|
-
// the event list should be able to modify the args that were set in unity if necessary
|
|
269
|
-
// and pass them on to the component
|
|
270
|
-
const invokeFunction = (...forwardedArgs) => {
|
|
271
|
-
const method = target[call.method];
|
|
272
|
-
|
|
273
|
-
if (typeof method === "function") {
|
|
274
|
-
if (args !== undefined)
|
|
275
|
-
method?.call(target, args);
|
|
276
|
-
else // support invoking EventList with any number of arguments (if none were declared in unity)
|
|
277
|
-
method?.call(target, ...forwardedArgs);
|
|
278
|
-
}
|
|
279
|
-
else // the target "method" can be a property too
|
|
280
|
-
{
|
|
281
|
-
target[call.method] = args;
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
|
|
285
277
|
if (!fn.method)
|
|
286
|
-
fn[
|
|
278
|
+
fn[$eventListDebugInfo] = context.object?.name;
|
|
287
279
|
if (!target || !fn.method) {
|
|
288
280
|
const debugInfo = context.object ? "Current object: " + context.object.name + ", " + context.object["guid"] : null;
|
|
289
281
|
if (!target)
|
|
@@ -307,6 +299,23 @@ class EventListSerializer extends TypeSerializer {
|
|
|
307
299
|
}
|
|
308
300
|
return undefined;
|
|
309
301
|
}
|
|
302
|
+
|
|
303
|
+
private createEventMethod(target : object, methodName: string, args?: any) : Function | undefined {
|
|
304
|
+
|
|
305
|
+
return (...forwardedArgs) => {
|
|
306
|
+
const method = target[methodName];
|
|
307
|
+
if (typeof method === "function") {
|
|
308
|
+
if (args !== undefined)
|
|
309
|
+
method?.call(target, args);
|
|
310
|
+
else // support invoking EventList with any number of arguments (if none were declared in unity)
|
|
311
|
+
method?.call(target, ...forwardedArgs);
|
|
312
|
+
}
|
|
313
|
+
else // the target "method" can be a property too
|
|
314
|
+
{
|
|
315
|
+
target[methodName] = args;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|
|
310
319
|
}
|
|
311
320
|
export const eventListSerializer = new EventListSerializer();
|
|
312
321
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GLTF } from "three/examples/jsm/loaders/GLTFLoader";
|
|
2
2
|
import { getParam } from "./engine_utils";
|
|
3
|
-
import { Object3D } from "three";
|
|
3
|
+
import { AnimationClip, Material, Mesh, Object3D, Texture } from "three";
|
|
4
4
|
import { Context } from "./engine_setup";
|
|
5
5
|
import { isPersistentAsset } from "./extensions/NEEDLE_persistent_assets";
|
|
6
6
|
import { SourceIdentifier } from "./engine_types";
|
|
@@ -545,6 +545,13 @@ function deserializeObjectWithType(data: any, typeOrConstructor: Constructor<any
|
|
|
545
545
|
else {
|
|
546
546
|
// happens when exporting e.g. Animation component with only clip assigned (clips array is marked as serialized but it might be undefined if no clips are assigned in e.g. blender)
|
|
547
547
|
if (data === undefined) return undefined;
|
|
548
|
+
if (data === null) {
|
|
549
|
+
// Dont implictly create instances for three types that are not assigned
|
|
550
|
+
// see: https://github.com/needle-tools/needle-tiny/issues/637
|
|
551
|
+
if (type === Material || type === Texture || type === Mesh || type === AnimationClip) {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
548
555
|
// the fallback - this assumes that the type has a constructor that accepts the serialized arguments
|
|
549
556
|
// made originally with THREE.Vector3 in mind but SHOULD actually not be used/called anymore
|
|
550
557
|
instance = new type(...setBuffer(data));
|
|
@@ -233,7 +233,7 @@ export class Context implements IContext {
|
|
|
233
233
|
|
|
234
234
|
private _stats: Stats.default | null = stats ? Stats.default() : null;
|
|
235
235
|
|
|
236
|
-
constructor(args
|
|
236
|
+
constructor(args?: ContextArgs) {
|
|
237
237
|
this.name = args?.name || "";
|
|
238
238
|
this.alias = args?.alias;
|
|
239
239
|
this.domElement = args?.domElement || document.body;
|
|
@@ -3,7 +3,7 @@ import { getParam } from './engine_utils';
|
|
|
3
3
|
|
|
4
4
|
const timescaleUrl = getParam("timescale");
|
|
5
5
|
let timeScale = 1;
|
|
6
|
-
if(typeof timescaleUrl === "number") timeScale = timescaleUrl;
|
|
6
|
+
if (typeof timescaleUrl === "number") timeScale = timescaleUrl;
|
|
7
7
|
|
|
8
8
|
export class Time {
|
|
9
9
|
|
|
@@ -28,12 +28,17 @@ export class Time {
|
|
|
28
28
|
private _fpsSamples: number[] = [];
|
|
29
29
|
private _fpsSampleIndex: number = 0;
|
|
30
30
|
|
|
31
|
+
constructor() {
|
|
32
|
+
if (typeof timeScale === "number")
|
|
33
|
+
this.timeScale = timeScale;
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
update() {
|
|
32
37
|
this.deltaTime = this.clock.getDelta();
|
|
33
38
|
// clamp delta time because if tab is not active clock.getDelta can get pretty big
|
|
34
39
|
this.deltaTime = Math.min(.1, this.deltaTime);
|
|
35
|
-
this.deltaTime *=
|
|
36
|
-
if(this.deltaTime <= 0) this.deltaTime = 0.000000000001;
|
|
40
|
+
this.deltaTime *= this.timeScale;
|
|
41
|
+
if (this.deltaTime <= 0) this.deltaTime = 0.000000000001;
|
|
37
42
|
this.frame += 1;
|
|
38
43
|
this.time += this.deltaTime;
|
|
39
44
|
|
|
@@ -42,6 +47,6 @@ export class Time {
|
|
|
42
47
|
let sum = 0;
|
|
43
48
|
for (let i = 0; i < this._fpsSamples.length; i++)
|
|
44
49
|
sum += this._fpsSamples[i];
|
|
45
|
-
this._smoothedFps = 1/(sum / this._fpsSamples.length);
|
|
50
|
+
this._smoothedFps = 1 / (sum / this._fpsSamples.length);
|
|
46
51
|
}
|
|
47
52
|
}
|