Scene Lifecycle Hooks
Overview
This example demonstrates how to react to scene lifecycle events using RegisterOnSceneOpen and RegisterOnSceneClose. These hooks enable addons to perform scene-specific setup, cache management, and cleanup when switching between scenes during development.
Files
package.json
{
"name": "Scene Watcher Addon",
"author": "Polyphase Examples",
"description": "Monitors scene lifecycle events.",
"version": "1.0.0",
"tags": ["editor", "example"],
"native": {
"target": "editor",
"sourceDir": "Source",
"binaryName": "scenewatcheraddon",
"apiVersion": 2
}
}
Source/SceneWatcherAddon.cpp
#include "Plugins/PolyphasePluginAPI.h"
#include "Plugins/PolyphaseEngineAPI.h"
#if EDITOR
#include "Plugins/EditorUIHooks.h"
#endif
static PolyphaseEngineAPI* sEngineAPI = nullptr;
#if EDITOR
static char sCurrentScenePath[512] = {};
static int sSceneOpenCount = 0;
/**
* @brief Called when a scene is opened.
* @param scenePath Absolute path to the scene file.
* @param userData User-provided data.
*/
static void OnSceneOpen(const char* scenePath, void* userData)
{
sSceneOpenCount++;
sEngineAPI->LogDebug("Scene opened (#%d): %s", sSceneOpenCount, scenePath);
if (scenePath)
{
strncpy(sCurrentScenePath, scenePath, sizeof(sCurrentScenePath) - 1);
sCurrentScenePath[sizeof(sCurrentScenePath) - 1] = '\0';
}
// Example: Build scene-specific caches
sEngineAPI->LogDebug("Building scene cache...");
// Example: Load scene-specific addon data
sEngineAPI->LogDebug("Loading scene configuration...");
// Example: Validate scene content
sEngineAPI->LogDebug("Validating scene assets...");
}
/**
* @brief Called when a scene is closed.
* @param scenePath Absolute path to the scene file being closed.
* @param userData User-provided data.
*/
static void OnSceneClose(const char* scenePath, void* userData)
{
sEngineAPI->LogDebug("Scene closing: %s", scenePath);
// Example: Save scene-specific addon data
sEngineAPI->LogDebug("Saving scene-specific addon data...");
// Example: Clear scene-specific caches
sEngineAPI->LogDebug("Clearing scene cache...");
sCurrentScenePath[0] = '\0';
}
#endif
/**
* @brief Called when the plugin is loaded by the engine.
* @param api Pointer to the engine API.
* @return 0 on success, non-zero on failure.
*/
static int OnLoad(PolyphaseEngineAPI* api)
{
sEngineAPI = api;
api->LogDebug("Scene Watcher Addon loaded!");
return 0;
}
/**
* @brief Called when the plugin is about to be unloaded.
*/
static void OnUnload()
{
if (sEngineAPI) sEngineAPI->LogDebug("Scene Watcher Addon unloading.");
sEngineAPI = nullptr;
}
#if EDITOR
/**
* @brief Register editor UI hooks.
* @param hooks Pointer to the EditorUIHooks function table.
* @param hookId Unique identifier for this plugin's hooks.
*
* All hooks registered here are automatically cleaned up via
* RemoveAllHooks(hookId) when the plugin unloads.
*/
static void RegisterEditorUI(EditorUIHooks* hooks, uint64_t hookId)
{
hooks->RegisterOnSceneOpen(hookId, OnSceneOpen, nullptr);
hooks->RegisterOnSceneClose(hookId, OnSceneClose, nullptr);
sEngineAPI->LogDebug("Scene lifecycle hooks registered");
}
#endif
extern "C" OCTAVE_PLUGIN_API int PolyphasePlugin_GetDesc(PolyphasePluginDesc* desc)
{
desc->apiVersion = OCTAVE_PLUGIN_API_VERSION;
desc->pluginName = "Scene Watcher Addon";
desc->pluginVersion = "1.0.0";
desc->OnLoad = OnLoad;
desc->OnUnload = OnUnload;
desc->Tick = nullptr;
desc->TickEditor = nullptr;
desc->RegisterTypes = nullptr;
desc->RegisterScriptFuncs = nullptr;
#if EDITOR
desc->RegisterEditorUI = RegisterEditorUI;
#else
desc->RegisterEditorUI = nullptr;
#endif
desc->OnEditorPreInit = nullptr;
desc->OnEditorReady = nullptr;
return 0;
}
API Reference
RegisterOnSceneOpen
void (*RegisterOnSceneOpen)(HookId hookId, StringEventCallback cb, void* userData);
Registers a callback invoked when a scene is opened in the editor.
Parameters:
- hookId - The hook identifier provided by RegisterEditorUI
- cb - Function to call when a scene opens
- userData - Optional user data passed to the callback
Triggered when: - User opens a scene from the File menu - Scene is opened programmatically - Project initially loads with a default scene
RegisterOnSceneClose
void (*RegisterOnSceneClose)(HookId hookId, StringEventCallback cb, void* userData);
Registers a callback invoked when a scene is closed in the editor.
Parameters:
- hookId - The hook identifier provided by RegisterEditorUI
- cb - Function to call when a scene closes
- userData - Optional user data passed to the callback
Triggered when: - User closes the current scene - User opens a different scene (old scene closes first) - Project is closed
StringEventCallback
typedef void (*StringEventCallback)(const char* str, void* userData);
Callback signature for events that provide a string parameter.
Parameters:
- str - String data (scene file path in these cases)
- userData - User-provided data from registration
Best Practices
- Path Storage - Store the scene path if you need to reference it elsewhere
- Cache Management - Build scene-specific caches on open, clear on close
- Cleanup - Always clean up in
OnSceneClosebefore switching scenes - Null Checks - Validate the
scenePathparameter before using it - Performance - Keep callbacks fast to avoid delaying scene loading
- Automatic Cleanup - Hooks are cleaned up automatically; manual unregistration is not required
- Multi-Scene - Handle rapid scene switching gracefully