@needle-tools/engine 5.1.0-canary.fbdfce3 → 5.1.0-experimental.03e8105
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 +86 -0
- package/SKILL.md +4 -1
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-BFSj2Fz8.js → needle-engine.bundle-BNqUjnSQ.js} +19180 -18386
- package/dist/needle-engine.bundle-Bt8ULD7E.umd.cjs +1733 -0
- package/dist/needle-engine.bundle-DF6ovbwD.min.js +1733 -0
- package/dist/needle-engine.d.ts +1487 -356
- package/dist/needle-engine.js +544 -542
- 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 +8 -1
- package/lib/engine/api.js +7 -1
- 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_audio.d.ts +68 -0
- package/lib/engine/engine_audio.js +172 -0
- package/lib/engine/engine_audio.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_components.js +1 -1
- package/lib/engine/engine_components.js.map +1 -1
- package/lib/engine/engine_context.d.ts +21 -8
- package/lib/engine/engine_context.js +32 -16
- 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 +22 -120
- 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_init.js +7 -7
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_input.d.ts +24 -5
- package/lib/engine/engine_input.js +3 -2
- 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_license.d.ts +7 -7
- package/lib/engine/engine_license.js +183 -57
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +7 -4
- 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_blob.js +4 -4
- package/lib/engine/engine_networking_blob.js.map +1 -1
- 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_scenedata.js +2 -2
- package/lib/engine/engine_scenedata.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js +28 -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/engine_utils_qrcode.js +2 -2
- package/lib/engine/engine_utils_qrcode.js.map +1 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +6 -6
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +10 -4
- package/lib/engine/webcomponents/needle-engine.js +3 -3
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.loading.js +2 -2
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
- package/lib/engine/xr/NeedleXRSession.js +50 -14
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine/xr/TempXRContext.js +2 -2
- package/lib/engine/xr/TempXRContext.js.map +1 -1
- package/lib/engine/xr/events.d.ts +1 -1
- package/lib/engine/xr/events.js.map +1 -1
- package/lib/engine-components/Animation.js +17 -16
- package/lib/engine-components/Animation.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/AudioSource.d.ts +19 -3
- package/lib/engine-components/AudioSource.js +121 -68
- package/lib/engine-components/AudioSource.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.d.ts +7 -0
- package/lib/engine-components/DragControls.js +19 -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/Networking.d.ts +1 -1
- package/lib/engine-components/Networking.js +1 -1
- package/lib/engine-components/OrbitControls.d.ts +0 -2
- package/lib/engine-components/OrbitControls.js +30 -12
- 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/SeeThrough.js +2 -2
- package/lib/engine-components/SeeThrough.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/export/usdz/USDZExporter.js +4 -4
- package/lib/engine-components/export/usdz/USDZExporter.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/ui/Canvas.d.ts +1 -1
- package/lib/engine-components/ui/Canvas.js +2 -8
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/Text.d.ts +1 -0
- package/lib/engine-components/ui/Text.js +10 -7
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.d.ts +0 -1
- package/lib/engine-components/web/CursorFollow.js +21 -13
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js +4 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +2 -83
- package/plugins/common/cloud.js +6 -1
- package/plugins/common/license.js +31 -10
- package/plugins/common/worker.js +9 -4
- package/plugins/vite/asap.js +17 -8
- package/plugins/vite/dependencies.js +29 -10
- package/plugins/vite/dependency-watcher.js +2 -2
- package/plugins/vite/editor-connection.js +3 -3
- package/plugins/vite/license.js +46 -7
- package/plugins/vite/local-files-core.js +3 -3
- package/plugins/vite/local-files-utils.d.ts +3 -1
- package/plugins/vite/local-files-utils.js +29 -5
- package/plugins/vite/reload.js +1 -1
- package/plugins/vite/server.js +2 -1
- package/src/engine/api.ts +11 -1
- package/src/engine/codegen/register_types.ts +10 -18
- package/src/engine/engine_audio.ts +184 -0
- package/src/engine/engine_camera.fit.ts +15 -4
- package/src/engine/engine_components.ts +1 -1
- package/src/engine/engine_context.ts +34 -18
- package/src/engine/engine_context_eventbus.ts +73 -0
- package/src/engine/engine_disposable.ts +214 -0
- package/src/engine/engine_gameobject.ts +54 -159
- package/src/engine/engine_gltf_builtin_components.ts +7 -76
- package/src/engine/engine_init.ts +7 -7
- package/src/engine/engine_input.ts +28 -7
- package/src/engine/engine_instantiate_resolve.ts +407 -0
- package/src/engine/engine_license.ts +197 -55
- package/src/engine/engine_mainloop_utils.ts +7 -4
- package/src/engine/engine_networking.transport.websocket.ts +45 -0
- package/src/engine/engine_networking.ts +161 -137
- package/src/engine/engine_networking_blob.ts +4 -4
- 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_scenedata.ts +3 -3
- package/src/engine/engine_serialization_builtin_serializer.ts +32 -9
- 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/engine_utils_qrcode.ts +2 -2
- package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
- package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
- package/src/engine/webcomponents/needle menu/needle-menu.ts +6 -6
- package/src/engine/webcomponents/needle-engine.loading.ts +6 -6
- package/src/engine/webcomponents/needle-engine.ts +12 -6
- package/src/engine/xr/NeedleXRSession.ts +48 -13
- package/src/engine/xr/TempXRContext.ts +2 -2
- package/src/engine/xr/events.ts +1 -1
- package/src/engine-components/Animation.ts +19 -16
- 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/AudioSource.ts +130 -79
- 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 +18 -11
- 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/Networking.ts +1 -1
- package/src/engine-components/OrbitControls.ts +34 -14
- package/src/engine-components/RigidBody.ts +18 -4
- package/src/engine-components/SceneSwitcher.ts +3 -0
- package/src/engine-components/SeeThrough.ts +2 -2
- package/src/engine-components/api.ts +2 -1
- package/src/engine-components/codegen/components.ts +7 -13
- package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
- 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/ui/Canvas.ts +2 -8
- package/src/engine-components/ui/Text.ts +12 -8
- package/src/engine-components/web/CursorFollow.ts +21 -14
- package/src/engine-components/webxr/WebXRImageTracking.ts +2 -0
- package/dist/needle-engine.bundle-CmxIO5uH.min.js +0 -1732
- package/dist/needle-engine.bundle-tJIZukCz.umd.cjs +0 -1732
- 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/plugins/dts-generator/dts.codegen.js +0 -334
- package/plugins/dts-generator/dts.scan.js +0 -99
- package/plugins/dts-generator/dts.writer.js +0 -59
- package/plugins/dts-generator/glb.discovery.js +0 -279
- package/plugins/dts-generator/glb.extractor.js +0 -215
- package/plugins/dts-generator/glb.reader.js +0 -167
- package/plugins/dts-generator/index.js +0 -36
- package/plugins/dts-generator/manifest.types.js +0 -174
- package/plugins/gltf-packer.mjs +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
- package/src/vite-env.d.ts +0 -16
|
@@ -10,9 +10,10 @@ import * as main from "../engine/engine_mainloop_utils.js";
|
|
|
10
10
|
import { syncDestroy, syncInstantiate, SyncInstantiateOptions } from "../engine/engine_networking_instantiate.js";
|
|
11
11
|
import { Context, FrameEvent } from "../engine/engine_setup.js";
|
|
12
12
|
import * as threeutils from "../engine/engine_three_utils.js";
|
|
13
|
-
import { $componentName, type Collision, type ComponentInit, type Constructor, type ConstructorConcrete, type
|
|
13
|
+
import { $componentName, type Collision, type ComponentInit, type Constructor, type ConstructorConcrete, type ICollider, type IComponent, type IGameObject, type SourceIdentifier } from "../engine/engine_types.js";
|
|
14
14
|
import { TypeStore } from "../engine/engine_typestore.js";
|
|
15
15
|
import type { INeedleXRSessionEventReceiver, NeedleXRControllerEventArgs, NeedleXREventArgs } from "../engine/engine_xr.js";
|
|
16
|
+
import { DisposableStore, type IDisposable, type DisposeFn } from "../engine/engine_disposable.js";
|
|
16
17
|
import { type IPointerEventHandler, PointerEventData } from "./ui/PointerEvents.js";
|
|
17
18
|
|
|
18
19
|
|
|
@@ -556,7 +557,7 @@ export abstract class GameObject extends Object3D implements Object3D, IGameObje
|
|
|
556
557
|
* **Input event methods:**
|
|
557
558
|
* {@link onPointerDown}, {@link onPointerUp}, {@link onPointerEnter}, {@link onPointerExit} and {@link onPointerMove}.
|
|
558
559
|
*
|
|
559
|
-
* @example
|
|
560
|
+
* @example Basic component
|
|
560
561
|
* ```typescript
|
|
561
562
|
* import { Behaviour } from "@needle-tools/engine";
|
|
562
563
|
* export class MyComponent extends Behaviour {
|
|
@@ -568,13 +569,31 @@ export abstract class GameObject extends Object3D implements Object3D, IGameObje
|
|
|
568
569
|
* }
|
|
569
570
|
* }
|
|
570
571
|
* ```
|
|
571
|
-
*
|
|
572
|
+
*
|
|
573
|
+
* @example Automatic cleanup with autoCleanup
|
|
574
|
+
* ```typescript
|
|
575
|
+
* import { Behaviour, serializable, EventList } from "@needle-tools/engine";
|
|
576
|
+
* export class ScoreTracker extends Behaviour {
|
|
577
|
+
* @serializable(EventList)
|
|
578
|
+
* onScoreChanged?: EventList<number>;
|
|
579
|
+
*
|
|
580
|
+
* start() {
|
|
581
|
+
* // Registered during start → survives enable/disable, cleaned up on destroy
|
|
582
|
+
* this.autoCleanup(this.onScoreChanged?.on(score => console.log("Score:", score)));
|
|
583
|
+
* }
|
|
584
|
+
*
|
|
585
|
+
* onEnable() {
|
|
586
|
+
* // Registered during onEnable → cleaned up on disable
|
|
587
|
+
* this.autoCleanup(() => this.cleanupResources());
|
|
588
|
+
* }
|
|
589
|
+
* }
|
|
590
|
+
* ```
|
|
591
|
+
*
|
|
572
592
|
* @group Components
|
|
573
593
|
*/
|
|
574
594
|
export abstract class Component implements IComponent, EventTarget,
|
|
575
595
|
Partial<INeedleXRSessionEventReceiver>,
|
|
576
|
-
Partial<IPointerEventHandler>
|
|
577
|
-
{
|
|
596
|
+
Partial<IPointerEventHandler> {
|
|
578
597
|
/**
|
|
579
598
|
* Indicates whether this object is a component
|
|
580
599
|
* @internal
|
|
@@ -686,6 +705,74 @@ export abstract class Component implements IComponent, EventTarget,
|
|
|
686
705
|
return true;
|
|
687
706
|
}
|
|
688
707
|
|
|
708
|
+
private __disableCleanups?: DisposableStore;
|
|
709
|
+
private __destroyCleanups?: DisposableStore;
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* @experimental
|
|
713
|
+
* Register a resource for automatic cleanup tied to this component's lifecycle.
|
|
714
|
+
* Accepts {@link IDisposable} objects, cleanup functions, or event unsubscribe functions.
|
|
715
|
+
* `null` and `undefined` are safe no-ops (convenient for conditional subscriptions).
|
|
716
|
+
*
|
|
717
|
+
* **Lifecycle-aware:** The cleanup store is chosen automatically based on when `autoCleanup` is called:
|
|
718
|
+
* - Called during {@link onEnable} → cleaned up on {@link onDisable} (and re-registered on re-enable)
|
|
719
|
+
* - Called during {@link awake} or {@link start} → cleaned up on {@link onDestroy} (survives enable/disable cycles)
|
|
720
|
+
* - Called at any other time (e.g. from update) → cleaned up on {@link onDisable}
|
|
721
|
+
*
|
|
722
|
+
* @param disposable An {@link IDisposable}, a cleanup/unsubscribe function, or `null`/`undefined`
|
|
723
|
+
*
|
|
724
|
+
* @example EventList subscriptions
|
|
725
|
+
* ```ts
|
|
726
|
+
* import { Behaviour, serializable, EventList } from "@needle-tools/engine";
|
|
727
|
+
*
|
|
728
|
+
* export class MyComponent extends Behaviour {
|
|
729
|
+
* @serializable(EventList)
|
|
730
|
+
* onScoreChanged?: EventList<number>;
|
|
731
|
+
*
|
|
732
|
+
* onEnable() {
|
|
733
|
+
* this.autoCleanup(this.onScoreChanged?.on(score => {
|
|
734
|
+
* console.log("Score:", score);
|
|
735
|
+
* }));
|
|
736
|
+
* }
|
|
737
|
+
* }
|
|
738
|
+
* ```
|
|
739
|
+
*
|
|
740
|
+
* @example Lifetime subscriptions in awake
|
|
741
|
+
* ```ts
|
|
742
|
+
* import { Behaviour } from "@needle-tools/engine";
|
|
743
|
+
*
|
|
744
|
+
* export class Persistent extends Behaviour {
|
|
745
|
+
* awake() {
|
|
746
|
+
* // Registered during awake → survives enable/disable, cleaned up on destroy
|
|
747
|
+
* this.autoCleanup(() => this.save());
|
|
748
|
+
* }
|
|
749
|
+
* }
|
|
750
|
+
* ```
|
|
751
|
+
*/
|
|
752
|
+
protected autoCleanup(disposable: IDisposable | DisposeFn | Function | null | undefined): void {
|
|
753
|
+
if (!disposable) {
|
|
754
|
+
if (isDevEnvironment()) {
|
|
755
|
+
console.warn(`[Component] autoCleanup called with null or undefined, no cleanup registered. This is safe, but you may want to check if this was intentional (${this[$componentName] || this.constructor.name})`);
|
|
756
|
+
}
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
// During onEnable → cleaned up on disable
|
|
760
|
+
if (this.__inEnableOrDisableCallback) {
|
|
761
|
+
if (!this.__disableCleanups) this.__disableCleanups = new DisposableStore();
|
|
762
|
+
this.__disableCleanups.add(disposable);
|
|
763
|
+
}
|
|
764
|
+
// During awake or start → cleaned up on destroy
|
|
765
|
+
else if (!this.__didCompleteStart) {
|
|
766
|
+
if (!this.__destroyCleanups) this.__destroyCleanups = new DisposableStore();
|
|
767
|
+
this.__destroyCleanups.add(disposable);
|
|
768
|
+
}
|
|
769
|
+
// After start (update, etc.) → cleaned up on disable
|
|
770
|
+
else {
|
|
771
|
+
if (!this.__disableCleanups) this.__disableCleanups = new DisposableStore();
|
|
772
|
+
this.__disableCleanups.add(disposable);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
689
776
|
private get __isActive(): boolean {
|
|
690
777
|
return this.gameObject.visible;
|
|
691
778
|
}
|
|
@@ -720,12 +807,6 @@ export abstract class Component implements IComponent, EventTarget,
|
|
|
720
807
|
*/
|
|
721
808
|
sourceId?: SourceIdentifier;
|
|
722
809
|
|
|
723
|
-
/**
|
|
724
|
-
* Called when this component needs to remap guids after an instantiate operation.
|
|
725
|
-
* @param guidsMap Mapping from old guids to newly generated guids
|
|
726
|
-
*/
|
|
727
|
-
resolveGuids?(guidsMap: GuidsMap): void;
|
|
728
|
-
|
|
729
810
|
/**
|
|
730
811
|
* Called once when the component becomes active for the first time.
|
|
731
812
|
* This is the first lifecycle callback to be invoked
|
|
@@ -988,6 +1069,12 @@ export abstract class Component implements IComponent, EventTarget,
|
|
|
988
1069
|
/** @internal */
|
|
989
1070
|
private __didStart: boolean = false;
|
|
990
1071
|
|
|
1072
|
+
/** True while start() has finished executing (used by autoCleanup to distinguish start from update) */
|
|
1073
|
+
private __didCompleteStart: boolean = false;
|
|
1074
|
+
|
|
1075
|
+
/** True while onEnable() is executing (used by autoCleanup to route to disable store) */
|
|
1076
|
+
private __inEnableOrDisableCallback: boolean = false;
|
|
1077
|
+
|
|
991
1078
|
/** @internal */
|
|
992
1079
|
protected __didEnable: boolean = false;
|
|
993
1080
|
|
|
@@ -1004,6 +1091,8 @@ export abstract class Component implements IComponent, EventTarget,
|
|
|
1004
1091
|
constructor(init?: ComponentInit<Component>) {
|
|
1005
1092
|
this.__didAwake = false;
|
|
1006
1093
|
this.__didStart = false;
|
|
1094
|
+
this.__didCompleteStart = false;
|
|
1095
|
+
this.__inEnableOrDisableCallback = false;
|
|
1007
1096
|
this.__didEnable = false;
|
|
1008
1097
|
this.__isEnabled = undefined;
|
|
1009
1098
|
this.__destroyed = false;
|
|
@@ -1015,6 +1104,8 @@ export abstract class Component implements IComponent, EventTarget,
|
|
|
1015
1104
|
__internalNewInstanceCreated(init?: ComponentInit<this>): this {
|
|
1016
1105
|
this.__didAwake = false;
|
|
1017
1106
|
this.__didStart = false;
|
|
1107
|
+
this.__didCompleteStart = false;
|
|
1108
|
+
this.__inEnableOrDisableCallback = false;
|
|
1018
1109
|
this.__didEnable = false;
|
|
1019
1110
|
this.__isEnabled = undefined;
|
|
1020
1111
|
this.__destroyed = false;
|
|
@@ -1051,11 +1142,12 @@ export abstract class Component implements IComponent, EventTarget,
|
|
|
1051
1142
|
if (this.__didStart) return;
|
|
1052
1143
|
this.__didStart = true;
|
|
1053
1144
|
if (this.start) this.start();
|
|
1145
|
+
this.__didCompleteStart = true;
|
|
1054
1146
|
}
|
|
1055
1147
|
|
|
1056
1148
|
|
|
1057
1149
|
/** @internal */
|
|
1058
|
-
__internalEnable(
|
|
1150
|
+
__internalEnable(isHierarchyChange?: boolean): boolean {
|
|
1059
1151
|
if (this.__destroyed) {
|
|
1060
1152
|
if (isDevEnvironment()) {
|
|
1061
1153
|
console.warn("[Needle Engine Dev] Trying to enable destroyed component");
|
|
@@ -1066,33 +1158,38 @@ export abstract class Component implements IComponent, EventTarget,
|
|
|
1066
1158
|
// But a user can change enable during awake
|
|
1067
1159
|
if (!this.__didAwake) return false;
|
|
1068
1160
|
if (this.__didEnable) {
|
|
1069
|
-
//
|
|
1070
|
-
|
|
1071
|
-
if (isAddingToScene !== true)
|
|
1161
|
+
// Don't change __isEnabled for hierarchy-driven changes (e.g. adding to scene, visibility)
|
|
1162
|
+
if (isHierarchyChange !== true)
|
|
1072
1163
|
this.__isEnabled = true;
|
|
1073
1164
|
return false;
|
|
1074
1165
|
}
|
|
1075
|
-
// console.trace("INTERNAL ENABLE");
|
|
1076
1166
|
this.__didEnable = true;
|
|
1077
1167
|
this.__isEnabled = true;
|
|
1168
|
+
this.__inEnableOrDisableCallback = true;
|
|
1078
1169
|
this.onEnable();
|
|
1170
|
+
this.__inEnableOrDisableCallback = false;
|
|
1079
1171
|
return true;
|
|
1080
1172
|
}
|
|
1081
1173
|
|
|
1082
1174
|
/** @internal */
|
|
1083
|
-
__internalDisable(
|
|
1175
|
+
__internalDisable(isHierarchyChange?: boolean) {
|
|
1084
1176
|
// Don't change enable before awake
|
|
1085
1177
|
// But a user can change enable during awake
|
|
1086
1178
|
if (!this.__didAwake) return;
|
|
1087
1179
|
if (!this.__didEnable) {
|
|
1088
|
-
//
|
|
1089
|
-
if (
|
|
1180
|
+
// Don't change __isEnabled for hierarchy-driven changes (e.g. removing from scene, visibility)
|
|
1181
|
+
if (isHierarchyChange !== true)
|
|
1090
1182
|
this.__isEnabled = false;
|
|
1091
1183
|
return;
|
|
1092
1184
|
}
|
|
1093
1185
|
this.__didEnable = false;
|
|
1094
|
-
|
|
1186
|
+
// Don't change __isEnabled for hierarchy-driven changes — the component itself is still "enabled"
|
|
1187
|
+
if (isHierarchyChange !== true)
|
|
1188
|
+
this.__isEnabled = false;
|
|
1189
|
+
this.__inEnableOrDisableCallback = true;
|
|
1095
1190
|
this.onDisable();
|
|
1191
|
+
this.__disableCleanups?.dispose();
|
|
1192
|
+
this.__inEnableOrDisableCallback = false;
|
|
1096
1193
|
}
|
|
1097
1194
|
|
|
1098
1195
|
/** @internal */
|
|
@@ -1101,6 +1198,7 @@ export abstract class Component implements IComponent, EventTarget,
|
|
|
1101
1198
|
this.__destroyed = true;
|
|
1102
1199
|
if (this.__didAwake) {
|
|
1103
1200
|
this.onDestroy?.call(this);
|
|
1201
|
+
this.__destroyCleanups?.dispose();
|
|
1104
1202
|
this.dispatchEvent(new CustomEvent("destroyed", { detail: this }));
|
|
1105
1203
|
}
|
|
1106
1204
|
destroyComponentInstance(this as any);
|
|
@@ -100,7 +100,7 @@ export class ContactShadows extends Behaviour {
|
|
|
100
100
|
const obj = new Object3D();
|
|
101
101
|
obj.name = "ContactShadows";
|
|
102
102
|
instance = addComponent(obj, ContactShadows, {
|
|
103
|
-
autoFit:
|
|
103
|
+
autoFit: true,
|
|
104
104
|
occludeBelowGround: false
|
|
105
105
|
});
|
|
106
106
|
this._instances.set(context, instance);
|
|
@@ -169,6 +169,10 @@ export class ContactShadows extends Behaviour {
|
|
|
169
169
|
return this._needsUpdate;
|
|
170
170
|
}
|
|
171
171
|
private _needsUpdate: boolean = false;
|
|
172
|
+
private _needsFit: boolean = false;
|
|
173
|
+
|
|
174
|
+
// TODO: support auto-refit for moveable/animated objects (e.g. via mesh-bvh / scene BVH).
|
|
175
|
+
// Currently there's no reliable way to detect object position/scale changes.
|
|
172
176
|
|
|
173
177
|
/** All shadow objects are parented to this object.
|
|
174
178
|
* The gameObject itself should not be transformed because we want the ContactShadows object e.g. also have a GroundProjectedEnv component
|
|
@@ -366,6 +370,11 @@ export class ContactShadows extends Behaviour {
|
|
|
366
370
|
|
|
367
371
|
onEnable(): void {
|
|
368
372
|
this._needsUpdate = true;
|
|
373
|
+
this.autoCleanup(this.context.events.on("scene-content-changed", () => {
|
|
374
|
+
if (!this.autoFit) return;
|
|
375
|
+
this._needsFit = true;
|
|
376
|
+
this._needsUpdate = true;
|
|
377
|
+
}));
|
|
369
378
|
}
|
|
370
379
|
|
|
371
380
|
/** @internal */
|
|
@@ -393,6 +402,11 @@ export class ContactShadows extends Behaviour {
|
|
|
393
402
|
/** @internal */
|
|
394
403
|
onBeforeRender(_frame: XRFrame | null): void {
|
|
395
404
|
|
|
405
|
+
if (this._needsFit && this.autoFit) {
|
|
406
|
+
this._needsFit = false;
|
|
407
|
+
this.fitShadows();
|
|
408
|
+
}
|
|
409
|
+
|
|
396
410
|
if (this.manualUpdate) {
|
|
397
411
|
if (!this._needsUpdate) return;
|
|
398
412
|
}
|
|
@@ -10,8 +10,8 @@ import { getBoundingBox, getTempVector, getWorldPosition, setWorldPosition } fro
|
|
|
10
10
|
import { type IGameObject } from "../engine/engine_types.js";
|
|
11
11
|
import { getParam } from "../engine/engine_utils.js";
|
|
12
12
|
import { NeedleXRSession } from "../engine/engine_xr.js";
|
|
13
|
-
import { Avatar_POI } from "./avatar/Avatar_Brain_LookAt.js";
|
|
14
13
|
import { Behaviour, GameObject } from "./Component.js";
|
|
14
|
+
import { EventList } from "./EventList.js";
|
|
15
15
|
import { UsageMarker } from "./Interactable.js";
|
|
16
16
|
import { Rigidbody } from "./RigidBody.js";
|
|
17
17
|
import { SyncedTransform } from "./SyncedTransform.js";
|
|
@@ -155,7 +155,19 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
155
155
|
@serializable()
|
|
156
156
|
public showGizmo: boolean = false;
|
|
157
157
|
|
|
158
|
-
/**
|
|
158
|
+
/** Invoked once when a drag begins (after the minimum drag distance threshold is met). */
|
|
159
|
+
@serializable(EventList)
|
|
160
|
+
dragStarted: EventList = new EventList();
|
|
161
|
+
|
|
162
|
+
/** Invoked every frame while the object is being dragged. */
|
|
163
|
+
@serializable(EventList)
|
|
164
|
+
dragUpdated: EventList = new EventList();
|
|
165
|
+
|
|
166
|
+
/** Invoked once when the last pointer is released and the drag ends. */
|
|
167
|
+
@serializable(EventList)
|
|
168
|
+
dragEnded: EventList = new EventList();
|
|
169
|
+
|
|
170
|
+
/**
|
|
159
171
|
* Returns the object currently being dragged by this DragControls component, if any.
|
|
160
172
|
* @returns The object being dragged or null if no object is currently dragged
|
|
161
173
|
*/
|
|
@@ -457,6 +469,7 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
457
469
|
if (!object) return;
|
|
458
470
|
|
|
459
471
|
this._isDragging = true;
|
|
472
|
+
this.dragStarted?.invoke();
|
|
460
473
|
|
|
461
474
|
const sync = GameObject.getComponentInChildren(object, SyncedTransform);
|
|
462
475
|
if (debug) console.log("DRAG START", sync, object);
|
|
@@ -497,9 +510,10 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
497
510
|
const object = this._targetObject || this.gameObject;
|
|
498
511
|
|
|
499
512
|
InstancingUtil.markDirty(object);
|
|
513
|
+
this.dragUpdated?.invoke();
|
|
500
514
|
}
|
|
501
515
|
|
|
502
|
-
/**
|
|
516
|
+
/**
|
|
503
517
|
* Called when the last pointer has been removed from this object.
|
|
504
518
|
* Cleans up drag state and applies final velocities to rigidbodies.
|
|
505
519
|
* @param evt Pointer event data for the last pointer that was lifted
|
|
@@ -507,6 +521,7 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
507
521
|
private onLastDragEnd(evt: PointerEventData | null) {
|
|
508
522
|
if (!this || !this._isDragging) return;
|
|
509
523
|
this._isDragging = false;
|
|
524
|
+
this.dragEnded?.invoke();
|
|
510
525
|
for (const rb of this._draggingRigidbodies) {
|
|
511
526
|
rb.setVelocity(rb.smoothedVelocity.multiplyScalar(this.context.time.deltaTime));
|
|
512
527
|
}
|
|
@@ -1484,11 +1499,6 @@ class LegacyDragVisualsHelper {
|
|
|
1484
1499
|
}
|
|
1485
1500
|
}
|
|
1486
1501
|
|
|
1487
|
-
if (this._selected) {
|
|
1488
|
-
// TODO move somewhere else
|
|
1489
|
-
Avatar_POI.Remove(context, this._selected);
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
1502
|
this._selected = newSelected;
|
|
1493
1503
|
this._context = context;
|
|
1494
1504
|
this._rbs.length = 0;
|
|
@@ -1508,9 +1518,6 @@ class LegacyDragVisualsHelper {
|
|
|
1508
1518
|
return;
|
|
1509
1519
|
}
|
|
1510
1520
|
|
|
1511
|
-
// TODO move somewhere else
|
|
1512
|
-
Avatar_POI.Add(context, this._selected, null);
|
|
1513
|
-
|
|
1514
1521
|
this._groundOffsetFactor = 0;
|
|
1515
1522
|
this._hasGroundPlane = true;
|
|
1516
1523
|
this._groundOffset.set(0, 0, 0);
|
|
@@ -597,6 +597,9 @@ export class DropListener extends Behaviour {
|
|
|
597
597
|
});
|
|
598
598
|
this.dispatchEvent(evt);
|
|
599
599
|
this.onDropped?.invoke(evt.detail);
|
|
600
|
+
if (obj) {
|
|
601
|
+
this.context.events.emit("scene-content-changed", { source: this, object: obj });
|
|
602
|
+
}
|
|
600
603
|
|
|
601
604
|
// send network event
|
|
602
605
|
if (!isRemote && ctx.url?.startsWith("http") && this.context.connection.isConnected && obj) {
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { isDevEnvironment } from "../engine/debug/index.js";
|
|
2
|
-
import { InstantiateContext } from "../engine/engine_gameobject.js";
|
|
3
2
|
import type { IComponent, IEventList } from "../engine/engine_types.js";
|
|
4
3
|
|
|
5
4
|
const argumentsBuffer = new Array<any>();
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* CallInfo represents a single callback method that can be invoked by the {@link EventList}.
|
|
7
|
+
* CallInfo represents a single callback method that can be invoked by the {@link EventList}.
|
|
9
8
|
*/
|
|
10
9
|
export class CallInfo {
|
|
10
|
+
|
|
11
|
+
/** @internal Used by the instantiate resolver to recursively resolve references */
|
|
12
|
+
static { CallInfo.prototype.$serializedTypes = { target: Object, arguments: Array }; }
|
|
13
|
+
declare $serializedTypes: Record<string, any>;
|
|
14
|
+
|
|
11
15
|
/**
|
|
12
16
|
* When the CallInfo is enabled it will be invoked when the EventList is invoked
|
|
13
17
|
*/
|
|
@@ -95,8 +99,7 @@ export class CallInfo {
|
|
|
95
99
|
}
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
/** @deprecated No longer automatically dispatched. Use `eventList.on()` directly instead. */
|
|
100
103
|
export class EventListEvent<TArgs extends any> extends Event { //implements ArrayLike<T> {
|
|
101
104
|
args?: TArgs;
|
|
102
105
|
}
|
|
@@ -150,73 +153,13 @@ export class EventListEvent<TArgs extends any> extends Event { //implements Arra
|
|
|
150
153
|
*/
|
|
151
154
|
export class EventList<TArgs extends any = any> implements IEventList {
|
|
152
155
|
|
|
156
|
+
/** @internal Used by the instantiate resolver to recursively resolve references */
|
|
157
|
+
static { EventList.prototype.$serializedTypes = { methods: Array }; }
|
|
158
|
+
declare $serializedTypes: Record<string, any>;
|
|
159
|
+
|
|
153
160
|
/** checked during instantiate to create a new instance */
|
|
154
161
|
readonly isEventList = true;
|
|
155
162
|
|
|
156
|
-
/**
|
|
157
|
-
* @internal Used by the Needle Engine instantiate call to remap the event listeners to the new instance
|
|
158
|
-
*/
|
|
159
|
-
__internalOnInstantiate(ctx: InstantiateContext) {
|
|
160
|
-
const newMethods = new Array<CallInfo>();
|
|
161
|
-
for (let i = 0; i < this.methods.length; i++) {
|
|
162
|
-
const method = this.methods[i];
|
|
163
|
-
if (method.target instanceof Function) {
|
|
164
|
-
// can not clone a function
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
const target = method.target as { uuid?: string };
|
|
168
|
-
let key = target?.uuid;
|
|
169
|
-
if ((target as IComponent)) {
|
|
170
|
-
key = (target as IComponent).guid;
|
|
171
|
-
}
|
|
172
|
-
if (key) {
|
|
173
|
-
const newTarget = ctx[key];
|
|
174
|
-
if (newTarget) {
|
|
175
|
-
// remap the arguments to the new instance (e.g. if an object is passed as an argument to the event list and this object has been cloned we want to remap it to the clone)
|
|
176
|
-
const newArguments = method.arguments?.map(arg => {
|
|
177
|
-
if (arg instanceof Object && arg.uuid) {
|
|
178
|
-
return ctx[arg.uuid].clone;
|
|
179
|
-
}
|
|
180
|
-
else if ((arg as IComponent)?.isComponent) {
|
|
181
|
-
return ctx[(arg as IComponent).guid].clone;
|
|
182
|
-
}
|
|
183
|
-
return arg;
|
|
184
|
-
});
|
|
185
|
-
newMethods.push(new CallInfo(newTarget.clone, method.methodName, newArguments, method.enabled));
|
|
186
|
-
}
|
|
187
|
-
else if (isDevEnvironment()) {
|
|
188
|
-
console.warn("Could not find target for event listener");
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
const newInstance = new EventList(newMethods);
|
|
194
|
-
return newInstance;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
private target?: object;
|
|
198
|
-
private key?: string;
|
|
199
|
-
|
|
200
|
-
// TODO: serialization should not take care of the args but instead give them to the eventlist directly
|
|
201
|
-
// so we can handle passing them on here instead of in the serializer
|
|
202
|
-
// this would also allow us to pass them on to the component EventTarget
|
|
203
|
-
|
|
204
|
-
/** set an event target to try invoke the EventTarget dispatchEvent when this EventList is invoked */
|
|
205
|
-
setEventTarget(key: string, target: object) {
|
|
206
|
-
this.key = key;
|
|
207
|
-
this.target = target;
|
|
208
|
-
if (this.key !== undefined) {
|
|
209
|
-
let temp = "";
|
|
210
|
-
let foundFirstLetter = false;
|
|
211
|
-
for (const c of this.key) {
|
|
212
|
-
if (foundFirstLetter && isUpperCase(c))
|
|
213
|
-
temp += "-";
|
|
214
|
-
foundFirstLetter = true;
|
|
215
|
-
temp += c.toLowerCase();
|
|
216
|
-
}
|
|
217
|
-
this.key = temp;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
163
|
|
|
221
164
|
/** How many callback methods are subscribed to this event */
|
|
222
165
|
get listenerCount() { return this.methods?.length ?? 0; }
|
|
@@ -285,24 +228,9 @@ export class EventList<TArgs extends any = any> implements IEventList {
|
|
|
285
228
|
this._methodsCopy.length = 0;
|
|
286
229
|
this._methodsCopy.push(...this.methods);
|
|
287
230
|
|
|
288
|
-
// first invoke all the methods that were subscribed to this eventlist
|
|
289
231
|
for (const m of this._methodsCopy) {
|
|
290
232
|
m.invoke(...args);
|
|
291
233
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
// then try to dispatch the event on the object that is owning this eventlist
|
|
295
|
-
// with this we get automatic event listener support for unity events on all componnets
|
|
296
|
-
// so example for a component with a click UnityEvent you can also subscribe to the component like this:
|
|
297
|
-
// myComponent.addEventListener("click", args => {...")
|
|
298
|
-
if (typeof this.target === "object" && typeof this.key === "string") {
|
|
299
|
-
const fn = this.target["dispatchEvent"];
|
|
300
|
-
if (typeof fn === "function") {
|
|
301
|
-
const evt = new EventListEvent(this.key);
|
|
302
|
-
evt.args = args;
|
|
303
|
-
fn.call(this.target, evt);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
234
|
}
|
|
307
235
|
finally {
|
|
308
236
|
this._isInvoking = false;
|
|
@@ -313,12 +241,32 @@ export class EventList<TArgs extends any = any> implements IEventList {
|
|
|
313
241
|
|
|
314
242
|
/** Add a new event listener to this event
|
|
315
243
|
* @returns a function to remove the event listener
|
|
244
|
+
* @see {@link removeEventListener} for more details and return value information
|
|
245
|
+
* @see {@link off} for an alias with better readability when unsubscribing from events
|
|
246
|
+
* @example
|
|
247
|
+
* ```ts
|
|
248
|
+
* const off = myEvent.addEventListener(args => console.log("Clicked!", args));
|
|
249
|
+
* // later
|
|
250
|
+
* off();
|
|
251
|
+
* ```
|
|
316
252
|
*/
|
|
317
253
|
addEventListener(callback: (args: TArgs) => void): Function {
|
|
318
254
|
this.methods.push(new CallInfo(callback));
|
|
319
255
|
return () => this.removeEventListener(callback);
|
|
320
256
|
}
|
|
321
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Alias for addEventListener for better readability when subscribing to events. You can use it like this:
|
|
260
|
+
* ```ts
|
|
261
|
+
* myEvent.on(args => console.log("Clicked!", args));
|
|
262
|
+
* ```
|
|
263
|
+
* @returns a function to remove the event listener
|
|
264
|
+
* @see {@link addEventListener} for more details and return value information
|
|
265
|
+
*/
|
|
266
|
+
on(callback: (args: TArgs) => void): Function {
|
|
267
|
+
return this.addEventListener(callback);
|
|
268
|
+
}
|
|
269
|
+
|
|
322
270
|
/**
|
|
323
271
|
* Remove an event listener from this event.
|
|
324
272
|
* @returns true if the event listener was found and removed, false otherwise
|
|
@@ -336,6 +284,20 @@ export class EventList<TArgs extends any = any> implements IEventList {
|
|
|
336
284
|
return found;
|
|
337
285
|
}
|
|
338
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Alias for removeEventListener for better readability when unsubscribing from events. You can use it like this:
|
|
289
|
+
* ```ts
|
|
290
|
+
* const off = myEvent.on(args => console.log("Clicked!", args));
|
|
291
|
+
* // later
|
|
292
|
+
* off();
|
|
293
|
+
* ```
|
|
294
|
+
*
|
|
295
|
+
* @see {@link removeEventListener} for more details and return value information
|
|
296
|
+
*/
|
|
297
|
+
off(callback: Function | null | undefined) {
|
|
298
|
+
return this.removeEventListener(callback);
|
|
299
|
+
}
|
|
300
|
+
|
|
339
301
|
/**
|
|
340
302
|
* Remove all event listeners from this event. Use with caution! This will remove all listeners!
|
|
341
303
|
*/
|
|
@@ -28,6 +28,7 @@ export abstract class Joint extends Behaviour {
|
|
|
28
28
|
return this._rigidBody;
|
|
29
29
|
}
|
|
30
30
|
private _rigidBody: Rigidbody | null = null;
|
|
31
|
+
private _jointHandle: any = null;
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
onEnable() {
|
|
@@ -36,14 +37,28 @@ export abstract class Joint extends Behaviour {
|
|
|
36
37
|
this.startCoroutine(this.create());
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
onDisable() {
|
|
41
|
+
if (this._jointHandle) {
|
|
42
|
+
this.context.physics.engine?.removeJoint(this._jointHandle);
|
|
43
|
+
this._jointHandle = null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
39
47
|
private *create() {
|
|
40
48
|
yield;
|
|
49
|
+
if (this._jointHandle) return;
|
|
41
50
|
if (this.rigidBody && this.connectedBody && this.activeAndEnabled) {
|
|
42
|
-
this.createJoint(this.rigidBody, this.connectedBody)
|
|
51
|
+
const result = this.createJoint(this.rigidBody, this.connectedBody);
|
|
52
|
+
if (result instanceof Promise) {
|
|
53
|
+
yield result.then(handle => this._jointHandle = handle);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this._jointHandle = result;
|
|
57
|
+
}
|
|
43
58
|
}
|
|
44
59
|
}
|
|
45
60
|
|
|
46
|
-
protected abstract createJoint(self: Rigidbody, other: Rigidbody);
|
|
61
|
+
protected abstract createJoint(self: Rigidbody, other: Rigidbody): any;
|
|
47
62
|
}
|
|
48
63
|
|
|
49
64
|
/**
|
|
@@ -70,7 +85,7 @@ export abstract class Joint extends Behaviour {
|
|
|
70
85
|
export class FixedJoint extends Joint {
|
|
71
86
|
|
|
72
87
|
protected createJoint(self: Rigidbody, other: Rigidbody) {
|
|
73
|
-
this.context.physics.engine?.addFixedJoint(self, other);
|
|
88
|
+
return this.context.physics.engine?.addFixedJoint(self, other) ?? null;
|
|
74
89
|
}
|
|
75
90
|
}
|
|
76
91
|
|
|
@@ -110,7 +125,8 @@ export class HingeJoint extends Joint {
|
|
|
110
125
|
|
|
111
126
|
protected createJoint(self: Rigidbody, other: Rigidbody) {
|
|
112
127
|
if (this.axis && this.anchor)
|
|
113
|
-
this.context.physics.engine?.addHingeJoint(self, other, this.anchor, this.axis);
|
|
128
|
+
return this.context.physics.engine?.addHingeJoint(self, other, this.anchor, this.axis) ?? null;
|
|
129
|
+
return null;
|
|
114
130
|
}
|
|
115
131
|
|
|
116
132
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CameraHelper, Color, DirectionalLight, DirectionalLightHelper, Light as ThreeLight, OrthographicCamera, PointLight, SpotLight, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
4
|
-
import { FrameEvent } from "../engine/engine_setup.js";
|
|
5
4
|
import { setWorldPositionXYZ } from "../engine/engine_three_utils.js";
|
|
6
5
|
import type { ILight } from "../engine/engine_types.js";
|
|
7
6
|
import { getParam } from "../engine/engine_utils.js";
|
|
8
7
|
import type { NeedleXREventArgs } from "../engine/xr/api.js";
|
|
9
8
|
import { Behaviour, GameObject } from "./Component.js";
|
|
9
|
+
import { isDevEnvironment } from "../engine/debug/index.js";
|
|
10
10
|
|
|
11
11
|
// https://threejs.org/examples/webgl_shadowmap_csm.html
|
|
12
12
|
|
|
@@ -135,7 +135,10 @@ export class Light extends Behaviour implements ILight {
|
|
|
135
135
|
this._type = value;
|
|
136
136
|
break;
|
|
137
137
|
default:
|
|
138
|
-
|
|
138
|
+
if (debug || isDevEnvironment())
|
|
139
|
+
console.warn(`[Light] Unsupported light type: ${LightType[value]} (${value}) on '${this.name}'`);
|
|
140
|
+
this._type = "unsupported" as any;
|
|
141
|
+
break;
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
144
|
private _type: ILight["type"] = "point";
|
|
@@ -474,6 +477,11 @@ export class Light extends Behaviour implements ILight {
|
|
|
474
477
|
// const pointHelper = new PointLightHelper(pointLight, this.range, this.color);
|
|
475
478
|
// scene.add(pointHelper);
|
|
476
479
|
break;
|
|
480
|
+
|
|
481
|
+
default:
|
|
482
|
+
if (debug) console.warn(`[Light] Unsupported light type: ${LightType[this.type as any]} (${this.type}) on '${this.name}'`);
|
|
483
|
+
break;
|
|
484
|
+
|
|
477
485
|
}
|
|
478
486
|
}
|
|
479
487
|
|
|
@@ -37,7 +37,7 @@ const debug = getParam("debugnet");
|
|
|
37
37
|
* @see {@link RoomEvents} for room lifecycle events
|
|
38
38
|
* @see {@link isLocalNetwork} for local network detection
|
|
39
39
|
* @link https://engine.needle.tools/docs/how-to-guides/networking/
|
|
40
|
-
* @summary
|
|
40
|
+
* @summary Configures the websocket server URL for multiplayer networking
|
|
41
41
|
* @category Networking
|
|
42
42
|
* @group Components
|
|
43
43
|
*/
|