chore: Pass Lua VM from editor when decoding runtime File (#11458) f57124001d The C++ runtime requires a ScriptingVM and lua_State to run scripts. Previously when a runtime File was built, we would always instance a ScriptingVM and lua_State. At runtime, this is required, however, when building the runtime in the editor, this resulted in additional objects being created that weren't needed. This PR passes the lua_State into File::import so that the file will only create the ScriptingVM once and either use the passed in lua_State or instance a new one if none is passed. Co-authored-by: Philip Chung <philterdesign@gmail.com>
diff --git a/.rive_head b/.rive_head index c880cd3..76080af 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -f3a89390cb428a5ea841d21de91f9cb2adc312df +f57124001d4ee388c32a3ec0cd08e292fafc268d
diff --git a/include/rive/file.hpp b/include/rive/file.hpp index 3d9bba3..a14d5db 100644 --- a/include/rive/file.hpp +++ b/include/rive/file.hpp
@@ -86,15 +86,17 @@ static rcp<File> import(Span<const uint8_t> data, Factory* factory, ImportResult* result = nullptr, - FileAssetLoader* assetLoader = nullptr) + FileAssetLoader* assetLoader = nullptr, + void* vm = nullptr) { - return import(data, factory, result, ref_rcp(assetLoader)); + return import(data, factory, result, ref_rcp(assetLoader), vm); } static rcp<File> import(Span<const uint8_t> data, Factory*, ImportResult* result, - rcp<FileAssetLoader> assetLoader); + rcp<FileAssetLoader> assetLoader, + void* vm = nullptr); /// @returns the file's backboard. All files have exactly one backboard. Backboard* backboard() const { return m_backboard; } @@ -180,21 +182,8 @@ // we are running in the runtime and should instance our own VMs // and pass them down to the root #ifdef WITH_RIVE_SCRIPTING - void scriptingVM(lua_State* vm) - { - cleanupScriptingVM(); - m_luaState = vm; - } - lua_State* scriptingVM() - { - // For now, if we don't have a vm, create one. In the future, we - // may need a way to create multiple vms in parallel - if (m_luaState == nullptr) - { - makeScriptingVM(); - } - return m_luaState; - } + void scriptingState(lua_State* vm) { m_luaState = vm; } + lua_State* scriptingState() { return m_luaState; } #ifdef WITH_RIVE_TOOLS void clearScriptingVM() { cleanupScriptingVM(); } bool hasVM() { return m_luaState != nullptr; } @@ -280,7 +269,7 @@ lua_State* m_luaState = nullptr; std::unique_ptr<CPPRuntimeScriptingContext> m_scriptingContext; std::unique_ptr<ScriptingVM> m_scriptingVM; - void makeScriptingVM(); + void makeScriptingVM(lua_State* existingState = nullptr); void cleanupScriptingVM(); void registerScripts(); #endif
diff --git a/include/rive/lua/rive_lua_libs.hpp b/include/rive/lua/rive_lua_libs.hpp index 45eb3f9..8c5b645 100644 --- a/include/rive/lua/rive_lua_libs.hpp +++ b/include/rive/lua/rive_lua_libs.hpp
@@ -860,6 +860,7 @@ { public: ScriptingVM(ScriptingContext* context); + ScriptingVM(ScriptingContext* context, lua_State* existingState); ~ScriptingVM(); // ScriptingContext& context() { return m_context; } @@ -895,6 +896,7 @@ private: lua_State* m_state; ScriptingContext* m_context; + bool m_ownsState; }; class ScriptedDataValue
diff --git a/src/assets/script_asset.cpp b/src/assets/script_asset.cpp index 1542c46..9642b5b 100644 --- a/src/assets/script_asset.cpp +++ b/src/assets/script_asset.cpp
@@ -169,7 +169,7 @@ } // We get the scripting VM from File for now, however, // this will need to change if/when we support multiple VMs - return m_file->scriptingVM(); + return m_file->scriptingState(); } #endif
diff --git a/src/file.cpp b/src/file.cpp index 0b7dfac..a7ef9a0 100644 --- a/src/file.cpp +++ b/src/file.cpp
@@ -234,7 +234,8 @@ rcp<File> File::import(Span<const uint8_t> bytes, Factory* factory, ImportResult* result, - rcp<FileAssetLoader> assetLoader) + rcp<FileAssetLoader> assetLoader, + void* vm) { BinaryReader reader(bytes); RuntimeHeader header; @@ -262,6 +263,12 @@ return nullptr; } auto file = make_rcp<File>(factory, std::move(assetLoader)); +#ifdef WITH_RIVE_SCRIPTING + if (vm != nullptr) + { + file->scriptingState(static_cast<lua_State*>(vm)); + } +#endif auto readResult = file->read(reader, header); if (result) @@ -609,39 +616,54 @@ #ifdef WITH_RIVE_SCRIPTING void File::registerScripts() { - if (m_scriptingVM == nullptr) - { - makeScriptingVM(); - } - - // Add all scripts to the VM for registration + // Check if we have any script assets in the file + std::vector<ScriptAsset*> scripts; for (auto asset : m_fileAssets) { if (asset->is<ScriptAsset>()) { - ScriptAsset* scriptAsset = asset->as<ScriptAsset>(); - // At runtime, generatorFunctionRef should be 0, meaning - // it hasn't been registered yet with a VM. + scripts.push_back(asset->as<ScriptAsset>()); + } + } + // Only make the ScriptingVM if we have any script assets + if (!scripts.empty()) + { + makeScriptingVM(scriptingState()); + for (auto scriptAsset : scripts) + { + // At runtime, if the script is verified, add it to be + // registered with the VM. At edit time, the script will + // have already been registered, so this won't run if (scriptAsset->verified()) { m_scriptingVM->addModule(scriptAsset); } } + // Perform registration - ScriptingContext will handle dependencies and + // retries + m_scriptingVM->performRegistration(); } - - // Perform registration - ScriptingContext will handle dependencies and - // retries - m_scriptingVM->performRegistration(); } -void File::makeScriptingVM() +void File::makeScriptingVM(lua_State* existingState) { cleanupScriptingVM(); m_scriptingContext = rivestd::make_unique<CPPRuntimeScriptingContext>(m_factory); - m_scriptingVM = rivestd::make_unique<ScriptingVM>(m_scriptingContext.get()); - m_luaState = m_scriptingVM->state(); - initializeLuaData(m_luaState, m_ViewModels); + if (existingState != nullptr) + { + m_scriptingVM = + rivestd::make_unique<ScriptingVM>(m_scriptingContext.get(), + existingState); + m_luaState = existingState; + } + else + { + m_scriptingVM = + rivestd::make_unique<ScriptingVM>(m_scriptingContext.get()); + m_luaState = m_scriptingVM->state(); + initializeLuaData(m_luaState, m_ViewModels); + } } void File::cleanupScriptingVM()
diff --git a/src/lua/rive_lua_libs.cpp b/src/lua/rive_lua_libs.cpp index 0b7d466..66f5565 100644 --- a/src/lua/rive_lua_libs.cpp +++ b/src/lua/rive_lua_libs.cpp
@@ -342,13 +342,24 @@ luaL_sandboxthread(state); } -ScriptingVM::ScriptingVM(ScriptingContext* context) : m_context(context) +ScriptingVM::ScriptingVM(ScriptingContext* context) : + m_context(context), m_ownsState(true) { m_state = lua_newstate(l_alloc, nullptr); init(m_state, m_context); } -ScriptingVM::~ScriptingVM() { lua_close(m_state); } +ScriptingVM::ScriptingVM(ScriptingContext* context, lua_State* existingState) : + m_state(existingState), m_context(context), m_ownsState(false) +{} + +ScriptingVM::~ScriptingVM() +{ + if (m_ownsState) + { + lua_close(m_state); + } +} static int register_module(lua_State* L) {