@needle-tools/engine 5.1.0-alpha.3 → 5.1.0-alpha.5
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 +68 -0
- package/SKILL.md +4 -1
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-DF01sSGQ.js → needle-engine.bundle-C-LG00ZZ.js} +10681 -10100
- package/dist/needle-engine.bundle-D7tzaiYE.min.js +1733 -0
- package/dist/{needle-engine.bundle-C-ixARur.umd.cjs → needle-engine.bundle-OPkPmdUM.umd.cjs} +161 -161
- package/dist/needle-engine.d.ts +1349 -317
- package/dist/needle-engine.js +556 -555
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/three.js +1 -0
- package/dist/three.min.js +21 -21
- package/dist/three.umd.cjs +16 -16
- package/lib/engine/api.d.ts +5 -0
- package/lib/engine/api.js +4 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/codegen/register_types.js +10 -18
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_camera.fit.js +16 -4
- package/lib/engine/engine_camera.fit.js.map +1 -1
- package/lib/engine/engine_context.d.ts +20 -7
- package/lib/engine/engine_context.js +31 -15
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_context_eventbus.d.ts +47 -0
- package/lib/engine/engine_context_eventbus.js +47 -0
- package/lib/engine/engine_context_eventbus.js.map +1 -0
- package/lib/engine/engine_disposable.d.ts +172 -0
- package/lib/engine/engine_disposable.js +136 -0
- package/lib/engine/engine_disposable.js.map +1 -0
- package/lib/engine/engine_gameobject.d.ts +1 -10
- package/lib/engine/engine_gameobject.js +20 -118
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_gltf_builtin_components.js +7 -69
- package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
- package/lib/engine/engine_input.d.ts +23 -4
- package/lib/engine/engine_input.js +2 -1
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_instantiate_resolve.d.ts +42 -0
- package/lib/engine/engine_instantiate_resolve.js +372 -0
- package/lib/engine/engine_instantiate_resolve.js.map +1 -0
- package/lib/engine/engine_mainloop_utils.js +2 -2
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_networking.d.ts +51 -37
- package/lib/engine/engine_networking.js +132 -82
- package/lib/engine/engine_networking.js.map +1 -1
- package/lib/engine/engine_networking.transport.websocket.d.ts +15 -0
- package/lib/engine/engine_networking.transport.websocket.js +38 -0
- package/lib/engine/engine_networking.transport.websocket.js.map +1 -0
- package/lib/engine/engine_networking_instantiate.js +2 -2
- package/lib/engine/engine_networking_instantiate.js.map +1 -1
- package/lib/engine/engine_networking_types.d.ts +39 -1
- package/lib/engine/engine_networking_types.js +7 -0
- package/lib/engine/engine_networking_types.js.map +1 -1
- package/lib/engine/engine_physics_rapier.d.ts +21 -3
- package/lib/engine/engine_physics_rapier.js +94 -25
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js +1 -5
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/engine_serialization_core.d.ts +1 -0
- package/lib/engine/engine_serialization_core.js +7 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_types.d.ts +29 -11
- package/lib/engine/engine_types.js +1 -1
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/engine_util_decorator.js +7 -2
- package/lib/engine/engine_util_decorator.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -1
- package/lib/engine/engine_utils.js +19 -5
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine-components/AnimationBuilder.d.ts +158 -0
- package/lib/engine-components/AnimationBuilder.js +305 -0
- package/lib/engine-components/AnimationBuilder.js.map +1 -0
- package/lib/engine-components/Animator.d.ts +6 -0
- package/lib/engine-components/Animator.js +23 -13
- package/lib/engine-components/Animator.js.map +1 -1
- package/lib/engine-components/AnimatorController.builder.d.ts +191 -0
- package/lib/engine-components/AnimatorController.builder.js +263 -0
- package/lib/engine-components/AnimatorController.builder.js.map +1 -0
- package/lib/engine-components/AnimatorController.d.ts +2 -119
- package/lib/engine-components/AnimatorController.js +33 -232
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +18 -9
- package/lib/engine-components/Collider.js +61 -14
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Component.d.ts +72 -9
- package/lib/engine-components/Component.js +114 -10
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +1 -0
- package/lib/engine-components/ContactShadows.js +14 -1
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DragControls.js +0 -7
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/DropListener.js +3 -0
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/EventList.d.ts +31 -9
- package/lib/engine-components/EventList.js +37 -76
- package/lib/engine-components/EventList.js.map +1 -1
- package/lib/engine-components/Joints.d.ts +4 -2
- package/lib/engine-components/Joints.js +19 -3
- package/lib/engine-components/Joints.js.map +1 -1
- package/lib/engine-components/Light.js +9 -1
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +0 -2
- package/lib/engine-components/OrbitControls.js +14 -1
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +12 -4
- package/lib/engine-components/RigidBody.js +18 -4
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.js +3 -0
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/api.d.ts +2 -1
- package/lib/engine-components/api.js +2 -1
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +7 -13
- package/lib/engine-components/codegen/components.js +7 -13
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +21 -11
- package/lib/engine-components/timeline/PlayableDirector.js +75 -67
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/SignalAsset.d.ts +3 -1
- package/lib/engine-components/timeline/SignalAsset.js +1 -0
- package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
- package/lib/engine-components/timeline/TimelineBuilder.d.ts +413 -0
- package/lib/engine-components/timeline/TimelineBuilder.js +506 -0
- package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -0
- package/lib/engine-components/timeline/TimelineModels.d.ts +2 -1
- package/lib/engine-components/timeline/TimelineModels.js +3 -0
- package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +37 -6
- package/lib/engine-components/timeline/TimelineTracks.js +92 -26
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/timeline/index.d.ts +2 -1
- package/lib/engine-components/timeline/index.js +2 -0
- package/lib/engine-components/timeline/index.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.d.ts +0 -1
- package/lib/engine-components/web/CursorFollow.js +0 -1
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/package.json +2 -83
- package/plugins/common/cloud.js +6 -1
- package/plugins/common/license.js +5 -2
- package/plugins/common/worker.js +9 -4
- package/plugins/vite/dependencies.js +1 -11
- package/plugins/vite/dependency-watcher.js +2 -2
- package/plugins/vite/editor-connection.js +3 -3
- package/plugins/vite/license.js +19 -1
- package/plugins/vite/reload.js +1 -1
- package/plugins/vite/server.js +2 -1
- package/src/engine/api.ts +7 -0
- package/src/engine/codegen/register_types.ts +10 -18
- package/src/engine/engine_camera.fit.ts +15 -4
- package/src/engine/engine_context.ts +32 -16
- package/src/engine/engine_context_eventbus.ts +73 -0
- package/src/engine/engine_disposable.ts +214 -0
- package/src/engine/engine_gameobject.ts +52 -157
- package/src/engine/engine_gltf_builtin_components.ts +7 -76
- package/src/engine/engine_input.ts +27 -6
- package/src/engine/engine_instantiate_resolve.ts +407 -0
- package/src/engine/engine_mainloop_utils.ts +2 -2
- package/src/engine/engine_networking.transport.websocket.ts +45 -0
- package/src/engine/engine_networking.ts +161 -137
- package/src/engine/engine_networking_instantiate.ts +2 -2
- package/src/engine/engine_networking_types.ts +41 -1
- package/src/engine/engine_physics_rapier.ts +102 -33
- package/src/engine/engine_serialization_builtin_serializer.ts +1 -6
- package/src/engine/engine_serialization_core.ts +9 -0
- package/src/engine/engine_types.ts +46 -27
- package/src/engine/engine_util_decorator.ts +7 -2
- package/src/engine/engine_utils.ts +16 -5
- package/src/engine-components/AnimationBuilder.ts +472 -0
- package/src/engine-components/Animator.ts +24 -12
- package/src/engine-components/AnimatorController.builder.ts +387 -0
- package/src/engine-components/AnimatorController.ts +20 -291
- package/src/engine-components/Collider.ts +66 -18
- package/src/engine-components/Component.ts +118 -20
- package/src/engine-components/ContactShadows.ts +15 -1
- package/src/engine-components/DragControls.ts +0 -9
- package/src/engine-components/DropListener.ts +3 -0
- package/src/engine-components/EventList.ts +45 -83
- package/src/engine-components/Joints.ts +20 -4
- package/src/engine-components/Light.ts +10 -2
- package/src/engine-components/OrbitControls.ts +16 -5
- package/src/engine-components/RigidBody.ts +18 -4
- package/src/engine-components/SceneSwitcher.ts +3 -0
- package/src/engine-components/api.ts +2 -1
- package/src/engine-components/codegen/components.ts +7 -13
- package/src/engine-components/timeline/PlayableDirector.ts +83 -81
- package/src/engine-components/timeline/SignalAsset.ts +4 -1
- package/src/engine-components/timeline/TimelineBuilder.ts +824 -0
- package/src/engine-components/timeline/TimelineModels.ts +5 -1
- package/src/engine-components/timeline/TimelineTracks.ts +96 -27
- package/src/engine-components/timeline/index.ts +2 -1
- package/src/engine-components/web/CursorFollow.ts +0 -1
- package/dist/needle-engine.bundle-CHmXdnE1.min.js +0 -1733
- package/lib/engine-components/AvatarLoader.d.ts +0 -80
- package/lib/engine-components/AvatarLoader.js +0 -232
- package/lib/engine-components/AvatarLoader.js.map +0 -1
- package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +0 -11
- package/lib/engine-components/avatar/AvatarBlink_Simple.js +0 -77
- package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +0 -1
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +0 -14
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +0 -69
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +0 -29
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +0 -122
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +0 -15
- package/lib/engine-components/avatar/Avatar_MouthShapes.js +0 -80
- package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +0 -9
- package/lib/engine-components/avatar/Avatar_MustacheShake.js +0 -30
- package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +0 -1
- package/src/engine-components/AvatarLoader.ts +0 -264
- package/src/engine-components/avatar/AvatarBlink_Simple.ts +0 -70
- package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +0 -64
- package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +0 -140
- package/src/engine-components/avatar/Avatar_MouthShapes.ts +0 -84
- package/src/engine-components/avatar/Avatar_MustacheShake.ts +0 -32
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Ball, Collider, ColliderDesc, Cuboid, EventQueue, QueryFilterFlags, Ray, RigidBody, RigidBodyDesc, World } from '@dimforge/rapier3d-compat';
|
|
1
|
+
import type { Ball, Collider, ColliderDesc, Cuboid, EventQueue, ImpulseJoint, QueryFilterFlags, Ray, RigidBody, RigidBodyDesc, World } from '@dimforge/rapier3d-compat';
|
|
2
2
|
import { BufferAttribute, BufferGeometry, InterleavedBufferAttribute, LineBasicMaterial, LineSegments, Matrix4, Mesh, Object3D, Quaternion, Vector3, Vector4Like } from 'three'
|
|
3
3
|
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
|
|
4
4
|
|
|
@@ -402,11 +402,16 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
402
402
|
filterGroups?: number,
|
|
403
403
|
/** Return false to ignore this collider */
|
|
404
404
|
filterPredicate?: (c: ICollider) => boolean,
|
|
405
|
-
/** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
|
|
405
|
+
/** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
|
|
406
406
|
* If not set the raycast will ignore objects in the IgnoreRaycast layer (default: true)
|
|
407
|
-
* @default undefined
|
|
407
|
+
* @default undefined
|
|
408
408
|
*/
|
|
409
|
-
useIgnoreRaycastLayer?: boolean
|
|
409
|
+
useIgnoreRaycastLayer?: boolean,
|
|
410
|
+
/** When true, trigger/sensor colliders will be included in the raycast results.
|
|
411
|
+
* By default trigger colliders are skipped.
|
|
412
|
+
* @default false
|
|
413
|
+
*/
|
|
414
|
+
includeTriggers?: boolean,
|
|
410
415
|
})
|
|
411
416
|
: null | { point: Vector3, collider: ICollider } {
|
|
412
417
|
|
|
@@ -428,6 +433,8 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
428
433
|
|
|
429
434
|
const hit = this.world?.castRay(ray, maxDistance, solid, options?.queryFilterFlags, options?.filterGroups, undefined, undefined, (c) => {
|
|
430
435
|
const component = c[$componentKey];
|
|
436
|
+
// Skip trigger/sensor colliders unless explicitly included
|
|
437
|
+
if (options?.includeTriggers !== true && component?.isTrigger) return false;
|
|
431
438
|
if (options?.filterPredicate) return options.filterPredicate(component);
|
|
432
439
|
if (options?.useIgnoreRaycastLayer !== false) {
|
|
433
440
|
// ignore objects in the IgnoreRaycast=2 layer
|
|
@@ -453,11 +460,16 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
453
460
|
filterGroups?: number,
|
|
454
461
|
/** Return false to ignore this collider */
|
|
455
462
|
filterPredicate?: (c: ICollider) => boolean,
|
|
456
|
-
/** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
|
|
463
|
+
/** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
|
|
457
464
|
* If not set the raycast will ignore objects in the IgnoreRaycast layer (default: true)
|
|
458
|
-
* @default undefined
|
|
465
|
+
* @default undefined
|
|
459
466
|
*/
|
|
460
|
-
useIgnoreRaycastLayer?: boolean
|
|
467
|
+
useIgnoreRaycastLayer?: boolean,
|
|
468
|
+
/** When true, trigger/sensor colliders will be included in the raycast results.
|
|
469
|
+
* By default trigger colliders are skipped.
|
|
470
|
+
* @default false
|
|
471
|
+
*/
|
|
472
|
+
includeTriggers?: boolean,
|
|
461
473
|
})
|
|
462
474
|
: null | { point: Vector3, normal: Vector3, collider: ICollider } {
|
|
463
475
|
|
|
@@ -478,6 +490,8 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
478
490
|
|
|
479
491
|
const hit = this.world?.castRayAndGetNormal(ray, maxDistance, solid, options?.queryFilterFlags, options?.filterGroups, undefined, undefined, (c) => {
|
|
480
492
|
const component = c[$componentKey];
|
|
493
|
+
// Skip trigger/sensor colliders unless explicitly included
|
|
494
|
+
if (options?.includeTriggers !== true && component?.isTrigger) return false;
|
|
481
495
|
if (options?.filterPredicate) return options.filterPredicate(component);
|
|
482
496
|
if (options?.useIgnoreRaycastLayer !== false) {
|
|
483
497
|
// ignore objects in the IgnoreRaycast=2 layer
|
|
@@ -690,12 +704,26 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
690
704
|
}
|
|
691
705
|
}
|
|
692
706
|
|
|
693
|
-
|
|
707
|
+
/** Tears down the physics world and frees all WASM resources.
|
|
708
|
+
* After calling this, the world will be re-created on next use. */
|
|
709
|
+
dispose() {
|
|
694
710
|
this._meshCache.clear();
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
711
|
+
this.eventQueue?.free();
|
|
712
|
+
this._world?.free();
|
|
713
|
+
// Reset initialization state so the world can be recreated
|
|
714
|
+
this._world = undefined;
|
|
715
|
+
this.eventQueue = undefined;
|
|
716
|
+
this.collisionHandler = undefined;
|
|
717
|
+
this._isInitialized = false;
|
|
718
|
+
this._hasCreatedWorld = false;
|
|
719
|
+
this._initializePromise = undefined;
|
|
720
|
+
this.objects.length = 0;
|
|
721
|
+
this.bodies.length = 0;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/** @deprecated Use {@link dispose} instead. */
|
|
725
|
+
clearCaches() {
|
|
726
|
+
this.dispose();
|
|
699
727
|
}
|
|
700
728
|
|
|
701
729
|
async addBoxCollider(collider: ICollider, size: Vector3) {
|
|
@@ -981,13 +1009,17 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
981
1009
|
}
|
|
982
1010
|
}
|
|
983
1011
|
|
|
984
|
-
//
|
|
985
|
-
//
|
|
1012
|
+
// When using explicit mass (autoMass=false), set collider mass to near-zero
|
|
1013
|
+
// so Rapier doesn't contribute mass from the collider shape.
|
|
1014
|
+
// The actual mass is applied via setAdditionalMass on the rigidbody instead.
|
|
1015
|
+
// Note: setMass overrides any prior setDensity call (they are mutually exclusive in Rapier)
|
|
986
1016
|
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
|
|
987
1017
|
if (collider.attachedRigidbody?.autoMass === false) {
|
|
988
|
-
desc.setDensity(.000001);
|
|
989
1018
|
desc.setMass(.000001);
|
|
990
1019
|
}
|
|
1020
|
+
else if (collider.density != null) {
|
|
1021
|
+
desc.setDensity(collider.density);
|
|
1022
|
+
}
|
|
991
1023
|
|
|
992
1024
|
try {
|
|
993
1025
|
const col = this.world.createCollider(desc, rigidBody);
|
|
@@ -1130,6 +1162,11 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
1130
1162
|
break;
|
|
1131
1163
|
}
|
|
1132
1164
|
|
|
1165
|
+
// Update density if specified (setDensity auto-recomputes parent body mass)
|
|
1166
|
+
if (col.density != null) {
|
|
1167
|
+
collider.setDensity(col.density);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1133
1170
|
if (sizeHasChanged) {
|
|
1134
1171
|
const rb = col.attachedRigidbody;
|
|
1135
1172
|
if (rb?.autoMass) {
|
|
@@ -1161,7 +1198,8 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
1161
1198
|
rigidbody.setAdditionalMass(0, false);
|
|
1162
1199
|
for (let i = 0; i < rigidbody.numColliders(); i++) {
|
|
1163
1200
|
const col = rigidbody.collider(i);
|
|
1164
|
-
col
|
|
1201
|
+
const colliderComponent = col[$componentKey] as ICollider | null;
|
|
1202
|
+
col.setDensity(colliderComponent?.density ?? 1);
|
|
1165
1203
|
}
|
|
1166
1204
|
rigidbody.recomputeMassPropertiesFromColliders();
|
|
1167
1205
|
}
|
|
@@ -1477,16 +1515,21 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
1477
1515
|
|
|
1478
1516
|
private static centerConnectionPos = { x: 0, y: 0, z: 0 };
|
|
1479
1517
|
private static centerConnectionRot = { x: 0, y: 0, z: 0, w: 1 };
|
|
1518
|
+
private _jointTempMatrix = new Matrix4();
|
|
1480
1519
|
|
|
1481
1520
|
|
|
1482
|
-
|
|
1483
|
-
|
|
1521
|
+
async addFixedJoint(body1: IRigidbody, body2: IRigidbody): Promise<ImpulseJoint | null> {
|
|
1522
|
+
if (!this._isInitialized) await this.initialize();
|
|
1484
1523
|
if (!this.world) {
|
|
1485
1524
|
console.error("Physics world not initialized");
|
|
1486
|
-
return;
|
|
1525
|
+
return null;
|
|
1487
1526
|
}
|
|
1488
1527
|
const b1 = body1[$bodyKey] as RigidBody;
|
|
1489
1528
|
const b2 = body2[$bodyKey] as RigidBody;
|
|
1529
|
+
if (!b1 || !b2) {
|
|
1530
|
+
console.error("Cannot create fixed joint: one or both physics bodies are not initialized");
|
|
1531
|
+
return null;
|
|
1532
|
+
}
|
|
1490
1533
|
|
|
1491
1534
|
this.calculateJointRelativeMatrices(body1.gameObject, body2.gameObject, this._tempMatrix);
|
|
1492
1535
|
this._tempMatrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
|
|
@@ -1498,41 +1541,67 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
1498
1541
|
const joint = this.world.createImpulseJoint(params, b1, b2, true);
|
|
1499
1542
|
if (debugPhysics)
|
|
1500
1543
|
console.log("ADD FIXED JOINT", joint)
|
|
1544
|
+
return joint;
|
|
1501
1545
|
}
|
|
1502
1546
|
|
|
1503
1547
|
|
|
1504
1548
|
/** The joint prevents any relative movement between two rigid-bodies, except for relative rotations along one axis. This is typically used to simulate wheels, fans, etc. They are characterized by one local anchor as well as one local axis on each rigid-body. */
|
|
1505
|
-
addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: { x: number, y: number, z: number }, axis: { x: number, y: number, z: number }) {
|
|
1549
|
+
async addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: { x: number, y: number, z: number }, axis: { x: number, y: number, z: number }): Promise<ImpulseJoint | null> {
|
|
1550
|
+
if (!this._isInitialized) await this.initialize();
|
|
1506
1551
|
if (!this.world) {
|
|
1507
1552
|
console.error("Physics world not initialized");
|
|
1508
|
-
return;
|
|
1553
|
+
return null;
|
|
1509
1554
|
}
|
|
1510
1555
|
const b1 = body1[$bodyKey] as RigidBody;
|
|
1511
1556
|
const b2 = body2[$bodyKey] as RigidBody;
|
|
1557
|
+
if (!b1 || !b2) {
|
|
1558
|
+
console.error("Cannot create hinge joint: one or both physics bodies are not initialized");
|
|
1559
|
+
return null;
|
|
1560
|
+
}
|
|
1512
1561
|
|
|
1513
1562
|
this.calculateJointRelativeMatrices(body1.gameObject, body2.gameObject, this._tempMatrix);
|
|
1514
|
-
|
|
1563
|
+
// Transform anchor from body1's local space to body2's local space
|
|
1564
|
+
const anchor2 = this._tempPosition.set(anchor.x, anchor.y, anchor.z).applyMatrix4(this._tempMatrix);
|
|
1515
1565
|
|
|
1516
|
-
const params = MODULES.RAPIER_PHYSICS.MODULE.JointData.revolute(anchor,
|
|
1566
|
+
const params = MODULES.RAPIER_PHYSICS.MODULE.JointData.revolute(anchor, anchor2, axis);
|
|
1517
1567
|
const joint = this.world.createImpulseJoint(params, b1, b2, true);
|
|
1518
1568
|
if (debugPhysics)
|
|
1519
1569
|
console.log("ADD HINGE JOINT", joint)
|
|
1570
|
+
return joint;
|
|
1520
1571
|
}
|
|
1521
1572
|
|
|
1522
1573
|
|
|
1574
|
+
removeJoint(joint: ImpulseJoint) {
|
|
1575
|
+
if (!this.world) return;
|
|
1576
|
+
this.world.removeImpulseJoint(joint, true);
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
|
|
1580
|
+
/** Compute the relative transform from body1's local space to body2's local space (W2⁻¹ * W1), ignoring scale. */
|
|
1523
1581
|
private calculateJointRelativeMatrices(body1: IGameObject, body2: IGameObject, mat: Matrix4) {
|
|
1524
1582
|
body1.updateWorldMatrix(true, false);
|
|
1525
1583
|
body2.updateWorldMatrix(true, false);
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
mat
|
|
1584
|
+
|
|
1585
|
+
// Work on copies to avoid mutating the actual world matrices
|
|
1586
|
+
mat.copy(body1.matrixWorld);
|
|
1587
|
+
const w2 = this._jointTempMatrix.copy(body2.matrixWorld);
|
|
1588
|
+
|
|
1589
|
+
// Strip scale by normalizing each column of the upper 3x3
|
|
1590
|
+
this.normalizeMatrixColumns(mat);
|
|
1591
|
+
this.normalizeMatrixColumns(w2);
|
|
1592
|
+
|
|
1593
|
+
// mat = W2^-1 * W1 (body1's frame in body2's local space)
|
|
1594
|
+
mat.premultiply(w2.invert());
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
private normalizeMatrixColumns(m: Matrix4) {
|
|
1598
|
+
const e = m.elements;
|
|
1599
|
+
let len = Math.sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);
|
|
1600
|
+
if (len > 0) { e[0] /= len; e[1] /= len; e[2] /= len; }
|
|
1601
|
+
len = Math.sqrt(e[4] * e[4] + e[5] * e[5] + e[6] * e[6]);
|
|
1602
|
+
if (len > 0) { e[4] /= len; e[5] /= len; e[6] /= len; }
|
|
1603
|
+
len = Math.sqrt(e[8] * e[8] + e[9] * e[9] + e[10] * e[10]);
|
|
1604
|
+
if (len > 0) { e[8] /= len; e[9] /= len; e[10] /= len; }
|
|
1536
1605
|
}
|
|
1537
1606
|
}
|
|
1538
1607
|
|
|
@@ -124,7 +124,7 @@ class ObjectSerializer extends TypeSerializer {
|
|
|
124
124
|
}
|
|
125
125
|
if (!res) {
|
|
126
126
|
if (isDevEnvironment() || debugExtension)
|
|
127
|
-
console.warn(
|
|
127
|
+
console.warn(`Could not resolve object reference \"${context.path}\" (guid: ${data.guid}). The referenced object may have been deleted — check if the reference is still valid in your scene.`);
|
|
128
128
|
data["could_not_resolve"] = true;
|
|
129
129
|
}
|
|
130
130
|
else {
|
|
@@ -334,11 +334,6 @@ class EventListSerializer extends TypeSerializer {
|
|
|
334
334
|
if (debugExtension)
|
|
335
335
|
console.log(evt);
|
|
336
336
|
|
|
337
|
-
const eventListOwner = context.target;
|
|
338
|
-
if (eventListOwner !== undefined && context.path !== undefined) {
|
|
339
|
-
evt.setEventTarget(context.path, eventListOwner);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
337
|
return evt;
|
|
343
338
|
}
|
|
344
339
|
return undefined;
|
|
@@ -207,6 +207,15 @@ export interface ISerializable {
|
|
|
207
207
|
onAfterDeserialize?(data: any, context: SerializationContext): void;
|
|
208
208
|
};
|
|
209
209
|
|
|
210
|
+
export function isSerializable(obj: any): obj is ISerializable {
|
|
211
|
+
return obj && typeof obj === "object" && (
|
|
212
|
+
typeof obj.$serializedTypes === "object" ||
|
|
213
|
+
typeof obj.onBeforeDeserialize === "function" ||
|
|
214
|
+
typeof obj.onBeforeDeserializeMember === "function" ||
|
|
215
|
+
typeof obj.onAfterDeserializeMember === "function" ||
|
|
216
|
+
typeof obj.onAfterDeserialize === "function"
|
|
217
|
+
)
|
|
218
|
+
}
|
|
210
219
|
|
|
211
220
|
export function serializeObject(obj: ISerializable, context: SerializationContext): object | null {
|
|
212
221
|
const types = obj.$serializedTypes;
|
|
@@ -5,7 +5,6 @@ import { type GLTF as THREE_GLTF } from "three/examples/jsm/loaders/GLTFLoader.j
|
|
|
5
5
|
|
|
6
6
|
import type { Camera as CameraComponent } from "../engine-components/api.js";
|
|
7
7
|
import type { Context } from "./engine_context.js";
|
|
8
|
-
import { InstantiateContext } from "./engine_gameobject.js";
|
|
9
8
|
import { CollisionDetectionMode, type PhysicsMaterial, RigidbodyConstraints } from "./engine_physics.types.js";
|
|
10
9
|
import { CircularBuffer } from "./engine_utils.js";
|
|
11
10
|
import type { NeedleXRSession } from "./engine_xr.js";
|
|
@@ -196,13 +195,11 @@ export interface IComponent extends IHasGuid {
|
|
|
196
195
|
/** @internal */
|
|
197
196
|
__internalStart();
|
|
198
197
|
/** @internal */
|
|
199
|
-
__internalEnable(
|
|
198
|
+
__internalEnable(isHierarchyChange?: boolean);
|
|
200
199
|
/** @internal */
|
|
201
|
-
__internalDisable(
|
|
200
|
+
__internalDisable(isHierarchyChange?: boolean);
|
|
202
201
|
/** @internal */
|
|
203
202
|
__internalDestroy();
|
|
204
|
-
/** @internal */
|
|
205
|
-
resolveGuids?(guidsMap: GuidsMap): void;
|
|
206
203
|
|
|
207
204
|
/** experimental, called when the script is registered for the first time, this is called even if the component is not enabled. */
|
|
208
205
|
registering?();
|
|
@@ -240,14 +237,14 @@ export interface IComponent extends IHasGuid {
|
|
|
240
237
|
}
|
|
241
238
|
|
|
242
239
|
export function isComponent(obj: any): obj is IComponent {
|
|
243
|
-
return obj && obj.isComponent;
|
|
240
|
+
return obj && typeof obj === "object" && obj.isComponent;
|
|
244
241
|
}
|
|
245
242
|
|
|
246
243
|
export type ICamera = CameraComponent;
|
|
247
244
|
|
|
248
245
|
export type IAnimationComponent = Pick<IComponent, "gameObject"> & {
|
|
249
246
|
isAnimationComponent: boolean;
|
|
250
|
-
addClip?(clip: AnimationClip);
|
|
247
|
+
addClip?(clip: AnimationClip): void;
|
|
251
248
|
}
|
|
252
249
|
|
|
253
250
|
/** Interface for a camera controller component that can be attached to a camera to control it */
|
|
@@ -274,7 +271,10 @@ export declare interface IRenderer extends IComponent {
|
|
|
274
271
|
|
|
275
272
|
export declare interface IEventList {
|
|
276
273
|
readonly isEventList: true;
|
|
277
|
-
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export declare interface ISignalReceiver {
|
|
277
|
+
readonly isSignalReceiver: true;
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
// export declare interface IPhysicsComponent extends IComponent {
|
|
@@ -302,12 +302,18 @@ export declare interface ICollider extends IComponent {
|
|
|
302
302
|
* Default: [0]
|
|
303
303
|
*/
|
|
304
304
|
membership?: number[];
|
|
305
|
-
/** The collider filter indicates what groups the collider can interact with (e.g. group 3 and 4)
|
|
306
|
-
* An `undefined` array indicates that the collider can interact with all groups
|
|
307
|
-
* Note: Make sure to call updateProperties after having changed this property
|
|
305
|
+
/** The collider filter indicates what groups the collider can interact with (e.g. group 3 and 4)
|
|
306
|
+
* An `undefined` array indicates that the collider can interact with all groups
|
|
307
|
+
* Note: Make sure to call updateProperties after having changed this property
|
|
308
308
|
* Default: undefined
|
|
309
309
|
*/
|
|
310
310
|
filter?: number[];
|
|
311
|
+
/** The density of the collider used for automatic mass calculation.
|
|
312
|
+
* When the attached Rigidbody has `autoMass` enabled, the mass is computed as `density × volume`.
|
|
313
|
+
* Note: Make sure to call updateProperties after having changed this property
|
|
314
|
+
* Default: undefined (uses physics engine default of 1.0)
|
|
315
|
+
*/
|
|
316
|
+
density?: number;
|
|
311
317
|
}
|
|
312
318
|
|
|
313
319
|
export declare interface ISphereCollider extends ICollider {
|
|
@@ -475,8 +481,10 @@ export interface IPhysicsEngine {
|
|
|
475
481
|
postStep();
|
|
476
482
|
/** Indicates whether the physics engine is currently updating */
|
|
477
483
|
get isUpdating(): boolean;
|
|
478
|
-
/**
|
|
479
|
-
|
|
484
|
+
/** Tears down the physics world and frees all resources. The world will be re-created on next use. */
|
|
485
|
+
dispose(): void;
|
|
486
|
+
/** @deprecated Use {@link dispose} instead. */
|
|
487
|
+
clearCaches(): void;
|
|
480
488
|
|
|
481
489
|
/** Enables or disables the physics engine */
|
|
482
490
|
enabled: boolean;
|
|
@@ -513,20 +521,25 @@ export interface IPhysicsEngine {
|
|
|
513
521
|
/** True if you want to also hit objects when the raycast starts from inside a collider */
|
|
514
522
|
solid?: boolean,
|
|
515
523
|
queryFilterFlags?: QueryFilterFlags,
|
|
516
|
-
/**
|
|
517
|
-
* Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
|
|
518
|
-
* The scene query will only consider hits with colliders with collision groups compatible with
|
|
524
|
+
/**
|
|
525
|
+
* Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
|
|
526
|
+
* The scene query will only consider hits with colliders with collision groups compatible with
|
|
519
527
|
* this collision group (using the bitwise test described in the collision groups section).
|
|
520
|
-
* For example membership 0x0001 and filter 0x0002 should be 0x00010002
|
|
528
|
+
* For example membership 0x0001 and filter 0x0002 should be 0x00010002
|
|
521
529
|
* @see https://rapier.rs/docs/user_guides/javascript/colliders#collision-groups-and-solver-groups
|
|
522
530
|
*/
|
|
523
531
|
filterGroups?: number,
|
|
524
|
-
/**
|
|
532
|
+
/**
|
|
525
533
|
* Predicate to filter colliders in raycast results
|
|
526
534
|
* @param collider The collider being tested
|
|
527
535
|
* @returns False to ignore this collider, true to include it
|
|
528
536
|
*/
|
|
529
|
-
filterPredicate?: (collider: ICollider) => boolean
|
|
537
|
+
filterPredicate?: (collider: ICollider) => boolean,
|
|
538
|
+
/** When true, trigger/sensor colliders will be included in the raycast results.
|
|
539
|
+
* By default trigger colliders are skipped.
|
|
540
|
+
* @default false
|
|
541
|
+
*/
|
|
542
|
+
includeTriggers?: boolean,
|
|
530
543
|
}): RaycastResult;
|
|
531
544
|
|
|
532
545
|
/**
|
|
@@ -541,20 +554,25 @@ export interface IPhysicsEngine {
|
|
|
541
554
|
/** True if you want to also hit objects when the raycast starts from inside a collider */
|
|
542
555
|
solid?: boolean,
|
|
543
556
|
queryFilterFlags?: QueryFilterFlags,
|
|
544
|
-
/**
|
|
545
|
-
* Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
|
|
546
|
-
* The scene query will only consider hits with colliders with collision groups compatible with
|
|
557
|
+
/**
|
|
558
|
+
* Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
|
|
559
|
+
* The scene query will only consider hits with colliders with collision groups compatible with
|
|
547
560
|
* this collision group (using the bitwise test described in the collision groups section).
|
|
548
|
-
* For example membership 0x0001 and filter 0x0002 should be 0x00010002
|
|
561
|
+
* For example membership 0x0001 and filter 0x0002 should be 0x00010002
|
|
549
562
|
* @see https://rapier.rs/docs/user_guides/javascript/colliders#collision-groups-and-solver-groups
|
|
550
563
|
*/
|
|
551
564
|
filterGroups?: number,
|
|
552
|
-
/**
|
|
565
|
+
/**
|
|
553
566
|
* Predicate to filter colliders in raycast results
|
|
554
567
|
* @param collider The collider being tested
|
|
555
568
|
* @returns False to ignore this collider, true to include it
|
|
556
569
|
*/
|
|
557
|
-
filterPredicate?: (collider: ICollider) => boolean
|
|
570
|
+
filterPredicate?: (collider: ICollider) => boolean,
|
|
571
|
+
/** When true, trigger/sensor colliders will be included in the raycast results.
|
|
572
|
+
* By default trigger colliders are skipped.
|
|
573
|
+
* @default false
|
|
574
|
+
*/
|
|
575
|
+
includeTriggers?: boolean,
|
|
558
576
|
}): RaycastResult;
|
|
559
577
|
|
|
560
578
|
/**
|
|
@@ -738,8 +756,9 @@ export interface IPhysicsEngine {
|
|
|
738
756
|
getBody(obj: ICollider | IRigidbody): null | any;
|
|
739
757
|
|
|
740
758
|
// Joints
|
|
741
|
-
addFixedJoint(body1: IRigidbody, body2: IRigidbody);
|
|
742
|
-
addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: Vec3, axis: Vec3);
|
|
759
|
+
addFixedJoint(body1: IRigidbody, body2: IRigidbody): Promise<any> | any;
|
|
760
|
+
addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: Vec3, axis: Vec3): Promise<any> | any;
|
|
761
|
+
removeJoint(joint: any): void;
|
|
743
762
|
|
|
744
763
|
/** Enable to render collider shapes */
|
|
745
764
|
debugRenderColliders: boolean;
|
|
@@ -79,8 +79,12 @@ function createPropertyWrapper(target: IComponent | any, _propertyKey: string |
|
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
//
|
|
83
|
-
|
|
82
|
+
// Only install the getter/setter once per instance.
|
|
83
|
+
// processStart may call __internalAwake again for components that were inactive
|
|
84
|
+
// during processNewScripts — the base Component.__internalAwake has a __didAwake guard
|
|
85
|
+
// but this decorator wrapper runs before reaching it, so we need our own idempotency check.
|
|
86
|
+
const desc = Object.getOwnPropertyDescriptor(this, propertyKey);
|
|
87
|
+
if (!desc || !desc.get) {
|
|
84
88
|
|
|
85
89
|
// make sure the field is initialized in a hidden property
|
|
86
90
|
this[$prop] = this[propertyKey];
|
|
@@ -99,6 +103,7 @@ function createPropertyWrapper(target: IComponent | any, _propertyKey: string |
|
|
|
99
103
|
}
|
|
100
104
|
|
|
101
105
|
Object.defineProperty(this, propertyKey, {
|
|
106
|
+
configurable: true,
|
|
102
107
|
set: function (v) {
|
|
103
108
|
if (this[$isAssigningProperties] === true) {
|
|
104
109
|
this[$prop] = v;
|
|
@@ -279,24 +279,35 @@ declare type deepClonePredicate = (owner: any, propertyName: string, current: an
|
|
|
279
279
|
* return true;
|
|
280
280
|
* });
|
|
281
281
|
* */
|
|
282
|
-
export function deepClone(obj: any, predicate?: deepClonePredicate): any {
|
|
282
|
+
export function deepClone(obj: any, predicate?: deepClonePredicate, _visited?: WeakSet<object>): any {
|
|
283
283
|
if (obj !== null && obj !== undefined && typeof obj === "object") {
|
|
284
|
+
if (!_visited) _visited = new WeakSet();
|
|
285
|
+
if (_visited.has(obj)) return obj;
|
|
286
|
+
_visited.add(obj);
|
|
287
|
+
|
|
284
288
|
let clone;
|
|
285
289
|
if (Array.isArray(obj)) clone = [];
|
|
286
290
|
else {
|
|
287
|
-
clone = Object.create(obj);
|
|
288
|
-
|
|
291
|
+
clone = Object.create(Object.getPrototypeOf(obj));
|
|
292
|
+
// Copy own properties, skipping getter-only properties that can't be set
|
|
293
|
+
const descriptors = Object.getOwnPropertyDescriptors(obj);
|
|
294
|
+
for (const key in descriptors) {
|
|
295
|
+
const desc = descriptors[key];
|
|
296
|
+
if (desc.set || desc.writable !== false) {
|
|
297
|
+
try { clone[key] = obj[key]; }
|
|
298
|
+
catch { /* skip read-only properties */ }
|
|
299
|
+
}
|
|
300
|
+
}
|
|
289
301
|
}
|
|
290
302
|
for (const key of Object.keys(obj)) {
|
|
291
303
|
const val = obj[key];
|
|
292
304
|
if (predicate && !predicate(obj, key, val)) {
|
|
293
|
-
// console.log("SKIP", val);
|
|
294
305
|
clone[key] = val;
|
|
295
306
|
}
|
|
296
307
|
else if (val?.clone !== undefined && typeof val.clone === "function")
|
|
297
308
|
clone[key] = val.clone();
|
|
298
309
|
else
|
|
299
|
-
clone[key] = deepClone(val, predicate);
|
|
310
|
+
clone[key] = deepClone(val, predicate, _visited);
|
|
300
311
|
}
|
|
301
312
|
return clone;
|
|
302
313
|
}
|