Generic life cicle events after export from Editor Side

Hi! I was experimenting with a Nuxt integration, it’s working quite well, but I found myself in a bit of a dilema:
I changed the output from the editor to a folder called ´unityIntegration´ (to avoid confusion with some namings, mainly Needle´s output folders from predefined Nuxt Folders). So my ´needle.config.json´ looks like this:

{
“baseUrl”: “needle”,
“buildDirectory”: “public/needle”,
“assetsDirectory”: “unityIntegration”,
“scriptsDirectory”: “src/scripts”,
“codegenDirectory”: “src/generated”
}

When executing the Build everything works fine, but I noticed that during development, HMR doesn’t work for static assets, i understand that this is because i changed ´buildDirectory´ to be ´public/needle´ (public being the folder where Nuxt serves static assets to be picked by Nitro), I cannot set the build directory to be ´public/needle/assets´ (which was my original idea) because at some point, a clearing process happens and references get lost between export and build.
Hence the separation, but now i need to “manually” copy the contents of the integration to where i need it, so that the devserver can pick it and trigger an update.

I tried setting up a watcher that triggers events when a file changes on the ´unityIntegration´ folder, but this triggers once per each file during scene export, so i discarded the idea.
Last Friday I asked on Discord About it, and you guys pointed me out to another post about: “material export blending mode support” and also this fragment:

using Needle.Engine.Core;
using UnityEngine;

public static class NeedleEngineExportListener
{
private static void Init()
{
Builder.BuildStarting += () => Debug.Log(“BUILD STARTED”);
Builder.BuildEnded += () => Debug.Log(“BUILD ENDED”);
Builder.BuildFailed += () => Debug.Log(“BUILD FAILED”);
}
}

I tried the last one, but couldnt make it work, not sure if i´m doing something wrong, or is it Unity the one tricking me.
My objective is to execute a function inside a script immediately after scene export is completely finished (basically to synchronously copy/paste the contents to where i need it), not when building the final project. In other words, right after the process that happens when saving the scene with some changes.

Is this possible? and if the last fragment above is the way to achieve that, could you guys give me a step by step instruction? If i´m not mistaken, this should be an Editor extension right? I created an ´Assembly definition Reference´ asset to be able to use the ´Needle.Engine.Core´ namespace, the code compiles, but i don´t see it being executed. Did I miss something?

Hi whtw4thewin, it sounds like your export lifecycle events aren’t firing because the listener isn’t being initialized. In your snippet the static method Init() won’t run unless something triggers it. A common solution is to ensure the class gets loaded automatically in the Editor.

For example, you can add Unity’s [InitializeOnLoad] attribute with a static constructor so that your event handlers are set up as soon as the Editor loads. For instance:

using UnityEngine;
using UnityEditor; // needed for [InitializeOnLoad]
using Needle.Engine.Core;

[InitializeOnLoad]
public static class NeedleEngineExportListener
{
    static NeedleEngineExportListener()
    {
        Builder.BuildStarting += () => Debug.Log("BUILD STARTED");
        Builder.BuildEnded += () => Debug.Log("BUILD ENDED");
        Builder.BuildFailed += () => Debug.Log("BUILD FAILED");
    }
}

This ensures the static constructor runs automatically upon load, registering your events. If your class is not placed within an Editor folder (or otherwise loaded by the Editor), or if nothing forces its initialization, the method won’t be called.

Regarding your Nuxt integration and the file-watcher issue, a potential improvement is to debounce the file change events so that multiple rapid file exports trigger a single update in the dev server. That way, you avoid the “one per each file” problem during scene export.

If you continue experiencing issues, please double-check your Unity version and the Needle Engine version to ensure they support these callbacks. You can also try triggering a manual call to Init() to verify that the event subscription is working before automating it.

Hope this helps you get the lifecycle events working correctly! Let me know if you need further details.

1 replies left - Become PRO for more replies.
thread_kk2KIV5eANXK4yIiSa6k4aSO
Reply to this post directly if you need further help (bottom right button)

Hello,

