@needle-tools/engine
Version:
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.
131 lines (114 loc) • 5.95 kB
JavaScript
import { existsSync } from "fs";
import { needleLog } from "./logging.js";
const root = process.cwd();
const editorSyncPackageName = "@needle-tools/editor-sync"
/** sent from the editor when the server was already running
/* when the user added the editor sync component
/* at the top of this file we check if the component is present in the scene
/* and enabled and if it's not it will not install the editor plugin
*/
let editorSyncEnabled = false;
/**
* @param {"build" | "serve"} command
* @param {import('../types/needleConfig').needleMeta | null | undefined} config
* @param {import('../types').userSettings} userSettings
* @param {import('vite').Plugin[]} [pluginsArray]
* @returns {Promise<import('vite').Plugin | undefined>}
*/
export async function editorConnection(command, config, userSettings, pluginsArray) {
if (command === "build") return;
// Editor sync currently only supports Unity
if (typeof config.generator === "string" && !config.generator.includes("Unity")) return;
if (!config) {
setTimeout(() => needleLog("needle-editor-sync", "Needle Editor Sync can not be installed automatically to vite: missing config", "warn"), 1000);
return createPlugin(false);
}
if (config?.dontInstallEditor === true || userSettings?.dontInstallEditor === true) return;
const needleEditorSettings = config.needleEditor;
// If the component was added while the server was already running
// if (editorSyncEnabled === false) {
// if (!needleEditorSettings) {
// setTimeout(() => console.log("Needle Editor Sync is not enabled. Add a 'Needle Editor Sync' component to your scene to enable (no component)"), 1000);
// return createPlugin(false);
// }
// }
if (needleEditorSettings && needleEditorSettings.enabled === false) {
setTimeout(() => needleLog("needle-editor-sync", "Needle Editor Sync is not enabled. Add a 'Needle Editor Sync' component to your scene to enable", "warn"), 1000);
return createPlugin(false);
}
// Check if the editor package is installed
let path = root + `/node_modules/${editorSyncPackageName}/plugins/index.js`;
if (existsSync(path) === false) {
setTimeout(() => needleLog("needle-editor-sync", `${editorSyncPackageName} is not installed: Add the "Needle Editor Sync" component to your scene if you want to send changes directly from the Unity Editor to web app`, "warn"), 1000);
return createPlugin(false);
}
// Load vite plugin
if (!path.startsWith("file:")) path = "file:" + path;
const { needleEditor } = /** @type {{ needleEditor: () => Record<string, unknown> }} */ (await import(path));
setTimeout(() => needleLog("needle-editor-sync", "Automatically installed Needle Editor Sync"), 500)
const method = needleEditor();
const typedPluginsArray = /** @type {Array<Record<string, unknown>>} */ (pluginsArray);
typedPluginsArray.push(method);
return createPlugin(true);
}
/** @param {boolean} isInstalled */
function createPlugin(isInstalled) {
return /** @type {import('vite').Plugin} */ ({
name: "needle-editor-connection",
// Setup HMR port for connecting to the editor
config(config) {
if (isInstalled) {
if (!config.server) config.server = {};
if (!config.server.hmr) config.server.hmr = {};
if (config.server.hmr === false) {
setTimeout(() => needleLog("needle-editor-sync", "HMR is disabled, not initializing Needle Editor", "warn"));
return;
}
if (config.server.hmr.port === undefined) {
config.server.hmr.port = 1107;
setTimeout(() => needleLog("needle-editor-sync", "Update HMR port to " + config.server.hmr.port));
}
}
},
configureServer(server) {
try
{
server.ws.on('connection', (socket, _request) => {
// console.log("Send editor sync status: " + isInstalled);
const reply = {
type: "needle:editor-sync:installation-status",
data: isInstalled
}
socket.send(JSON.stringify(reply));
socket.on('message', async (bytes) => {
if (bytes?.length < 50) {
const message = Buffer.from(bytes).toString();
if (message === "needle:editor:restart") {
needleLog("needle-editor-sync", "Received request for a soft restart of the vite server...")
// This just restarts the vite server
server.restart();
}
else if (message === "needle:editor:stop") {
process.exit();
}
else if (message === `{"type":"ping"}`) {
socket.send(JSON.stringify({ type: "pong" }));
}
else if (message === "needle:editor:editor-sync-enabled") {
needleLog("needle-editor-sync", "Editor sync enabled")
editorSyncEnabled = true;
}
else if (message === "needle:editor:editor-sync-disabled") {
editorSyncEnabled = false;
}
}
})
});
}
catch(/** @type {unknown} */ err){
needleLog("needle-editor-sync", "Error in needle-editor-connection", "error")
console.error(err)
}
}
})
}