@needle-tools/engine 4.3.2-beta.2 → 4.3.2-beta.4

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/gltf-progressive.js +91 -90
  3. package/dist/gltf-progressive.light.js +91 -90
  4. package/dist/gltf-progressive.light.min.js +6 -6
  5. package/dist/gltf-progressive.light.umd.cjs +4 -4
  6. package/dist/gltf-progressive.min.js +6 -6
  7. package/dist/gltf-progressive.umd.cjs +4 -4
  8. package/dist/needle-engine.bundle.js +2999 -2990
  9. package/dist/needle-engine.bundle.light.js +3038 -3029
  10. package/dist/needle-engine.bundle.light.min.js +112 -112
  11. package/dist/needle-engine.bundle.light.umd.cjs +96 -96
  12. package/dist/needle-engine.bundle.min.js +112 -112
  13. package/dist/needle-engine.bundle.umd.cjs +99 -99
  14. package/dist/needle-engine.light.d.ts +9 -9
  15. package/lib/engine/engine_context.d.ts +3 -1
  16. package/lib/engine/engine_context.js +4 -1
  17. package/lib/engine/engine_context.js.map +1 -1
  18. package/lib/engine/engine_context_registry.js +7 -0
  19. package/lib/engine/engine_context_registry.js.map +1 -1
  20. package/lib/engine/engine_texture.d.ts +2 -1
  21. package/lib/engine/engine_texture.js.map +1 -1
  22. package/lib/engine/engine_tonemapping.js +2 -2
  23. package/lib/engine/engine_utils_format.js +5 -1
  24. package/lib/engine/engine_utils_format.js.map +1 -1
  25. package/lib/engine-components/Skybox.js +9 -8
  26. package/lib/engine-components/Skybox.js.map +1 -1
  27. package/package.json +2 -2
  28. package/plugins/common/license.js +42 -32
  29. package/src/engine/engine_context.ts +7 -2
  30. package/src/engine/engine_context_registry.ts +5 -0
  31. package/src/engine/engine_texture.ts +3 -2
  32. package/src/engine/engine_tonemapping.ts +2 -2
  33. package/src/engine/engine_utils_format.ts +5 -1
  34. package/src/engine-components/Skybox.ts +8 -7
@@ -1,8 +1,7 @@
1
1
  import { spawn } from "child_process";
2
- import https from 'https';
3
- import http from 'http';
4
2
 
5
3
  const port = 8424;
4
+ const packageName = "needle-cloud@version-1";
6
5
  const licenseServerUrl = `http://localhost:${port}/api/license`;
7
6
  const projectIdentifierUrl = `http://localhost:${port}/api/public_key`;
8
7
 
@@ -55,15 +54,33 @@ export async function resolveLicense(args = null) {
55
54
  console.log(`INFO: Fetching license...`);
56
55
  const licenseResponse = await fetch(url.toString(), {
57
56
  method: "GET",
58
- }).catch(console.error);
57
+ }).catch(err => {
58
+ if (err.cause.code === "ECONNREFUSED") {
59
+ return { error: "ERR: Failed to connect to license server (ECONNREFUSED)" };
60
+ }
61
+ else {
62
+ return { error: "ERR: Failed to fetch license." };
63
+ }
64
+ });
65
+
59
66
  if (!licenseResponse) {
60
67
  console.warn("WARN: Failed to fetch license");
61
68
  return null;
62
69
  }
70
+ else if ("error" in licenseResponse) {
71
+ console.error(licenseResponse.error);
72
+ return null;
73
+ }
74
+ else if (!licenseResponse.ok) {
75
+ console.error("ERROR: Failed to fetch license");
76
+ return null;
77
+ }
78
+
79
+ const text = await licenseResponse.text();
63
80
 
