@needle-tools/engine 4.3.2-beta.3 → 4.3.2-beta.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.
@@ -45,20 +45,6 @@ export const needleAsap = async (command, config, userSettings) => {
45
45
  /** @type {import('vite').HtmlTagDescriptor[]} */
46
46
  const tags = [];
47
47
 
48
- if (logoSvg?.length) {
49
- tags.push({
50
- tag: 'link',
51
- attrs: {
52
- rel: "preload",
53
- fetchpriority: "high",
54
- as: "image",
55
- href: logoSvg,
56
- type: "image/svg+xml",
57
- }
58
- })
59
- }
60
-
61
-
62
48
  try {
63
49
  generateGltfPreloadLinks(config, html, tags);
64
50
  }
@@ -82,6 +68,20 @@ export const needleAsap = async (command, config, userSettings) => {
82
68
  }
83
69
  });
84
70
 
71
+ // we insert the logo late because the logo svg string is quite long
72
+ if (logoSvg?.length) {
73
+ tags.push({
74
+ tag: 'link',
75
+ attrs: {
76
+ rel: "preload",
77
+ fetchpriority: "high",
78
+ as: "image",
79
+ href: logoSvg,
80
+ type: "image/svg+xml",
81
+ }
82
+ })
83
+ }
84
+
85
85
  return {
86
86
  html,
87
87
  tags
@@ -206,6 +206,18 @@ function generateGltfPreloadLinks(config, html, tags) {
206
206
  if (match.done) break;
207
207
  const value = match.value?.groups?.gltf;
208
208
  if (value) {
209
+ // if it's not a url we need to check if the file exists
210
+ const isUrl = value.startsWith("http");
211
+ if (!isUrl) {
212
+ let filepath = value.split("?")[0];
213
+ filepath = decodeURIComponent(filepath);
214
+ const fullpath = path.join(process.cwd(), filepath);
215
+ if (!existsSync(fullpath)) {
216
+ console.warn(`[needle:asap] Could not insert head preload link: file not found at \"${filepath}\"`);
217
+ continue;
218
+ }
219
+ }
220
+ console.log(`[needle:asap] Insert head glTF preload link: ${value}`);
209
221
  insertPreloadLink(tags, value, "model/gltf+json");
210
222
  }
211
223
  }
@@ -161,7 +161,7 @@ function testIfInstallIsRequired(projectDir, packageJson) {
161
161
  expectedVersion = value;
162
162
  }
163
163
  if (expectedVersion?.length > 0) {
164
- const isRange = expectedVersion.includes("^") || expectedVersion.includes(">") || expectedVersion.includes("<") || expectedVersion.includes("~");
164
+ const isRange = expectedVersion.includes("x") || expectedVersion.includes("^") || expectedVersion.includes(">") || expectedVersion.includes("<") || expectedVersion.includes("~");
165
165
  const isLatest = expectedVersion === "latest";
166
166
  if (!isRange && !isLatest) {
167
167
  const packageJsonPath = path.join(depPath, "package.json");
@@ -189,6 +189,10 @@ export class Context implements IContext {
189
189
  ContextRegistry.Current = context;
190
190
  }
191
191
 
192
+ static get All(): Context[] {
193
+ return ContextRegistry.All as Context[];
194
+ }
195
+
192
196
  /** The name of the context */
193
197
  name: string;
194
198
  /** An alias for the context */
@@ -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
 
@@ -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> };