Could you clarify what you mean by a clearing process happens and references get lost - which references are you refering to here?

https://needle.tools is built with nuxt at the moment, we didn’t have to implement such workarounds so it would be interesting to learn more.

Regarding your code: It’s missing the [InitializeOnLoad] or [InitializeOnLoadMethod] attribute so the Init function is never called by Unity. Sorry about that (The bot’s reply above should work) or you can change it to:

using Needle.Engine.Core;
using UnityEngine;

public static class NeedleEngineExportListener
{
    [UnityEditor.InitializeOnLoadMethod]
    private static void Init()
    {
        Builder.BuildStarting += () => Debug.Log("BUILD STARTED");
        Builder.BuildEnded += () => Debug.Log("BUILD ENDED");
        Builder.BuildFailed += () => Debug.Log("BUILD FAILED");
    }
}

I added “[UnityEditor.InitializeOnLoadMethod]“ and it worked. I´ll paste the Logs that appears when I build (via [Needle Engine/export and Build Dist]), which obviously fails at the end.

build
nuxt build --production
[nuxi] Nuxt 3.17.6 with Nitro 2.11.13
[nuxt:tailwindcss] i Using default Tailwind CSS file
[nuxi] i Building for Nitro preset: node-server
i Building client…
Needle Engine Version: 4.8.8 Unity 2022.3.43f1, Needle Engine Integration @4.8.8
Build directory: C:/Users/Admin/dev/EnelNuxt/Needle/ENEL/public/needle
@needle-tools/editor-sync 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
[needle-identifier] INFO: Fetching project identifier…
[needle-dependencies] Adding three-mesh-bvh to the optimizeDeps.exclude array to support workers.
[needle-dependencies] Adding @needle-tools/gltf-progressive to the optimizeDeps.exclude array to support workers.
[needle-dependencies] registering manualChunks
[needle-dependencies] chunkFileNames already defined
[needle-dependencies] assetFileNames already defined
[needle-alias] Detected local @needle-tools/engine package: will exclude it from optimization
Update HMR port to 1107
[needle-license] INFO: Fetching license…
[needle-license] INFO: Successfully received “INDIE” license
i vite v6.3.5 building for production…
[needle-copy-files] - Copy files at start
[needle-copy-files] - Copy engine include to C:\Users\Admin\dev\EnelNuxt\Needle\ENEL/include
[needle-copy-files] - Clearing target directory “C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle\assets”
[needle-copy-files] - Copy assets to public/needle/assets
i ✓ 0 modules transformed.
[needle-copy-files] - Copy files at end
[needle-copy-files] - Copy engine include to C:\Users\Admin\dev\EnelNuxt\Needle\ENEL/include
WARN: No assets directory found. Skipping copy of public/needle/assets resolved to C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle\assets
[needle-copy-files] - Copy include to public/needle/include
[needle-buildinfo] - Begin collecting files in “C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle”
[needle-buildinfo] - Collect files in “/include”
[needle-buildinfo] - Collect files in “/include/draco”
[needle-buildinfo] - Collect files in “/include/ktx2”
[needle-buildinfo] - Collect files in “/include/needle”
[needle-buildinfo] - Collect files in “/include/three”
[needle-buildinfo] - Collected 11 files (1.73 MB). Writing build info to “C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle/needle.buildinfo.json”
[needle-buildinfo] - Build info file successfully written to “C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle/needle.buildinfo.json”
ERROR ✗ Build failed in 652ms
[nuxi] ERROR Nuxt Build Error: [needle-copy-files] ENOENT: no such file or directory, copyfile ‘C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle\assets’ → ‘C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle\assets’
at copyFileSync (node:fs:3086:11)
at copyFilesSync (/C:/Users/Admin/dev/EnelNuxt/Needle/ENEL/node_modules/@needle-tools/engine/plugins/common/files.js:30:9)
at run (/C:/Users/Admin/dev/EnelNuxt/Needle/ENEL/node_modules/@needle-tools/engine/plugins/vite/copyfiles.js:105:9)
at Object.buildStart (/C:/Users/Admin/dev/EnelNuxt/Needle/ENEL/node_modules/@needle-tools/engine/plugins/vite/copyfiles.js:25:20)
at Object.handler (/C:/Users/Admin/dev/EnelNuxt/Needle/ENEL/node_modules/vite/dist/node/chunks/dep-DBxKXgDP.js:46529:15)
at /C:/Users/Admin/dev/EnelNuxt/Needle/ENEL/node_modules/rollup/dist/es/shared/node-entry.js:22276:40
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async Promise.all (index 2)
at async PluginDriver.hookParallel (/C:/Users/Admin/dev/EnelNuxt/Needle/ENEL/node_modules/rollup/dist/es/shared/node-entry.js:22186:9)
at async /C:/Users/Admin/dev/EnelNuxt/Needle/ENEL/node_modules/rollup/dist/es/shared/node-entry.js:23155:13