64
81
  try {
65
82
  /** @type {{needle_engine_license:string}} */
66
- const licenseJson = JSON.parse(licenseResponse);
83
+ const licenseJson = JSON.parse(text);
67
84
  console.log("\n");
68
85
  if (licenseJson.needle_engine_license) {
69
86
  console.log(`INFO: Successfully received \"${licenseJson.needle_engine_license?.toUpperCase()}\" license`)
@@ -99,14 +116,15 @@ export async function getPublicIdentifier(project_id) {
99
116
  method: "GET",
100
117
  });
101
118
 
102
- if (!res) {
119
+ if (!res || !res.ok) {
103
120
  console.warn("WARN: Failed to fetch project identifier");
104
121
  return null;
105
122
  }
123
+ const text = await res.text();
106
124
 
107
125
  try {
108
126
  /** @type {{public_key:string}} */
109
- const json = JSON.parse(res);
127
+ const json = JSON.parse(text);
110
128
  return json.public_key;
111
129
  }
112
130
  catch (err) {
@@ -121,7 +139,7 @@ export async function getPublicIdentifier(project_id) {
121
139
  // we need to to wait for the root URL to return a response
122
140
  async function waitForLicenseServer() {
123
141
  // Make sure the licensing server is running
124
- runCommand("npx", ["--yes", "needle-cloud@main", "start-server"]);
142
+ runCommand("npx", ["--yes", packageName, "start-server"]);
125
143
 
126
144
  let attempts = 0;
127
145
  while (attempts < 10) {
@@ -152,7 +170,7 @@ async function runCommand(processName, args) {
152
170
  if (code === 0) {
153
171
  resolve(true);
154
172
  } else {
155
- console.warn(`WARN: ${processName} exited with code ${code}`);
173
+ console.warn(`WARN: \"${processName}\" process exited with code ${code}\nProcess Arguments: ${args.join(" ")}`);
156
174
  resolve(false);
157
175
  }
158
176
  });
@@ -163,29 +181,21 @@ async function runCommand(processName, args) {
163
181
  }
164
182
 
165
183
 
166
- /**
167
- * @param {string} str
168
- */
169
- function obscure(str) {
170
- const start = str.substring(0, 3);
171
- return start + "******";
172
- }
173
-
174
184
 
175
185
  // NODE 16 doesn't support fetch yet
176
- function fetch(url, options) {
177
- const module = url.startsWith("https") ? https : http;
178
- return new Promise((resolve, reject) => {
179
- module.get(url, options, (res) => {
180
- let data = '';
181
- res.on('data', (chunk) => {
182
- data += chunk;
183
- });
184
- res.on('end', () => {
185
- resolve(data);
186
- });
187
- }).on("error", (err) => {
188
- reject(err);
189
- });
190
- });
191
- }
186
+ // function fetch(url, options) {
187
+ // const module = url.startsWith("https") ? https : http;
188
+ // return new Promise((resolve, reject) => {
189
+ // module.get(url, options, (res) => {
190
+ // let data = '';
191
+ // res.on('data', (chunk) => {
192
+ // data += chunk;
193
+ // });
194
+ // res.on('end', () => {
195
+ // resolve(data);
196
+ // });
197
+ // }).on("error", (err) => {
198
+ // reject(err);
199
+ // });
200
+ // });
201
+ // }
@@ -10,6 +10,7 @@ import {
10
10
  /** @ts-ignore (not yet in types?) */
11
11
  import { BasicNodeLibrary } from "three";
12
12
  import * as Stats from 'three/examples/jsm/libs/stats.module.js';
13
+ import type { EffectComposer as ThreeEffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
13
14
  import { nodeFrame } from "three/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodeBuilder.js";
14
15
 
15
16
  import { isDevEnvironment, LogType, showBalloonError, showBalloonMessage } from './debug/index.js';
@@ -188,6 +189,10 @@ export class Context implements IContext {
188
189
  ContextRegistry.Current = context;
189
190
  }
190
191
 
192
+ static get All(): Context[] {
193
+ return ContextRegistry.All as Context[];
194
+ }
195
+
191
196
  /** The name of the context */
192
197
  name: string;
193
198
  /** An alias for the context */
@@ -317,7 +322,7 @@ export class Context implements IContext {
317
322
 
318
323
  scene: Scene;
319
324
  renderer!: WebGLRenderer;
320
- composer: EffectComposer | null = null;
325
+ composer: EffectComposer | ThreeEffectComposer | null = null;
321
326
 
322
327
  // all scripts
323
328
  readonly scripts: IComponent[] = [];
@@ -1450,7 +1455,7 @@ export class Context implements IContext {
1450
1455
 
1451
1456
  if (this.composer && !this.isInXR) {
1452
1457
  // if a camera is passed in we need to check if we need to update the composer's camera
1453
- if (camera) {
1458
+ if (camera && "setMainCamera" in this.composer) {
1454
1459
  const currentPassesCamera = this.composer.passes[0]?.mainCamera;
1455
1460
  if (currentPassesCamera != camera)
1456
1461
  this.composer.setMainCamera(camera);
@@ -1,5 +1,7 @@
1
1
  import { type IComponent, type IContext, type LoadedModel } from "./engine_types.js";
2
2
 
3
+ const debug = typeof window !== undefined ? window.location.search.includes("debugcontext") : false;
4
+
3
5
  /** The various events that can be dispatched by a Needle Engine {@link IContext} instance
4
6
  */
5
7
  export enum ContextEvent {
@@ -62,6 +64,8 @@ export class ContextRegistry {
62
64
 
63
65
  /** @internal Internal use only */
64
66
  static register(ctx: IContext) {
67
+ if (this.Registered.indexOf(ctx) !== -1) return;
68
+ if (debug) console.warn("Registering context");
65
69
  this.Registered.push(ctx);
66
70
  this.dispatchCallback(ContextEvent.ContextRegistered, ctx);
67
71
  }
@@ -70,6 +74,7 @@ export class ContextRegistry {
70
74
  static unregister(ctx: IContext) {
71
75
  const index = this.Registered.indexOf(ctx);
72
76
  if (index === -1) return;
77
+ if (debug) console.warn("Unregistering context");
73
78
  this.Registered.splice(index, 1);
74
79
  }
75
80
 
@@ -1,5 +1,6 @@
1
1
  import type { EffectComposer } from "postprocessing";
2
2
  import { Camera, Mesh, Object3D, Texture, WebGLRenderer, WebGLRenderTarget } from "three";
3
+ import type { EffectComposer as ThreeEffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
3
4
 
4
5
  import { findResourceUsers } from "./engine_assetdatabase.js";
5
6
 
@@ -27,9 +28,9 @@ export class RenderTexture extends WebGLRenderTarget {
27
28
  * @param camera The camera to render from
28
29
  * @param renderer The renderer or effectcomposer to use
29
30
  */
30
- render(scene: Object3D, camera: Camera, renderer: WebGLRenderer | EffectComposer) {
31
+ render(scene: Object3D, camera: Camera, renderer: WebGLRenderer | EffectComposer | ThreeEffectComposer) {
31
32
 
32
- const composer = renderer as EffectComposer;
33
+ const composer = renderer as (EffectComposer | ThreeEffectComposer);
33
34
 
34
35
  if ("addPass" in composer) {
35
36
  if (!this["_unsupported_effectcomposer_warning"]) {
@@ -87,8 +87,8 @@ vec3 _agx(vec3 val) {
87
87
  0.0784335999999992, 0.878468636469772, 0.0784336,
88
88
  0.0792237451477643, 0.0791661274605434, 0.879142973793104);
89
89
 
90
- const float min_ev = -12.47393f;
91
- const float max_ev = 4.026069f;
90
+ const float min_ev = -12.47393;
91
+ const float max_ev = 4.026069;
92
92
 
93
93
  // val = pow(val, vec3(2.2));
94
94
 
@@ -61,7 +61,11 @@ export async function tryDetermineFileTypeFromURL(url: string, useExtension: boo
61
61
 
62
62
  // If the URL doesnt contain a filetype we need to check the header
63
63
  // This is the case for example if we load a file from a data url
64
- const header = await fetch(url, {
64
+ const newUrl = new URL(url);
65
+ // Adding a URL parameter to avoid the brower to bust the full cache
66
+ // If we don't do this the file that might already be disc cached will be deleted from the cache
67
+ newUrl.searchParams.append("range", "true");
68
+ const header = await fetch(newUrl, {
65
69
  method: "GET",
66
70
  headers: {
67
71
  "range": "bytes=0-32"
@@ -5,7 +5,7 @@ import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader.js";
5
5
  import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
6
6
 
7
7
  import { disposeObjectResources, setDisposable } from "../engine/engine_assetdatabase.js";
8
- import { ContextRegistry } from "../engine/engine_context_registry.js";
8
+ import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry.js";
9
9
  import { registerObservableAttribute } from "../engine/engine_element_extras.js";
10
10
  import { syncField } from "../engine/engine_networking_auto.js";
11
11
  import { serializable } from "../engine/engine_serialization_decorator.js";
@@ -39,11 +39,11 @@ function createRemoteSkyboxComponent(context: IContext, url: string, skybox: boo
39
39
  return remote.setSkybox(url);
40
40
  }
41
41
 
42
- ContextRegistry.addContextCreatedCallback((args) => {
42
+ const promises = new Array<Promise<any>>();
43
+ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, (args) => {
43
44
  const context = args.context;
44
45
  const skyboxImage = context.domElement.getAttribute("skybox-image") || context.domElement.getAttribute("background-image");
45
46
  const environmentImage = context.domElement.getAttribute("environment-image");
46
- const promises = new Array<Promise<any>>();
47
47
  if (skyboxImage) {
48
48
  if (debug)
49
49
  console.log("Creating remote skybox to load " + skyboxImage);
@@ -60,10 +60,11 @@ ContextRegistry.addContextCreatedCallback((args) => {
60
60
  const promise = createRemoteSkyboxComponent(context, environmentImage, false, true, "environment-image");
61
61
  promises.push(promise);
62
62
  }
63
- if (promises.length > 0) {
64
- return PromiseAllWithErrors(promises);
65
- }
66
- return Promise.resolve();
63
+ });
64
+ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, () => {
65
+ return Promise.all(promises).finally(() => {
66
+ promises.length = 0;
67
+ })
67
68
  });
68
69
 
69
70
  declare type SkyboxCacheEntry = { src: string, texture: Promise<Texture> };