@needle-tools/engine 3.2.13-alpha → 3.2.14-alpha

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "3.2.13-alpha",
3
+ "version": "3.2.14-alpha",
4
4
  "description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in",
5
5
  "main": "dist/needle-engine.umd.cjs",
6
6
  "type": "module",
@@ -61,7 +61,7 @@
61
61
  "postprocessing": "^6.30.1",
62
62
  "simplex-noise": "^4.0.1",
63
63
  "stats.js": "^0.17.0",
64
- "three": "npm:@needle-tools/three@^0.146.6",
64
+ "three": "npm:@needle-tools/three@^0.146.8",
65
65
  "three-mesh-ui": "^6.4.5",
66
66
  "three.quarks": "^0.7.3",
67
67
  "uuid": "^9.0.0",
@@ -95,6 +95,7 @@ import { Networking } from "../../engine-components/Networking";
95
95
  import { NoiseModule } from "../../engine-components/ParticleSystemModules";
96
96
  import { ObjectRaycaster } from "../../engine-components/ui/Raycaster";
97
97
  import { OffsetConstraint } from "../../engine-components/OffsetConstraint";
98
+ import { OpenURL } from "../../engine-components/utils/OpenURL";
98
99
  import { OrbitControls } from "../../engine-components/OrbitControls";
99
100
  import { ParticleBurst } from "../../engine-components/ParticleSystemModules";
100
101
  import { ParticleSubEmitter } from "../../engine-components/ParticleSystemSubEmitter";
@@ -284,6 +285,7 @@ TypeStore.add("Networking", Networking);
284
285
  TypeStore.add("NoiseModule", NoiseModule);
285
286
  TypeStore.add("ObjectRaycaster", ObjectRaycaster);
286
287
  TypeStore.add("OffsetConstraint", OffsetConstraint);
288
+ TypeStore.add("OpenURL", OpenURL);
287
289
  TypeStore.add("OrbitControls", OrbitControls);
288
290
  TypeStore.add("ParticleBurst", ParticleBurst);
289
291
  TypeStore.add("ParticleSubEmitter", ParticleSubEmitter);
@@ -93,6 +93,7 @@ export { Networking } from "../Networking";
93
93
  export { NoiseModule } from "../ParticleSystemModules";
94
94
  export { ObjectRaycaster } from "../ui/Raycaster";
95
95
  export { OffsetConstraint } from "../OffsetConstraint";
96
+ export { OpenURL } from "../utils/OpenURL";
96
97
  export { OrbitControls } from "../OrbitControls";
97
98
  export { ParticleBurst } from "../ParticleSystemModules";
98
99
  export { ParticleSubEmitter } from "../ParticleSystemSubEmitter";
@@ -1,6 +1,5 @@
1
1
  import { delay, getParam, isiOS, isMobileDevice, isSafari } from "../../../engine/engine_utils";
2
- import { Object3D, Color } from "three";
3
- import * as THREE from "three";
2
+ import { Object3D, Color, Mesh, Matrix4 } from "three";
4
3
  import { USDZExporter as ThreeUSDZExporter } from "three/examples/jsm/exporters/USDZExporter";
5
4
  import { AnimationExtension } from "./extensions/Animation"
6
5
  import { ensureQuicklookLinkIsCreated } from "./utils/quicklook";