Mmm maybe I´m not understanding something, but this happens because I dont want another dist folder, just to use the same directory that I´m using during dev. If I left it like this:

{
“baseUrl”: “needle”,
“buildDirectory”: “dist”,
“assetsDirectory”: “public/needle/assets”,
“scriptsDirectory”: “src/scripts”,
“codegenDirectory”: “src/generated”
}

Everything works as expected, but I have to clarify that I´m using Railway as the platform to deploy this app, and It syncs using my Git repo as base, dist is inside .gitignore currently because it expects to execute npm´s build script and then start script (so in theory the same folder would be reconstructed (?)). But wouldn´t this make the build procedure unnecesary since the code would already ship with the assets required inside public/needle/assets folder?

but this happens because I dont want another dist folder, just to use the same directory that I´m using during dev

I think here’s a misunderstanding - the dist folder is what gets deployed, it contains the bundled application code and all necessary assets. If you deploy your application using Railway you don’t need to build locally to make it work - it will be built inside of the Railway platform. So you won’t have another dist folder. Your dist folder configuration must match how you setup nuxt.

Here’s the needle.config.json content of the needle.tools website - we use github actions to deploy to Needle Cloud so it’s similar to what you’re trying to archieve with Railway.

{
  "baseUrl": "assets",
  "buildDirectory": ".output/public",
  "assetsDirectory": "public/assets",
  "scriptsDirectory": "src/scripts",
  "codegenDirectory": "src/generated"
}

This does however look like a bug - I’m not quite sure why it happens but will try to reproduce it.

[nuxi] ERROR Nuxt Build Error: [needle-copy-files] ENOENT: no such file or directory, copyfile ‘C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle\assets’ → ‘C:\Users\Admin\dev\EnelNuxt\Needle\ENEL\public\needle\assets’
at copyFileSync (node:fs:3086:11)

Hi! The setting you provided works fine, thank you very much, would be great if an offical Nuxt integration sample is released and listed.
About the error, you could ignore it, since its related to the previous misunderstanding.

I´ll add another reply with a summary and mark it as the answer to the post, so I can add the little details, maybe it will be usefull to someone.

Summary

If you want to listen for events before and/or after scene export, from the Unity Editor side:

  1. Create an Assembly Definition Asset and point it to the ´Needle.Engine.Editor´ asmdef file packed with Needle Engine Package (Located in: Packages/com.needle.engine-exporter/Core/Editor/Needle.Engine.Editor.asmdef).

  2. Create a file like this under a ´Editor´ folder:

using Needle.Engine.Core;
using UnityEngine;

public static class NeedleEngineExportListener
{
    [UnityEditor.InitializeOnLoadMethod]
    private static void Init()
    {
        Builder.BuildStarting += () => Debug.Log("BUILD STARTED");
        Builder.BuildEnded += () => Debug.Log("BUILD ENDED");
        Builder.BuildFailed += () => Debug.Log("BUILD FAILED");
    }
}
  1. Profit.

When saving your scene you should see the messages printed on console.

Thanks that’s great!

1 Like

This topic was automatically closed 13 days after the last reply. New replies are no longer allowed.