No double deref luau (#11448) 62fcec60de

Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
This commit is contained in:
luigi-rosso
2026-01-13 07:13:04 +00:00
parent 46cd7a7406
commit 768aacd78d
18 changed files with 226 additions and 189 deletions

View File

@@ -1 +1 @@
9b416a02f6fffdcb2210cbb674ef7d746466e2d1
62fcec60de0eea68dceb64758f284ef5b5e20c00

View File

@@ -7,6 +7,11 @@
#include "rive/generated/assets/script_asset_base.hpp"
#include "rive/simple_array.hpp"
#include <stdio.h>
#ifdef WITH_RIVE_SCRIPTING
struct lua_State;
#endif
namespace rive
{
class Artboard;
@@ -24,7 +29,6 @@ enum ScriptProtocol
};
#ifdef WITH_RIVE_SCRIPTING
class LuaState;
class ScriptAssetImporter;
#endif
@@ -65,7 +69,7 @@ private:
protected:
#ifdef WITH_RIVE_SCRIPTING
bool verifyImplementation(ScriptedObject* object, LuaState* luaState);
bool verifyImplementation(ScriptedObject* object, lua_State* state);
#endif
public:
@@ -173,7 +177,7 @@ public:
void file(File* value) { m_file = value; }
File* file() const { return m_file; }
#ifdef WITH_RIVE_SCRIPTING
LuaState* vm();
lua_State* vm();
void registrationComplete(int ref) override;
#endif
std::string moduleName() override

View File

@@ -20,6 +20,10 @@
#include <set>
#include <unordered_map>
#ifdef WITH_RIVE_SCRIPTING
struct lua_State;
#endif
///
/// Default namespace for Rive Cpp runtime code.
///
@@ -39,7 +43,6 @@ class BindableArtboard;
#ifdef WITH_RIVE_SCRIPTING
class CPPRuntimeScriptingContext;
class ScriptingVM;
class LuaState;
#endif
///
@@ -177,12 +180,12 @@ 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(LuaState* vm)
void scriptingVM(lua_State* vm)
{
cleanupScriptingVM();
m_luaState = vm;
}
LuaState* scriptingVM()
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
@@ -192,6 +195,10 @@ public:
}
return m_luaState;
}
#ifdef WITH_RIVE_TOOLS
void clearScriptingVM() { cleanupScriptingVM(); }
bool hasVM() { return m_luaState != nullptr; }
#endif
#endif
DataResolver* dataResolver()
@@ -270,7 +277,7 @@ private:
rcp<FileAssetLoader> m_assetLoader;
#ifdef WITH_RIVE_SCRIPTING
LuaState* m_luaState = nullptr;
lua_State* m_luaState = nullptr;
std::unique_ptr<CPPRuntimeScriptingContext> m_scriptingContext;
std::unique_ptr<ScriptingVM> m_scriptingVM;
void makeScriptingVM();

View File

@@ -9,18 +9,10 @@
namespace rive
{
class ViewModel;
class LuaState
{
public:
#ifdef WITH_RIVE_SCRIPTING
LuaState(lua_State* state) : state(state) {}
~LuaState() { state = nullptr; }
void initializeData(std::vector<ViewModel*>&);
lua_State* state;
void initializeLuaData(lua_State* state, std::vector<ViewModel*>& viewModels);
#endif
};
} // namespace rive
#endif

View File

@@ -1,8 +1,5 @@
#ifndef _RIVE_SCRIPTED_DATA_CONVERTER_HPP_
#define _RIVE_SCRIPTED_DATA_CONVERTER_HPP_
#ifdef WITH_RIVE_SCRIPTING
#include "rive/lua/rive_lua_libs.hpp"
#endif
#include "rive/generated/scripted/scripted_data_converter_base.hpp"
#include "rive/advancing_component.hpp"
#include "rive/scripted/scripted_object.hpp"
@@ -41,7 +38,7 @@ private:
public:
~ScriptedDataConverter();
#ifdef WITH_RIVE_SCRIPTING
bool scriptInit(LuaState* state) override;
bool scriptInit(lua_State* state) override;
DataValue* convert(DataValue* value, DataBind* dataBind) override;
DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override;
#endif