@@ -72,7 +71,7 @@ export class USDZExporter extends Behaviour {
72
71
  if (!this.objectToExport) this.objectToExport = this.gameObject;
73
72
 
74
73
 
75
- if (isDevEnvironment() && (!this.objectToExport || this.objectToExport.children.length <= 0)) {
74
+ if (isDevEnvironment() && (!this.objectToExport?.children?.length && !(this.objectToExport as Mesh)?.isMesh)) {
76
75
  showBalloonWarning("USDZ Exporter has nothing to export");
77
76
  console.warn("USDZExporter has no objects to export assigned:", this)
78
77
  }
@@ -114,7 +113,7 @@ export class USDZExporter extends Behaviour {
114
113
  const scale = 1 / this.webARSessionRoot!.arScale;
115
114
  scene.matrix.makeScale(scale, scale, scale);
116
115
  if (this.webARSessionRoot.invertForward) {
117
- scene.matrix.multiply(new THREE.Matrix4().makeRotationY(Math.PI));
116
+ scene.matrix.multiply(new Matrix4().makeRotationY(Math.PI));
118
117
  }
119
118
  }
120
119
 
@@ -6,14 +6,14 @@ import * as ThreeMeshUI from 'three-mesh-ui'
6
6
  import { Context } from "../../engine/engine_setup";
7
7
  import { OrbitControls } from "../OrbitControls";
8
8
  import { IPointerEventHandler, PointerEventData } from "./PointerEvents";
9
- import { Raycaster } from "./Raycaster";
9
+ import { ObjectRaycaster, Raycaster } from "./Raycaster";
10
10
  import { InputEvents } from "../../engine/engine_input";
11
11
  import { Object3D } from "three";
12
12
  import { ICanvasGroup, IGraphic } from "./Interfaces";
13
13
  import { getParam } from "../../engine/engine_utils";
14
14
  import { UIRaycastUtils } from "./RaycastUtils";
15
15
  import { $shadowDomOwner } from "./BaseUIComponent";
16
- import { showBalloonMessage, showBalloonWarning } from "../../engine/debug";
16
+ import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../../engine/debug";
17
17
 
18
18
  const debug = getParam("debugeventsystem");
19
19
 
@@ -86,9 +86,15 @@ export class EventSystem extends Behaviour {
86
86
  }
87
87
 
88
88
  start() {
89
- // const res = GameObject.findObjectsOfType(Raycaster, this.context);
90
- // if (res)
91
- // this.raycaster = [...res];
89
+ if (this.raycaster.length <= 0) {
90
+ const res = GameObject.findObjectOfType(Raycaster, this.context);
91
+ if (!res) {
92
+ const rc = GameObject.addNewComponent(this.context.scene, ObjectRaycaster);
93
+ this.raycaster.push(rc);
94
+ if (isDevEnvironment())
95
+ console.warn("Added an ObjectRaycaster to the scene because no raycaster was found", this);
96
+ }
97
+ }
92
98
  }
93
99
 
94
100
  register(rc: Raycaster) {
@@ -0,0 +1,119 @@
1
+
2
+ import { IPointerClickHandler, PointerEventData } from "../ui";
3
+ import { Behaviour } from "../Component";
4
+ import { serializable } from "../../engine/engine_serialization";
5
+ import { isDevEnvironment, showBalloonMessage } from "../../engine/debug";
6
+ import { isSafari } from "../../engine/engine_utils";
7
+ import { ObjectRaycaster, Raycaster } from "../ui/Raycaster";
8
+ import { tryGetUIComponent } from "../ui/Utils";
9
+
10
+ export enum OpenURLMode {
11
+ NewTab = 0,
12
+ SameTab = 1,
13
+ NewWindow = 2
14
+ }
15
+
16
+ export class OpenURL extends Behaviour implements IPointerClickHandler {
17
+
18
+ @serializable()
19
+ clickable: boolean = true;
20
+
21
+ @serializable()
22
+ url?: string;
23
+
24
+ @serializable()
25
+ mode: OpenURLMode = OpenURLMode.NewTab;
26
+
27
+ async open() {
28
+ if (!this.url) {
29
+ console.error("URL is not set", this);
30
+ return;
31
+ }
32
+
33
+ this._validateUrl();
34
+
35
+ if (isDevEnvironment()) showBalloonMessage("Open URL: " + this.url)
36
+
37
+
38
+ switch (this.mode) {
39
+ case OpenURLMode.NewTab:
40
+ if (isSafari()) {
41
+ globalThis.open(this.url, "_blank");
42
+ }
43
+ else
44
+ globalThis.open(this.url, "_blank");
45
+ break;
46
+ case OpenURLMode.SameTab:
47
+ if (isSafari()) {
48
+ globalThis.open(this.url, "_top");
49
+ }
50
+ else globalThis.open(this.url, "_self");
51
+ break;
52
+ case OpenURLMode.NewWindow:
53
+ if (isSafari()) {
54
+ globalThis.open(this.url, "_top");
55
+ }
56
+ else globalThis.open(this.url, "_new");
57
+ break;
58
+
59
+ }
60
+ }
61
+
62
+ start(): void {
63
+ const raycaster = this.gameObject.getComponentInParent(ObjectRaycaster);
64
+ if (!raycaster) this.gameObject.addNewComponent(ObjectRaycaster);
65
+ }
66
+
67
+ onEnable(): void {
68
+ if (isSafari()) window.addEventListener("touchend", this._safariNewTabWorkaround);
69
+ }
70
+ onDisable(): void {
71
+ if (isSafari()) window.removeEventListener("touchend", this._safariNewTabWorkaround);
72
+ }
73
+
74
+ onPointerEnter(args) {
75
+ if (!args.used && this.clickable)
76
+ this.context.input.setCursorPointer();
77
+ }
78
+ onPointerExit() {
79
+ if (this.clickable)
80
+ this.context.input.setCursorNormal();
81
+ }
82
+ onPointerClick(args: PointerEventData) {
83
+ if (this.clickable && !args.used && this.url?.length)
84
+ this.open();
85
+ }
86
+
87
+ private _safariNewTabWorkaround = () => {
88
+ if (!this.clickable || !this.url?.length) return;
89
+ // we only need this workaround for opening a new tab
90
+ if (this.mode === OpenURLMode.SameTab) return;
91
+ // When we process the click directly in the browser event we can open a new tab
92
+ // by emitting a link attribute and calling onClick
93
+ const raycaster = this.gameObject.getComponentInParent(Raycaster);
94
+ if (raycaster) {
95
+ const hits = raycaster.performRaycast();
96
+ if (!hits) return;
97
+ for (const hit of hits) {
98
+ if (hit.object === this.gameObject || tryGetUIComponent(hit.object)?.gameObject === this.gameObject) {
99
+ this._validateUrl();
100
+ var a = document.createElement('a') as HTMLAnchorElement;
101
+ a.setAttribute("target", "_blank");
102
+ a.setAttribute("href", this.url);
103
+ a.click();
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ private _validateUrl() {
111
+ if (!this.url) return;
112
+ if (this.url.startsWith("www.")) {
113
+ if (isDevEnvironment()) {
114
+ console.warn("URL is not valid, adding https:// to the start of the URL", this.url);
115
+ }
116
+ this.url = "https://" + this.url;
117
+ }
118
+ }
119
+ }