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>
This commit is contained in:
philter
2026-01-15 20:22:41 +00:00
parent 6eaf71f485
commit 155a726a9b
6 changed files with 65 additions and 41 deletions

View File

@@ -1 +1 @@
f3a89390cb428a5ea841d21de91f9cb2adc312df
f57124001d4ee388c32a3ec0cd08e292fafc268d

View File

@@ -86,15 +86,17 @@ public:
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 @@ public:
// 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 @@ private:
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

View File

@@ -860,6 +860,7 @@ class ScriptingVM
{
public:
ScriptingVM(ScriptingContext* context);
ScriptingVM(ScriptingContext* context, lua_State* existingState);
~ScriptingVM();
// ScriptingContext& context() { return m_context; }
@@ -895,6 +896,7 @@ public:
private:
lua_State* m_state;
ScriptingContext* m_context;
bool m_ownsState;
};
class ScriptedDataValue

View File

@@ -169,7 +169,7 @@ lua_State* ScriptAsset::vm()
}
// 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

View File

@@ -234,7 +234,8 @@ File::~File()
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 @@ rcp<File> File::import(Span<const uint8_t> bytes,
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 @@ ImportResult File::read(BinaryReader& reader, const RuntimeHeader& header)
#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()

View File

@@ -342,13 +342,24 @@ void ScriptingVM::init(lua_State* state, ScriptingContext* context)
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)
{