View File

@@ -1,8 +1,5 @@
#ifndef _RIVE_SCRIPTED_DRAWABLE_HPP_
#define _RIVE_SCRIPTED_DRAWABLE_HPP_
#ifdef WITH_RIVE_SCRIPTING
#include "rive/lua/rive_lua_libs.hpp"
#endif
#include "rive/generated/scripted/scripted_drawable_base.hpp"
#include "rive/animation/state_machine_instance.hpp"
#include "rive/advancing_component.hpp"
@@ -24,7 +21,7 @@ class ScriptedDrawable : public ScriptedDrawableBase,
{
public:
#ifdef WITH_RIVE_SCRIPTING
bool scriptInit(LuaState* state) override;
bool scriptInit(lua_State* state) override;
#endif
void draw(Renderer* renderer) override;
void update(ComponentDirt value) override;

View File

@@ -1,8 +1,5 @@
#ifndef _RIVE_SCRIPTED_LAYOUT_HPP_
#define _RIVE_SCRIPTED_LAYOUT_HPP_
#ifdef WITH_RIVE_SCRIPTING
#include "rive/lua/rive_lua_libs.hpp"
#endif
#include "rive/layout/layout_enums.hpp"
#include "rive/layout/layout_measure_mode.hpp"
#include "rive/generated/scripted/scripted_layout_base.hpp"
@@ -19,7 +16,7 @@ private:
public:
#ifdef WITH_RIVE_SCRIPTING
bool scriptInit(LuaState* luaState) override;
bool scriptInit(lua_State* state) override;
#endif
Vec2D measureLayout(float width,
LayoutMeasureMode widthMode,

View File

@@ -1,8 +1,5 @@
#ifndef _RIVE_SCRIPTED_OBJECT_HPP_
#define _RIVE_SCRIPTED_OBJECT_HPP_
#ifdef WITH_RIVE_SCRIPTING
#include "rive/lua/rive_lua_libs.hpp"
#endif
#include "rive/assets/file_asset_referencer.hpp"
#include "rive/assets/script_asset.hpp"
#include "rive/custom_property.hpp"
@@ -10,6 +7,11 @@
#include "rive/refcnt.hpp"
#include "rive/generated/assets/script_asset_base.hpp"
#include <stdio.h>
#ifdef WITH_RIVE_SCRIPTING
struct lua_State;
#endif
namespace rive
{
class Artboard;
@@ -26,7 +28,10 @@ protected:
int m_context = 0;
virtual void disposeScriptInputs();
#ifdef WITH_RIVE_SCRIPTING
LuaState* m_state = nullptr;
lua_State* m_state = nullptr;
#endif
#ifdef WITH_RIVE_TOOLS
bool hasValidVM();
#endif
public:
@@ -45,8 +50,8 @@ public:
virtual void markNeedsUpdate();
virtual DataContext* dataContext() { return nullptr; }
#ifdef WITH_RIVE_SCRIPTING
virtual bool scriptInit(LuaState* state);
LuaState* state() { return m_state; }
virtual bool scriptInit(lua_State* state);
lua_State* state() { return m_state; }
#endif
void scriptDispose();
virtual bool addScriptedDirt(ComponentDirt value, bool recurse = false) = 0;

View File

@@ -25,7 +25,7 @@ class ScriptedPathEffect : public ScriptedPathEffectBase,
{
public:
#ifdef WITH_RIVE_SCRIPTING
bool scriptInit(LuaState* state) override;
bool scriptInit(lua_State* state) override;
#endif
void addProperty(CustomProperty* prop) override;
StatusCode onAddedClean(CoreContext* context) override;

View File

@@ -45,9 +45,8 @@ void ScriptInput::initScriptedValue() {}
#ifdef WITH_RIVE_SCRIPTING
bool OptionalScriptedMethods::verifyImplementation(ScriptedObject* object,
LuaState* luaState)
lua_State* state)
{
auto state = luaState->state;
lua_pushvalue(state, -1);
if (static_cast<lua_Status>(rive_lua_pcall(state, 0, 1)) != LUA_OK)
{
@@ -161,7 +160,7 @@ bool OptionalScriptedMethods::verifyImplementation(ScriptedObject* object,
return true;
}
LuaState* ScriptAsset::vm()
lua_State* ScriptAsset::vm()
{
if (m_file == nullptr)
{
@@ -203,7 +202,8 @@ void ScriptAsset::registrationComplete(int ref)
bool ScriptAsset::initScriptedObjectWith(ScriptedObject* object)
{
#if defined(WITH_RIVE_SCRIPTING)
if (vm() == nullptr)
auto state = vm();
if (state == nullptr)
{
return false;
}
@@ -214,23 +214,22 @@ bool ScriptAsset::initScriptedObjectWith(ScriptedObject* object)
name().c_str());
return false;
}
auto vmState = vm()->state;
rive_lua_pushRef(vmState, generatorFunctionRef());
rive_lua_pushRef(state, generatorFunctionRef());
if (!m_initted)
{
if (!verifyImplementation(object, vm()))
if (!verifyImplementation(object, state))
{
fprintf(stderr,
"ScriptAsset failed to verify method implementation %s\n",
name().c_str());
rive_lua_pop(vmState, 1);
rive_lua_pop(state, 1);
return false;
}
m_initted = true;
}
object->implementedMethods(implementedMethods());
return object->scriptInit(vm());
return object->scriptInit(state);
#else
return false;
#endif

View File

@@ -19,6 +19,7 @@
#include "rive/importers/import_stack.hpp"
#ifdef WITH_RIVE_SCRIPTING
#include "rive/lua/rive_lua_libs.hpp"
#include "rive/lua/lua_state.hpp"
#endif
#include "rive/importers/keyed_object_importer.hpp"
#include "rive/importers/keyed_property_importer.hpp"
@@ -639,16 +640,15 @@ void File::makeScriptingVM()
m_scriptingContext =
rivestd::make_unique<CPPRuntimeScriptingContext>(m_factory);
m_scriptingVM = rivestd::make_unique<ScriptingVM>(m_scriptingContext.get());
m_luaState = new LuaState(m_scriptingVM->state());
m_luaState->initializeData(m_ViewModels);
m_luaState = m_scriptingVM->state();
initializeLuaData(m_luaState, m_ViewModels);
}
void File::cleanupScriptingVM()
{
m_luaState = nullptr;
if (m_scriptingVM != nullptr)
{
delete m_luaState;
m_luaState = nullptr;
m_scriptingVM.reset();
m_scriptingContext.reset();
}

View File

@@ -22,7 +22,8 @@ static int viewmodel_new(lua_State* L)
return 1;
}
void LuaState::initializeData(std::vector<ViewModel*>& viewModels)
void rive::initializeLuaData(lua_State* state,
std::vector<ViewModel*>& viewModels)
{
if (state)
{

View File

@@ -41,7 +41,7 @@ void ScriptedDataConverter::disposeScriptInputs()
}
#ifdef WITH_RIVE_SCRIPTING
bool ScriptedDataConverter::scriptInit(LuaState* state)
bool ScriptedDataConverter::scriptInit(lua_State* state)
{
ScriptedObject::scriptInit(state);
addScriptedDirt(ComponentDirt::Bindings);
@@ -50,34 +50,33 @@ bool ScriptedDataConverter::scriptInit(LuaState* state)
bool ScriptedDataConverter::pushDataValue(DataValue* value)
{
auto state = m_state->state;
// Stack: [self, field, self]
if (value->is<DataValueNumber>())
{
lua_newrive<ScriptedDataValueNumber>(
state,
state,
m_state,
m_state,
value->as<DataValueNumber>()->value());
}
else if (value->is<DataValueString>())
{
lua_newrive<ScriptedDataValueString>(
state,
state,
m_state,
m_state,
value->as<DataValueString>()->value());
}
else if (value->is<DataValueBoolean>())
{
lua_newrive<ScriptedDataValueBoolean>(
state,
state,
m_state,
m_state,
value->as<DataValueBoolean>()->value());
}
else if (value->is<DataValueColor>())
{
lua_newrive<ScriptedDataValueColor>(
state,
state,
m_state,
m_state,
value->as<DataValueColor>()->value());
}
else
@@ -94,21 +93,27 @@ DataValue* ScriptedDataConverter::applyConversion(DataValue* value,
{
return value;
}
auto state = m_state->state;
#ifdef WITH_RIVE_TOOLS
if (!hasValidVM())
{
return value;
}
#endif
// Stack: []
rive_lua_pushRef(state, m_self);
rive_lua_pushRef(m_state, m_self);
// Stack: [self]
lua_getfield(state, -1, method.c_str());
lua_getfield(m_state, -1, method.c_str());
// Stack: [self, field]
lua_pushvalue(state, -2);
lua_pushvalue(m_state, -2);
// Stack: [self, field, self]
if (pushDataValue(value))
{
// Stack: [self, field, self, ScriptedData]
if (static_cast<lua_Status>(rive_lua_pcall(state, 2, 1)) == LUA_OK)
if (static_cast<lua_Status>(rive_lua_pcall(m_state, 2, 1)) == LUA_OK)
{
auto result = (ScriptedDataValue*)lua_touserdata(state, -1);
auto result = (ScriptedDataValue*)lua_touserdata(m_state, -1);
if (result->isNumber())
{
storeData<DataValueNumber>(result->dataValue());
@@ -127,12 +132,12 @@ DataValue* ScriptedDataConverter::applyConversion(DataValue* value,
}
}
// Stack: [self, status] or [self, result]
rive_lua_pop(state, 2);
rive_lua_pop(m_state, 2);
}
else
{
// Stack: [self, field, self]
rive_lua_pop(state, 3);
rive_lua_pop(m_state, 3);
}
if (!m_dataValue)
{

View File

@@ -8,7 +8,7 @@
using namespace rive;
#ifdef WITH_RIVE_SCRIPTING
bool ScriptedDrawable::scriptInit(LuaState* state)
bool ScriptedDrawable::scriptInit(lua_State* state)
{
ScriptedObject::scriptInit(state);
addDirt(ComponentDirt::Paint);
@@ -17,11 +17,17 @@ bool ScriptedDrawable::scriptInit(LuaState* state)
void ScriptedDrawable::draw(Renderer* renderer)
{
if (!draws())
if (!draws() || !m_state)
{
return;
}
auto state = m_state->state;
#ifdef WITH_RIVE_TOOLS
if (!hasValidVM())
{
return;
}
#endif
if (m_needsSaveOperation)
{
@@ -38,24 +44,24 @@ void ScriptedDrawable::draw(Renderer* renderer)
renderer->transform(worldTransform());
// Stack: []
auto scriptedRenderer = lua_newrive<ScriptedRenderer>(state, renderer);
auto scriptedRenderer = lua_newrive<ScriptedRenderer>(m_state, renderer);
// Stack: [scriptedRenderer]
rive_lua_pushRef(state, m_self);
rive_lua_pushRef(m_state, m_self);
// Stack: [scriptedRenderer, self]
lua_getfield(state, -1, "draw");
lua_getfield(m_state, -1, "draw");
// Stack: [scriptedRenderer, self, "draw"]
lua_pushvalue(state, -2);
lua_pushvalue(m_state, -2);
// Stack: [scriptedRenderer, self, "draw", self]
lua_pushvalue(state, -4);
lua_pushvalue(m_state, -4);
// Stack: [scriptedRenderer, self, "draw", self, scriptedRenderer]
if (static_cast<lua_Status>(rive_lua_pcall(state, 2, 0)) != LUA_OK)
if (static_cast<lua_Status>(rive_lua_pcall(m_state, 2, 0)) != LUA_OK)
{
// Stack: [scriptedRenderer, self, status]
rive_lua_pop(state, 1);
rive_lua_pop(m_state, 1);
}
scriptedRenderer->end();
// Stack: [scriptedRenderer, self]
rive_lua_pop(state, 2);
rive_lua_pop(m_state, 2);
if (needsOpacitySave)
{
@@ -87,8 +93,8 @@ HitResult HitScriptedDrawable::processEvent(Vec2D position,
{
HitResult hitResult = HitResult::none;
auto scriptAsset = m_drawable->scriptAsset();
auto vm = m_drawable->state();
if (vm == nullptr || scriptAsset == nullptr ||
auto state = m_drawable->state();
if (state == nullptr || scriptAsset == nullptr ||
!handlesEvent(canHit, hitType))
{
return HitResult::none;
@@ -99,7 +105,6 @@ HitResult HitScriptedDrawable::processEvent(Vec2D position,
{
return hitResult;
}
auto state = vm->state;
rive_lua_pushRef(state, m_drawable->self());
auto mName = methodName(canHit, hitType);
if (static_cast<lua_Type>(lua_getfield(state, -1, mName.c_str())) !=

View File

@@ -8,7 +8,7 @@
using namespace rive;
#ifdef WITH_RIVE_SCRIPTING
bool ScriptedLayout::scriptInit(LuaState* state)
bool ScriptedLayout::scriptInit(lua_State* state)
{
ScriptedDrawable::scriptInit(state);
if (parent() != nullptr && parent()->is<LayoutComponent>())
@@ -24,25 +24,24 @@ void ScriptedLayout::callScriptedResize(Vec2D size)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
if (static_cast<lua_Type>(lua_getfield(state, -1, "resize")) !=
rive_lua_pushRef(m_state, m_self);
if (static_cast<lua_Type>(lua_getfield(m_state, -1, "resize")) !=
LUA_TFUNCTION)
{
fprintf(stderr, "expected resize to be a function\n");
rive_lua_pop(state, 1);
rive_lua_pop(m_state, 1);
}
else
{
lua_pushvalue(state, -2);
lua_pushvec2d(state, size);
if (static_cast<lua_Status>(rive_lua_pcall(state, 2, 0)) != LUA_OK)
lua_pushvalue(m_state, -2);
lua_pushvec2d(m_state, size);
if (static_cast<lua_Status>(rive_lua_pcall(m_state, 2, 0)) != LUA_OK)
{
fprintf(stderr, "resize failed\n");
rive_lua_pop(state, 1);
rive_lua_pop(m_state, 1);
}
}
rive_lua_pop(state, 1);
rive_lua_pop(m_state, 1);
}
Vec2D ScriptedLayout::measureLayout(float width,
@@ -56,37 +55,36 @@ Vec2D ScriptedLayout::measureLayout(float width,
}
auto measuredWidth = std::numeric_limits<float>::max();
auto measuredHeight = std::numeric_limits<float>::max();
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
if (static_cast<lua_Type>(lua_getfield(state, -1, "measure")) !=
rive_lua_pushRef(m_state, m_self);
if (static_cast<lua_Type>(lua_getfield(m_state, -1, "measure")) !=
LUA_TFUNCTION)
{
fprintf(stderr, "expected measure to be a function\n");
rive_lua_pop(state, 1);
rive_lua_pop(m_state, 1);
}
else
{
lua_pushvalue(state, -2);
if (static_cast<lua_Status>(rive_lua_pcall(state, 1, 1)) != LUA_OK)
lua_pushvalue(m_state, -2);
if (static_cast<lua_Status>(rive_lua_pcall(m_state, 1, 1)) != LUA_OK)
{
fprintf(stderr, "measure failed\n");
}
else
{
if (static_cast<lua_Type>(lua_type(state, -1)) != LUA_TVECTOR)
if (static_cast<lua_Type>(lua_type(m_state, -1)) != LUA_TVECTOR)
{
fprintf(stderr, "expected measure to return a Vec2D\n");
}
else
{
auto size = lua_tovec2d(state, -1);
auto size = lua_tovec2d(m_state, -1);
measuredWidth = size->x;
measuredHeight = size->y;
}
}
rive_lua_pop(state, 1);
rive_lua_pop(m_state, 1);
}
rive_lua_pop(state, 1);
rive_lua_pop(m_state, 1);
return Vec2D(std::min((widthMode == LayoutMeasureMode::undefined
? std::numeric_limits<float>::max()

View File

@@ -37,16 +37,15 @@ void ScriptedObject::setArtboardInput(std::string name, Artboard* artboard)
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
rive_lua_pushRef(m_state, m_self);
auto artboardInstance = artboard->instance();
artboardInstance->frameOrigin(false);
lua_newrive<ScriptedArtboard>(state,
state,
lua_newrive<ScriptedArtboard>(m_state,
m_state,
ref_rcp(scriptAsset()->file()),
std::move(artboardInstance));
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
lua_setfield(m_state, -2, name.c_str());
rive_lua_pop(m_state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
@@ -56,11 +55,10 @@ void ScriptedObject::setBooleanInput(std::string name, bool value)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_pushboolean(state, value);
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
rive_lua_pushRef(m_state, m_self);
lua_pushboolean(m_state, value);
lua_setfield(m_state, -2, name.c_str());
rive_lua_pop(m_state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
@@ -70,11 +68,10 @@ void ScriptedObject::setNumberInput(std::string name, float value)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_pushnumber(state, value);
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
rive_lua_pushRef(m_state, m_self);
lua_pushnumber(m_state, value);
lua_setfield(m_state, -2, name.c_str());
rive_lua_pop(m_state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
@@ -84,11 +81,10 @@ void ScriptedObject::setIntegerInput(std::string name, int value)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_pushunsigned(state, value);
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
rive_lua_pushRef(m_state, m_self);
lua_pushunsigned(m_state, value);
lua_setfield(m_state, -2, name.c_str());
rive_lua_pop(m_state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
@@ -98,11 +94,10 @@ void ScriptedObject::setStringInput(std::string name, std::string value)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_pushstring(state, value.c_str());
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
rive_lua_pushRef(m_state, m_self);
lua_pushstring(m_state, value.c_str());
lua_setfield(m_state, -2, name.c_str());
rive_lua_pop(m_state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
@@ -113,8 +108,7 @@ void ScriptedObject::setViewModelInput(std::string name,
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
rive_lua_pushRef(m_state, m_self);
switch (value->coreType())
{
case ViewModelInstanceViewModelBase::typeKey:
@@ -130,8 +124,8 @@ void ScriptedObject::setViewModelInput(std::string name,
return;
}
lua_newrive<ScriptedViewModel>(state,
state,
lua_newrive<ScriptedViewModel>(m_state,
m_state,
ref_rcp(vmi->viewModel()),
vmi);
break;
@@ -139,8 +133,8 @@ void ScriptedObject::setViewModelInput(std::string name,
default:
break;
}
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
lua_setfield(m_state, -2, name.c_str());
rive_lua_pop(m_state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
@@ -150,38 +144,64 @@ void ScriptedObject::trigger(std::string name)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
if (static_cast<lua_Type>(lua_getfield(state, -1, name.c_str())) !=
rive_lua_pushRef(m_state, m_self);
if (static_cast<lua_Type>(lua_getfield(m_state, -1, name.c_str())) !=
LUA_TFUNCTION)
{
rive_lua_pop(state, 2);
rive_lua_pop(m_state, 2);
return;
}
lua_pushvalue(state, -2);
rive_lua_pcall(state, 1, 0);
rive_lua_pop(state, 1);
lua_pushvalue(m_state, -2);
rive_lua_pcall(m_state, 1, 0);
rive_lua_pop(m_state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
#ifdef WITH_RIVE_TOOLS
bool ScriptedObject::hasValidVM()
{
#ifdef WITH_RIVE_SCRIPTING
if (!m_state)
{
return false;
}
if (asset())
{
auto scriptAsset = asset()->as<ScriptAsset>();
if (!scriptAsset->file() || !scriptAsset->file()->hasVM())
{
m_state = nullptr;
return false;
}
}
#endif
return true;
}
#endif
bool ScriptedObject::scriptAdvance(float elapsedSeconds)
{
if (!advances() || m_state == nullptr)
{
return false;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_getfield(state, -1, "advance");
lua_pushvalue(state, -2);
lua_pushnumber(state, elapsedSeconds);
if (static_cast<lua_Status>(rive_lua_pcall(state, 2, 1)) != LUA_OK)
#ifdef WITH_RIVE_TOOLS
if (!hasValidVM())
{
rive_lua_pop(state, 2);
return false;
}
bool result = lua_toboolean(state, -1);
rive_lua_pop(state, 2);
#endif
rive_lua_pushRef(m_state, m_self);
lua_getfield(m_state, -1, "advance");
lua_pushvalue(m_state, -2);
lua_pushnumber(m_state, elapsedSeconds);
if (static_cast<lua_Status>(rive_lua_pcall(m_state, 2, 1)) != LUA_OK)
{
rive_lua_pop(m_state, 2);
return false;
}
bool result = lua_toboolean(m_state, -1);
rive_lua_pop(m_state, 2);
return result;
}
@@ -191,35 +211,39 @@ void ScriptedObject::scriptUpdate()
{
return;
}
auto state = m_state->state;
// Stack: []
rive_lua_pushRef(state, m_self);
// Stack: [self]
lua_getfield(state, -1, "update");
// Stack: [self, field] Swap self and field
lua_insert(state, -2);
// Stack: [field, self]
if (static_cast<lua_Status>(rive_lua_pcall(state, 1, 0)) != LUA_OK)
#ifdef WITH_RIVE_TOOLS
if (!hasValidVM())
{
rive_lua_pop(state, 1);
return;
}
#endif
// Stack: []
rive_lua_pushRef(m_state, m_self);
// Stack: [self]
lua_getfield(m_state, -1, "update");
// Stack: [self, field] Swap self and field
lua_insert(m_state, -2);
// Stack: [field, self]
if (static_cast<lua_Status>(rive_lua_pcall(m_state, 1, 0)) != LUA_OK)
{
rive_lua_pop(m_state, 1);
}
}
bool ScriptedObject::scriptInit(LuaState* luaState)
bool ScriptedObject::scriptInit(lua_State* state)
{
auto state = luaState->state;
// Clean up old references if reinitializing
if (m_state != nullptr && (m_self != 0 || m_context != 0))
{
if (m_self != 0)
{
lua_unref(m_state->state, m_self);
lua_unref(m_state, m_self);
m_self = 0;
}
if (m_context != 0)
{
lua_unref(m_state->state, m_context);
lua_unref(m_state, m_context);
m_context = 0;
}
}
@@ -251,7 +275,7 @@ bool ScriptedObject::scriptInit(LuaState* luaState)
rive_lua_pop(state, 1);
// Stack: [self]
m_self = lua_ref(state, -1);
m_state = luaState;
m_state = state;
for (auto prop : m_customProperties)
{
auto scriptInput = ScriptInput::from(prop);
@@ -332,12 +356,12 @@ void ScriptedObject::scriptDispose()
if (m_state != nullptr)
{
lua_unref(m_state->state, m_self);
lua_unref(m_state->state, m_context);
lua_unref(m_state, m_self);
lua_unref(m_state, m_context);
#ifdef TESTING
// Force GC to collect any ScriptedArtboard instances created via
// instance()
lua_gc(m_state->state, LUA_GCCOLLECT, 0);
lua_gc(m_state, LUA_GCCOLLECT, 0);
#endif
}
m_state = nullptr;

View File

@@ -11,7 +11,7 @@ using namespace rive;
void ScriptedEffectPath::invalidateEffect() { m_path.rewind(); }
#ifdef WITH_RIVE_SCRIPTING
bool ScriptedPathEffect::scriptInit(LuaState* state)
bool ScriptedPathEffect::scriptInit(lua_State* state)
{
ScriptedObject::scriptInit(state);
addScriptedDirt(ComponentDirt::Paint, true);
@@ -26,6 +26,13 @@ void ScriptedPathEffect::updateEffect(PathProvider* pathProvider,
{
return;
}
#ifdef WITH_RIVE_TOOLS
if (!hasValidVM())
{
return;
}
#endif
auto effectPathIt = m_effectPaths.find(pathProvider);
if (effectPathIt != m_effectPaths.end())
{
@@ -43,35 +50,34 @@ void ScriptedPathEffect::updateEffect(PathProvider* pathProvider,
{
return;
}
auto state = m_state->state;
// Stack: []
rive_lua_pushRef(state, m_self);
rive_lua_pushRef(m_state, m_self);
// Stack: [self]
lua_getfield(state, -1, "update");
lua_getfield(m_state, -1, "update");
// Stack: [self, "update"]
lua_pushvalue(state, -2);
lua_pushvalue(m_state, -2);
// Stack: [self, "update", self]
lua_newrive<ScriptedPathData>(state, source->rawPath());
lua_newrive<ScriptedPathData>(m_state, source->rawPath());
// Stack: [self, "update", self, pathData]
lua_newrive<ScriptedNode>(state,
lua_newrive<ScriptedNode>(m_state,
nullptr,
shapePaint->parentTransformComponent());
auto scriptedNode = lua_torive<ScriptedNode>(state, -1);
auto scriptedNode = lua_torive<ScriptedNode>(m_state, -1);
scriptedNode->shapePaint(shapePaint);
// Stack: [self, "update", self, pathData, node]
if (static_cast<lua_Status>(rive_lua_pcall(state, 3, 1)) != LUA_OK)
if (static_cast<lua_Status>(rive_lua_pcall(m_state, 3, 1)) != LUA_OK)
{
fprintf(stderr, "update function failed\n");
}
else
{
// Stack: [self, outputPathData]
auto scriptedPath = (ScriptedPathData*)lua_touserdata(state, -1);
auto scriptedPath = (ScriptedPathData*)lua_touserdata(m_state, -1);
auto rawPath = path->mutableRawPath();
rawPath->addPath(scriptedPath->rawPath);
}
// Stack: [self, status] or [self, outputPathData]
rive_lua_pop(state, 2);
rive_lua_pop(m_state, 2);
}
}
#else

View File

@@ -513,7 +513,7 @@ end
ScriptedDrawable drawable;
// Create LuaState from ScriptingTest's VM state
LuaState luaState(L);
lua_State* luaState = L;
// Manually set the inits flag since we're not using ScriptAsset
// The inits flag indicates that the script has an init function
@@ -524,7 +524,7 @@ end
// ScriptingTest already left it there, so we can call scriptInit directly
// Call ScriptedObject::scriptInit directly to avoid addDirt which requires
// an artboard
CHECK(drawable.ScriptedObject::scriptInit(&luaState));
CHECK(drawable.ScriptedObject::scriptInit(luaState));
// Manually set implemented methods flags since we're not using ScriptAsset
// Check if advance function exists and set the flag
@@ -597,7 +597,7 @@ end
ScriptedLayout layout;
// Create LuaState from ScriptingTest's VM state
LuaState luaState(L);
lua_State* luaState = L;
// Manually set the inits flag since we're not using ScriptAsset
layout.implementedMethods(layout.implementedMethods() |
@@ -606,7 +606,7 @@ end
// scriptInit expects the factory function on the stack
// Call ScriptedObject::scriptInit directly to avoid addDirt which requires
// an artboard
CHECK(layout.ScriptedObject::scriptInit(&luaState));
CHECK(layout.ScriptedObject::scriptInit(luaState));
// Manually set implemented methods flags
// After scriptInit, the self table is stored in m_self
@@ -708,22 +708,22 @@ end
// Create LuaState from ScriptingTest's VM state
// Keep it in scope for the entire test since converter stores a pointer to
// it
LuaState luaState(L);
lua_State* luaState = L;
// Manually set the inits flag since we're not using ScriptAsset
converter->implementedMethods(converter->implementedMethods() |
(1 << 9)); // m_initsBit
// Verify LuaState is valid before using it
REQUIRE(luaState.state != nullptr);
REQUIRE(luaState.state == L);
REQUIRE(luaState != nullptr);
REQUIRE(luaState == L);
// scriptInit expects the factory function on the stack
// Verify stack state before calling scriptInit
REQUIRE(lua_gettop(L) == stackTop);
REQUIRE(lua_type(L, -1) == LUA_TFUNCTION);
REQUIRE(converter->ScriptedObject::scriptInit(&luaState));
REQUIRE(converter->ScriptedObject::scriptInit(luaState));
converter->addScriptedDirt(ComponentDirt::Bindings);
// Verify self() is valid before using it