@needle-tools/engine 4.16.4-next.90e872e → 4.16.4-next.d7334fa
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 +5 -0
- package/dist/gltf-progressive-BJ9OrddA.js +28272 -0
- package/dist/gltf-progressive-Ck_bXBr_.umd.cjs +4022 -0
- package/dist/gltf-progressive-CqZYu6Hx.min.js +4022 -0
- package/dist/loader.worker-CCrD-Ycm.js +3 -0
- package/dist/{materialx-CT8J50pg.js → materialx-CEJOMiVq.js} +6 -7
- package/dist/{materialx-BrPdNmQT.umd.cjs → materialx-CN_PDqtU.umd.cjs} +1 -1
- package/dist/{materialx-D_ofN96q.min.js → materialx-DZYSWLvT.min.js} +1 -1
- package/dist/{needle-engine.bundle-dWi9rwQU.umd.cjs → needle-engine.bundle-7jhrheqM.umd.cjs} +159 -159
- package/dist/{needle-engine.bundle-j_dgrIWR.min.js → needle-engine.bundle-B1vy0_5d.min.js} +137 -137
- package/dist/{needle-engine.bundle-CTDEd5SB.js → needle-engine.bundle-BVUJloKV.js} +4192 -4185
- package/dist/needle-engine.d.ts +59 -53
- package/dist/needle-engine.js +3 -3
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/three-examples.js +3294 -4643
- package/dist/three-examples.min.js +13 -47
- package/dist/three-examples.umd.cjs +12 -46
- package/dist/three.js +24892 -15999
- package/dist/three.min.js +214 -214
- package/dist/three.umd.cjs +208 -208
- package/dist/{vendor-DZ45lcA8.min.js → vendor-BPp9F5vR.min.js} +19 -19
- package/dist/{vendor-BsRxp-FT.js → vendor-CQMI3jTS.js} +862 -901
- package/dist/{vendor-BwxpsdCm.umd.cjs → vendor-CipoooTV.umd.cjs} +20 -20
- package/lib/engine/engine_feature_flags.d.ts +3 -3
- package/lib/engine/engine_feature_flags.js +3 -5
- package/lib/engine/engine_feature_flags.js.map +1 -1
- package/lib/engine/engine_lods.d.ts +9 -1
- package/lib/engine/engine_lods.js +9 -1
- package/lib/engine/engine_lods.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +49 -60
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_modules.d.ts +26 -30
- package/lib/engine/engine_modules.js +32 -103
- package/lib/engine/engine_modules.js.map +1 -1
- package/lib/engine/engine_three_utils.js +7 -13
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +6 -2
- package/lib/engine/webcomponents/needle-engine.js +56 -41
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/package.json +3 -2
- package/plugins/vite/alias.d.ts +1 -1
- package/plugins/vite/alias.js +87 -82
- package/plugins/vite/build-pipeline.js +4 -3
- package/plugins/vite/dependencies.js +7 -5
- package/plugins/vite/drop.js +6 -8
- package/plugins/vite/editor-connection.js +2 -1
- package/plugins/vite/index.js +12 -0
- package/plugins/vite/poster.js +2 -1
- package/plugins/vite/reload.js +7 -2
- package/src/engine/engine_feature_flags.ts +3 -7
- package/src/engine/engine_lods.ts +10 -2
- package/src/engine/engine_mainloop_utils.ts +54 -62
- package/src/engine/engine_modules.ts +39 -101
- package/src/engine/engine_three_utils.ts +7 -15
- package/src/engine/webcomponents/needle-engine.ts +62 -47
- package/dist/gltf-progressive-DQa78GTA.min.js +0 -10
- package/dist/gltf-progressive-LOFTyzy4.umd.cjs +0 -10
- package/dist/gltf-progressive-_wvokUUu.js +0 -1528
- package/dist/loader.worker-BqODMeeW.js +0 -23
package/plugins/vite/alias.js
CHANGED
|
@@ -1,50 +1,46 @@
|
|
|
1
|
-
import { createWriteStream, existsSync, mkdirSync
|
|
1
|
+
import { createWriteStream, existsSync, mkdirSync } from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { needleLog } from './logging.js';
|
|
4
4
|
|
|
5
5
|
const projectDir = process.cwd() + "/";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @typedef {"auto-resolve" | ((res: string, packageName: string, index: number,
|
|
8
|
+
* @typedef {"auto-resolve" | ((res: string, packageName: string, index: number, importPath: string) => string | null | void)} PackageResolveValue
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
/** these are alias callbacks as in the vite.alias dictionary
|
|
12
|
-
* the first argument is the already resoled absolute path (it is only invoked if the path was found in node_modules)
|
|
13
|
-
* the 2,3,4 args are the same as in vite.alias (packageName, index, path);
|
|
14
|
-
*/
|
|
15
11
|
/**
|
|
16
12
|
* @type {Record<string, PackageResolveValue>}
|
|
17
13
|
*/
|
|
18
14
|
const packages_to_resolve = {
|
|
19
15
|
// We are currently overriding "three" resolution to ensure that all dependencies resolve to the same three.js version.
|
|
20
|
-
// This is hacky, but the alternative is potentially having conflicting three.js versions since some packages are
|
|
16
|
+
// This is hacky, but the alternative is potentially having conflicting three.js versions since some packages are
|
|
21
17
|
// stubborn with their peer dependencies or just slow (slower as we) with updating.
|
|
22
18
|
// NOT adding this allows node.js to correctly resolve `exports` specified in three.js package.json;
|
|
23
19
|
// since we're overriding resolution here we need to manually resolve the subset of exports that we use.
|
|
24
|
-
'three/addons': (res, packageName, index,
|
|
20
|
+
'three/addons': (res, packageName, index, importPath) => {
|
|
25
21
|
return "three/examples/jsm";
|
|
26
22
|
},
|
|
27
|
-
'three/nodes': (res, packageName, index,
|
|
23
|
+
'three/nodes': (res, packageName, index, importPath) => {
|
|
28
24
|
return "three/examples/jsm/nodes/Nodes.js";
|
|
29
25
|
},
|
|
30
26
|
'three': "auto-resolve",
|
|
31
27
|
|
|
32
28
|
// Handle all previous imports where users did import using @needle-engine/src
|
|
33
|
-
'@needle-tools/engine/src': (res, packageName, index,
|
|
29
|
+
'@needle-tools/engine/src': (res, packageName, index, importPath) => {
|
|
34
30
|
// resolve old engine/src imports UNLESS it's the asap plugin (the asap plugin currently only exists in the src folder)
|
|
35
|
-
if (!
|
|
31
|
+
if (!importPath.startsWith("@needle-tools/engine/src/asap")) {
|
|
36
32
|
return res + "/../lib";
|
|
37
33
|
}
|
|
38
34
|
},
|
|
39
|
-
/*
|
|
40
|
-
Removed the previously present @needle-tools/engine entry
|
|
35
|
+
/*
|
|
36
|
+
Removed the previously present @needle-tools/engine entry
|
|
41
37
|
because this is automatically done by vite according to whatever we define in our package.json exports
|
|
42
38
|
This did previously prevent us from declaring proper exports in package.json
|
|
43
39
|
*/
|
|
44
|
-
'@needle-tools/engine': (res, packageName, index,
|
|
40
|
+
'@needle-tools/engine': (res, packageName, index, importPath) => {
|
|
45
41
|
// Check if the import is something like @needle-tools/engine/engine/engine_utils
|
|
46
42
|
// in which case we want to resolve into the lib directory
|
|
47
|
-
if (
|
|
43
|
+
if (importPath.startsWith("@needle-tools/engine/engine")) {
|
|
48
44
|
return res + "/lib";
|
|
49
45
|
}
|
|
50
46
|
const node_modules_path = path.resolve(projectDir, 'node_modules', '@needle-tools/engine');
|
|
@@ -60,10 +56,6 @@ const packages_to_resolve = {
|
|
|
60
56
|
'three-mesh-bvh': "auto-resolve",
|
|
61
57
|
'postprocessing': "auto-resolve",
|
|
62
58
|
'@dimforge/rapier3d-compat': "auto-resolve",
|
|
63
|
-
|
|
64
|
-
// Note: this isnt necessary anymore since we exclude needle-engine from optimization when locally installed in the dev server
|
|
65
|
-
// '@needle-tools/gltf-progressive': "auto-resolve",
|
|
66
|
-
// '@needle-tools/materialx': "auto-resolve",
|
|
67
59
|
}
|
|
68
60
|
|
|
69
61
|
/**
|
|
@@ -98,32 +90,91 @@ export function needleViteAlias(command, config, userSettings) {
|
|
|
98
90
|
log("Logging to:", outputFilePath);
|
|
99
91
|
}
|
|
100
92
|
|
|
93
|
+
// Pre-compute resolved paths for each package
|
|
94
|
+
/** @type {Array<{name: string, fullpath: string, pathExists: boolean, isNestedInEngine: boolean, callback: ((res: string, packageName: string, index: number, importPath: string) => string | null | void) | null}>} */
|
|
95
|
+
const resolvers = [];
|
|
96
|
+
/** @type {Array<{find: string, replacement: string}>} Aliases for nested engine auto-resolve packages */
|
|
97
|
+
const nestedAliases = [];
|
|
98
|
+
for (const name in packages_to_resolve) {
|
|
99
|
+
const value = packages_to_resolve[name];
|
|
100
|
+
const callback = typeof value === "function" ? value : null;
|
|
101
|
+
const isAutoResolve = value === "auto-resolve";
|
|
102
|
+
|
|
103
|
+
let fullpath = path.resolve(projectDir, 'node_modules', name);
|
|
104
|
+
let isNestedInEngine = false;
|
|
105
|
+
{
|
|
106
|
+
const pathInEngine = path.resolve(projectDir, 'node_modules', "@needle-tools/engine", "node_modules", name);
|
|
107
|
+
if (existsSync(pathInEngine)) {
|
|
108
|
+
fullpath = pathInEngine;
|
|
109
|
+
isNestedInEngine = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const pathExists = existsSync(fullpath);
|
|
113
|
+
resolvers.push({ name, fullpath, pathExists, isNestedInEngine, callback });
|
|
114
|
+
|
|
115
|
+
// For auto-resolve packages nested in the engine, use resolve.alias so both
|
|
116
|
+
// the optimizer and resolveId see the same path. This ensures Vite pre-bundles
|
|
117
|
+
// these deps (handling CJS interop) while keeping a single copy.
|
|
118
|
+
if (isAutoResolve && isNestedInEngine && pathExists) {
|
|
119
|
+
nestedAliases.push({ find: name, replacement: fullpath });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const workingDirectory = `${process.cwd()}/`;
|
|
101
124
|
|
|
102
125
|
/** @type {import("vite").Plugin} */
|
|
103
126
|
const aliasPlugin = {
|
|
104
127
|
name: "needle-alias",
|
|
128
|
+
// Register resolve.alias for nested engine packages so Vite's optimizer
|
|
129
|
+
// can find and pre-bundle them (with proper CJS interop).
|
|
105
130
|
config(config) {
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
131
|
+
if (nestedAliases.length > 0) {
|
|
132
|
+
if (!config.resolve) config.resolve = {};
|
|
133
|
+
// resolve.alias can be an array of {find,replacement} or a Record<string,string>.
|
|
134
|
+
// Convert to array format if needed (works in Vite 2-8).
|
|
135
|
+
if (!config.resolve.alias) {
|
|
136
|
+
config.resolve.alias = [];
|
|
137
|
+
}
|
|
138
|
+
else if (!Array.isArray(config.resolve.alias)) {
|
|
139
|
+
// Convert Record<string,string> to array format
|
|
140
|
+
const entries = Object.entries(config.resolve.alias);
|
|
141
|
+
config.resolve.alias = entries.map(([find, replacement]) => ({ find, replacement }));
|
|
142
|
+
}
|
|
143
|
+
for (const alias of nestedAliases) {
|
|
144
|
+
config.resolve.alias.push(alias);
|
|
145
|
+
needleLog("needle-alias", `Adding resolve.alias: ${alias.find} → ${alias.replacement.split('node_modules/').pop()}`);
|
|
114
146
|
}
|
|
115
147
|
}
|
|
148
|
+
},
|
|
149
|
+
// Use resolveId instead of resolve.alias to support both Rollup and Rolldown (Vite 8+).
|
|
150
|
+
// Rolldown does not support function-based alias replacements.
|
|
151
|
+
enforce: 'pre',
|
|
152
|
+
async resolveId(id, _importer, _options) {
|
|
153
|
+
for (const { name, fullpath, pathExists, isNestedInEngine, callback } of resolvers) {
|
|
154
|
+
// Check if import matches this resolver (exact match or starts with name/)
|
|
155
|
+
if (id !== name && !id.startsWith(name + '/')) continue;
|
|
156
|
+
|
|
157
|
+
if (callback !== null) {
|
|
158
|
+
const overrideResult = callback(fullpath, name, 0, id);
|
|
159
|
+
if (typeof overrideResult === "string") {
|
|
160
|
+
if (debug) log(`Redirecting "${id}" → "${overrideResult}"`);
|
|
161
|
+
// Let Vite resolve the result further (handles directories, package.json exports, etc.)
|
|
162
|
+
return this.resolve(overrideResult, _importer, { skipSelf: true });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
116
165
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
166
|
+
// For auto-resolve packages in the project's own node_modules,
|
|
167
|
+
// let Vite handle resolution naturally (preserves CJS interop / optimizeDeps).
|
|
168
|
+
// Only redirect when the package is nested inside @needle-tools/engine/node_modules.
|
|
169
|
+
if (pathExists && (callback !== null || isNestedInEngine)) {
|
|
170
|
+
if (debug) log(`Resolved "${id}" → "${fullpath.substring(workingDirectory.length).replaceAll("\\", "/")}"`);
|
|
171
|
+
// Rewrite the import to resolve from the target directory, letting Vite handle package.json/exports
|
|
172
|
+
const subpath = id.substring(name.length); // e.g. "" or "/something"
|
|
173
|
+
const rewritten = fullpath + subpath;
|
|
174
|
+
return this.resolve(rewritten, _importer, { skipSelf: true });
|
|
125
175
|
}
|
|
126
|
-
|
|
176
|
+
|
|
177
|
+
break;
|
|
127
178
|
}
|
|
128
179
|
},
|
|
129
180
|
}
|
|
@@ -145,9 +196,6 @@ export function needleViteAlias(command, config, userSettings) {
|
|
|
145
196
|
if (importer.includes("node_modules/.vite")) importer = ".vite" + importer.split("node_modules/.vite")[1];
|
|
146
197
|
}
|
|
147
198
|
|
|
148
|
-
// could filter here, e.g. for things related to three
|
|
149
|
-
// if (id.includes("three")) return;
|
|
150
|
-
|
|
151
199
|
// verbose logging for all imports
|
|
152
200
|
if (lastImporter !== importer) {
|
|
153
201
|
lastImporter = importer;
|
|
@@ -159,47 +207,4 @@ export function needleViteAlias(command, config, userSettings) {
|
|
|
159
207
|
}
|
|
160
208
|
if (debug) return [debuggingPlugin, aliasPlugin];
|
|
161
209
|
return [aliasPlugin];
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Adds a path resolver to the alias dictionary.
|
|
166
|
-
* @param {string} name - The name of the package to resolve.
|
|
167
|
-
* @param {import("vite").AliasOptions} aliasDict - The alias dictionary to add the resolver to.
|
|
168
|
-
* @param {PackageResolveValue | null} value - A callback function to override the default resolution behavior.
|
|
169
|
-
* @param {boolean} debug - Whether to log debug information.
|
|
170
|
-
* @returns {void}
|
|
171
|
-
*/
|
|
172
|
-
function addPathResolver(name, aliasDict, value, debug) {
|
|
173
|
-
// If a package at the node_modules path exist we resolve the request there
|
|
174
|
-
// introduced in 89a50718c38940abb99ee16c5e029065e41d7d65
|
|
175
|
-
const callback = typeof value === "function" ? value : null;
|
|
176
|
-
|
|
177
|
-
let fullpath = path.resolve(projectDir, 'node_modules', name);
|
|
178
|
-
// if (!existsSync(path.resolve(fullpath, "package.json")))
|
|
179
|
-
{
|
|
180
|
-
const pathInEngine = path.resolve(projectDir, 'node_modules', "@needle-tools/engine", "node_modules", name);
|
|
181
|
-
if (existsSync(pathInEngine)) {
|
|
182
|
-
fullpath = pathInEngine;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const workingDirectory = `${process.cwd()}/`;
|
|
187
|
-
const pathExists = existsSync(fullpath);
|
|
188
|
-
|
|
189
|
-
aliasDict[name] = (packageName, index, path) => {
|
|
190
|
-
if (callback !== null) {
|
|
191
|
-
const overrideResult = callback(fullpath, packageName, index, path);
|
|
192
|
-
if (typeof overrideResult === "string")
|
|
193
|
-
if (existsSync(overrideResult)) {
|
|
194
|
-
if (debug && overrideResult !== packageName) log(`[needle-alias] Resolved \"${path}\" → \"${overrideResult.substring(workingDirectory.length).replaceAll("\\", "/")}\"`);
|
|
195
|
-
return overrideResult;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (pathExists) {
|
|
200
|
-
if (debug && path !== packageName) log(`[needle-alias] Resolved \"${path}\" → \"${fullpath.substring(workingDirectory.length).replaceAll("\\", "/")}\"`);
|
|
201
|
-
return fullpath;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
210
|
}
|
|
@@ -130,9 +130,10 @@ export async function needleBuildPipeline(command, config, userSettings) {
|
|
|
130
130
|
if (verboseOutput) {
|
|
131
131
|
log("Apply:", env);
|
|
132
132
|
}
|
|
133
|
-
// Don't run for SSR builds (e.g. sveltekit).
|
|
134
|
-
// Unfortunately this is always
|
|
135
|
-
|
|
133
|
+
// Don't run for SSR builds (e.g. sveltekit).
|
|
134
|
+
// Unfortunately this is always false in vite 4.3 so we can not rely on it solely
|
|
135
|
+
// Vite 8+ renamed ssrBuild to isSsrBuild
|
|
136
|
+
if (env.isSsrBuild ?? env.ssrBuild) return false;
|
|
136
137
|
// Dont run if there's already a build pipeline task running
|
|
137
138
|
if (env.command === "build") {
|
|
138
139
|
increaseMaxWaitTime(verboseOutput);
|
|
@@ -103,14 +103,16 @@ function handleManualChunks(config) {
|
|
|
103
103
|
if (!config.build) {
|
|
104
104
|
config.build = {};
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
// Support both rolldownOptions (Vite 8+) and rollupOptions (Vite 7 and earlier)
|
|
107
|
+
const optionsKey = 'rolldownOptions' in (config.build) ? 'rolldownOptions' : 'rollupOptions';
|
|
108
|
+
if (!config.build[optionsKey]) {
|
|
109
|
+
config.build[optionsKey] = {};
|
|
108
110
|
}
|
|
109
|
-
if (!config.build.
|
|
110
|
-
config.build.
|
|
111
|
+
if (!config.build[optionsKey].output) {
|
|
112
|
+
config.build[optionsKey].output = {};
|
|
111
113
|
}
|
|
112
114
|
|
|
113
|
-
const rollupOutput = config.build.
|
|
115
|
+
const rollupOutput = config.build[optionsKey].output;
|
|
114
116
|
|
|
115
117
|
if (Array.isArray(rollupOutput)) {
|
|
116
118
|
// append the manualChunks function to the array
|
package/plugins/vite/drop.js
CHANGED
|
@@ -42,16 +42,14 @@ export function needleDrop(command, config, userSettings) {
|
|
|
42
42
|
];
|
|
43
43
|
},
|
|
44
44
|
},
|
|
45
|
-
configureServer(/** @type {
|
|
45
|
+
configureServer(/** @type {import('vite').ViteDevServer} */ server) {
|
|
46
|
+
const hot = server.hot ?? server.ws;
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
hot.on('needle:drop-file', async (/** @type {unknown} */ data, /** @type {unknown} */ client) => {
|
|
49
|
+
hot.send('needle-editor:drop-file', data);
|
|
49
50
|
});
|
|
50
|
-
// TODO: not sure how we can receive it with the normal vite server
|
|
51
|
-
// server.ws.on("custom", (data, client) => {
|
|
52
|
-
// console.log(data);
|
|
53
|
-
// })
|
|
54
51
|
|
|
52
|
+
// Raw WebSocket access for editor messages
|
|
55
53
|
server.ws.on('connection', (/** @type {{ on(event: string, cb: (...args: unknown[]) => void): void }} */ socket, /** @type {unknown} */ request) => {
|
|
56
54
|
socket.on('message', async (/** @type {Buffer | string} */ bytes) => {
|
|
57
55
|
try {
|
|
@@ -59,7 +57,7 @@ export function needleDrop(command, config, userSettings) {
|
|
|
59
57
|
if (message && message.startsWith("{")) {
|
|
60
58
|
const obj = /** @type {{ type: string, data: unknown }} */ (JSON.parse(message));
|
|
61
59
|
if (obj.type === "needle-editor:exported-file") {
|
|
62
|
-
|
|
60
|
+
hot.send(obj.type, obj.data);
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
63
|
}
|
|
@@ -86,8 +86,9 @@ function createPlugin(isInstalled) {
|
|
|
86
86
|
},
|
|
87
87
|
|
|
88
88
|
configureServer(server) {
|
|
89
|
-
try
|
|
89
|
+
try
|
|
90
90
|
{
|
|
91
|
+
// Raw WebSocket access needed for direct socket communication
|
|
91
92
|
server.ws.on('connection', (socket, _request) => {
|
|
92
93
|
|
|
93
94
|
// console.log("Send editor sync status: " + isInstalled);
|
package/plugins/vite/index.js
CHANGED
|
@@ -158,5 +158,17 @@ export async function needlePlugins(command, config = undefined, userSettings =
|
|
|
158
158
|
|
|
159
159
|
array.push(await editorConnection(command, config, userSettings, array));
|
|
160
160
|
array.push(needleDependencyWatcher(command, config, userSettings));
|
|
161
|
+
|
|
162
|
+
// Ensure the process exits on SIGINT (Ctrl+C) since plugin timers/sockets can keep the event loop alive
|
|
163
|
+
if (command === "serve") {
|
|
164
|
+
process.on('SIGINT', () => {
|
|
165
|
+
// Wait a moment to allow plugins to clean up if needed, then exit
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
console.debug('\nGoodbye!');
|
|
168
|
+
process.exit();
|
|
169
|
+
}, 1000);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
161
173
|
return array;
|
|
162
174
|
}
|
package/plugins/vite/poster.js
CHANGED
|
@@ -24,7 +24,8 @@ export function needlePoster(command, config, userSettings) {
|
|
|
24
24
|
return {
|
|
25
25
|
name: 'needle:poster',
|
|
26
26
|
configureServer(server) {
|
|
27
|
-
|
|
27
|
+
const hot = server.hot ?? server.ws;
|
|
28
|
+
hot.on('needle:screenshot', async (data, client) => {
|
|
28
29
|
if (userSettings.noPoster) return;
|
|
29
30
|
if (!data?.data) {
|
|
30
31
|
console.warn("Received empty screenshot data, ignoring");
|
package/plugins/vite/reload.js
CHANGED
|
@@ -112,10 +112,15 @@ const posterPath = getPosterPath();
|
|
|
112
112
|
let reloadIsScheduled = false;
|
|
113
113
|
const lockFileName = "needle.lock";
|
|
114
114
|
|
|
115
|
+
/** @param {import('vite').ViteDevServer} server */
|
|
116
|
+
function getHot(server) {
|
|
117
|
+
return server.hot ?? server.ws;
|
|
118
|
+
}
|
|
119
|
+
|
|
115
120
|
/** @param {import('vite').ViteDevServer} server @param {string} [file] */
|
|
116
121
|
function notifyClientWillReload(server, file) {
|
|
117
122
|
console.log("Send reload notification");
|
|
118
|
-
server.
|
|
123
|
+
getHot(server).send('needle:reload', { type: 'will-reload', file: file });
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
/**
|
|
@@ -236,7 +241,7 @@ async function scheduleReload(server, level = 0) {
|
|
|
236
241
|
lastReloadTime = Date.now();
|
|
237
242
|
const readableTime = new Date(lastReloadTime).toLocaleTimeString();
|
|
238
243
|
console.log("< Reloading... " + readableTime)
|
|
239
|
-
server.
|
|
244
|
+
getHot(server).send({
|
|
240
245
|
type: 'full-reload',
|
|
241
246
|
path: '*'
|
|
242
247
|
});
|
|
@@ -14,8 +14,10 @@ const _tempBox: Box3 = new Box3();
|
|
|
14
14
|
const _tempSphere: Sphere = new Sphere();
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Needle Engine LODs manager. Wrapper around the internal LODs manager.
|
|
18
|
-
* It uses the @needle-tools/gltf-progressive package to manage LODs.
|
|
17
|
+
* Needle Engine LODs manager. Wrapper around the internal LODs manager.
|
|
18
|
+
* It uses the [@needle-tools/gltf-progressive](https://npmjs.com/package/@needle-tools/gltf-progressive) package to manage LODs.
|
|
19
|
+
*
|
|
20
|
+
* For lower-level control (e.g. configuring max concurrent loading tasks, queue settings, or other progressive loading specifics), use {@link NEEDLE_progressive} directly.
|
|
19
21
|
* @link https://npmjs.com/package/@needle-tools/gltf-progressive
|
|
20
22
|
*/
|
|
21
23
|
export class LODsManager implements NEEDLE_progressive_plugin {
|
|
@@ -37,6 +39,11 @@ export class LODsManager implements NEEDLE_progressive_plugin {
|
|
|
37
39
|
return this._lodsManager;
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
/**
|
|
43
|
+
* The interval (in seconds) at which the bounding volumes of skinned meshes are automatically updated.
|
|
44
|
+
* If set to 0, automatic updates are disabled and bounding volumes will only be updated when the mesh is loaded or when the `updateSkinnedMeshBounds` method is called manually.
|
|
45
|
+
* @default 0
|
|
46
|
+
*/
|
|
40
47
|
get skinnedMeshAutoUpdateBoundsInterval() {
|
|
41
48
|
return this._lodsManager?.skinnedMeshAutoUpdateBoundsInterval || this._settings.skinnedMeshAutoUpdateBoundsInterval || 0;
|
|
42
49
|
}
|
|
@@ -57,6 +64,7 @@ export class LODsManager implements NEEDLE_progressive_plugin {
|
|
|
57
64
|
this.applySettings();
|
|
58
65
|
}
|
|
59
66
|
|
|
67
|
+
/** @internal */
|
|
60
68
|
constructor(context: Context) {
|
|
61
69
|
this.context = context;
|
|
62
70
|
}
|
|
@@ -270,6 +270,10 @@ export function isNeedleXRSessionEventReceiver(script: any, mode: XRSessionMode
|
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
// #region activeInHierarchy
|
|
276
|
+
|
|
273
277
|
let needsUpdate = true;
|
|
274
278
|
export function markHierarchyDirty() {
|
|
275
279
|
needsUpdate = true;
|
|
@@ -304,7 +308,7 @@ export function updateIsActive(obj?: Object3D, force: boolean = false) {
|
|
|
304
308
|
}
|
|
305
309
|
}
|
|
306
310
|
|
|
307
|
-
function updateIsActiveInHierarchyRecursiveRuntime(go: Object3D, activeInHierarchy: boolean, allowEventCall: boolean, level: number = 0) {
|
|
311
|
+
function updateIsActiveInHierarchyRecursiveRuntime(go: Object3D, activeInHierarchy: boolean, allowEventCall: boolean, level: number = 0): boolean {
|
|
308
312
|
if (level > 1000) {
|
|
309
313
|
console.warn("Hierarchy is too deep (> 1000 level) - will abort updating active state");
|
|
310
314
|
return false;
|
|
@@ -336,74 +340,70 @@ function updateIsActiveInHierarchyRecursiveRuntime(go: Object3D, activeInHierarc
|
|
|
336
340
|
go[constants.activeInHierarchyFieldName] = activeInHierarchy;
|
|
337
341
|
|
|
338
342
|
if (debugHierarchy)
|
|
339
|
-
console.warn("ACTIVE CHANGE", go.name, activeSelf, go.visible, activeInHierarchy,
|
|
343
|
+
console.warn("ACTIVE CHANGE", { name: go.name, activeSelf, visible: go.visible, activeInHierarchy, changed, go });
|
|
340
344
|
if (allowEventCall) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
+
const components = go.userData?.components;
|
|
346
|
+
if (components) {
|
|
347
|
+
for (let ci = 0, cl = components.length; ci < cl; ci++) {
|
|
348
|
+
const comp = components[ci];
|
|
349
|
+
if (activeInHierarchy) {
|
|
345
350
|
if (comp.enabled) {
|
|
346
|
-
comp.
|
|
351
|
+
try { comp.__internalAwake(); }
|
|
352
|
+
catch (err) { console.error(err); }
|
|
353
|
+
if (comp.enabled) {
|
|
354
|
+
comp.__internalEnable();
|
|
355
|
+
}
|
|
347
356
|
}
|
|
348
357
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
358
|
+
else {
|
|
359
|
+
if (comp["__didAwake"] && comp.enabled) {
|
|
360
|
+
comp["__didEnable"] = false;
|
|
361
|
+
comp.onDisable();
|
|
362
|
+
}
|
|
354
363
|
}
|
|
355
364
|
}
|
|
356
|
-
}
|
|
365
|
+
}
|
|
357
366
|
}
|
|
358
367
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
368
|
+
const children = go.children;
|
|
369
|
+
if (children) {
|
|
370
|
+
// When this node is inactive and hasn't changed, skip children that are already
|
|
371
|
+
// marked inactive. Only recurse into children that still have a stale active=true
|
|
372
|
+
// (e.g. after reparenting into this inactive subtree).
|
|
373
|
+
if (!changed && !activeInHierarchy) {
|
|
374
|
+
let success = true;
|
|
375
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
376
|
+
const ch = children[i];
|
|
377
|
+
if (ch[constants.activeInHierarchyFieldName] !== false) {
|
|
378
|
+
if (updateIsActiveInHierarchyRecursiveRuntime(ch, false, allowEventCall, level + 1) === false)
|
|
379
|
+
success = false;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return success;
|
|
365
383
|
}
|
|
384
|
+
let success = true;
|
|
385
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
386
|
+
if (updateIsActiveInHierarchyRecursiveRuntime(children[i], activeInHierarchy, allowEventCall, level + 1) === false)
|
|
387
|
+
success = false;
|
|
388
|
+
}
|
|
389
|
+
return success;
|
|
366
390
|
}
|
|
367
|
-
return
|
|
391
|
+
return true;
|
|
368
392
|
}
|
|
369
393
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
// while (current) {
|
|
373
|
-
// const activeState = current[constants.activeInHierarchyFieldName];
|
|
374
|
-
// if (activeState !== undefined) return activeState;
|
|
375
|
-
// if (current instanceof Scene && !current.parent) {
|
|
376
|
-
// return true;
|
|
377
|
-
// }
|
|
378
|
-
// current = current.parent;
|
|
379
|
-
// }
|
|
380
|
-
// return false;
|
|
381
|
-
// }
|
|
382
|
-
|
|
383
|
-
// let isRunning = false;
|
|
384
|
-
// // Prevent: https://github.com/needle-tools/needle-tiny/issues/641
|
|
385
|
-
// const temporyChildArrayBuffer: Array<Array<Object3D>> = [];
|
|
386
|
-
// export function* iterateChildrenSafe(obj: Object3D) {
|
|
387
|
-
// if (!obj || !obj.children) yield null;
|
|
388
|
-
// // if(isRunning) return;
|
|
389
|
-
// // isRunning = true;
|
|
390
|
-
// const arr = temporyChildArrayBuffer.pop() || [];
|
|
391
|
-
// arr.push(...obj.children);
|
|
392
|
-
// for (const ch of arr) {
|
|
393
|
-
// yield ch;
|
|
394
|
-
// }
|
|
395
|
-
// // isRunning = false;
|
|
396
|
-
// arr.length = 0;
|
|
397
|
-
// temporyChildArrayBuffer.push(arr);
|
|
398
|
-
// }
|
|
394
|
+
|
|
395
|
+
|
|
399
396
|
|
|
400
397
|
/** @internal */
|
|
401
398
|
export function updateActiveInHierarchyWithoutEventCall(go: Object3D) {
|
|
399
|
+
if (!go) {
|
|
400
|
+
console.error("GO is null");
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
402
403
|
let activeInHierarchy = true;
|
|
404
|
+
let foundScene = false;
|
|
403
405
|
let current: Object3D | null = go;
|
|
404
|
-
let foundScene: boolean = false;
|
|
405
406
|
while (current) {
|
|
406
|
-
if (!current) break;
|
|
407
407
|
if (current.type === "Scene") foundScene = true;
|
|
408
408
|
if (!isActiveSelf(current)) {
|
|
409
409
|
activeInHierarchy = false;
|
|
@@ -411,22 +411,14 @@ export function updateActiveInHierarchyWithoutEventCall(go: Object3D) {
|
|
|
411
411
|
}
|
|
412
412
|
current = current.parent;
|
|
413
413
|
}
|
|
414
|
-
if (!go) {
|
|
415
|
-
console.error("GO is null");
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
414
|
go[constants.activeInHierarchyFieldName] = activeInHierarchy && foundScene;
|
|
419
415
|
}
|
|
420
416
|
|
|
421
|
-
function perComponent(go: Object3D, evt: (comp: IComponent) => void) {
|
|
422
|
-
if (go.userData?.components) {
|
|
423
|
-
for (const comp of go.userData.components) {
|
|
424
|
-
evt(comp);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
417
|
|
|
429
418
|
|
|
419
|
+
|
|
420
|
+
// #region prewarm
|
|
421
|
+
|
|
430
422
|
const prewarmList: Map<IContext, Object3D[]> = new Map();
|
|
431
423
|
const $prewarmedFlag = Symbol("prewarmFlag");
|
|
432
424
|
const $waitingForPrewarm = Symbol("waitingForPrewarm");
|