UNPKG

@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.

132 lines (115 loc) 6.03 kB
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 { // Raw WebSocket access needed for direct socket communication 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) } } }) }