Fix Lua reference leaks (fixes #638)

This commit is contained in:
Tamás Bálint Misius 2019-04-06 18:39:50 +02:00
parent 783310dc16
commit 06e2836726
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
21 changed files with 310 additions and 348 deletions

View File

@ -18,6 +18,7 @@
#ifdef LUACONSOLE #ifdef LUACONSOLE
#include "lua/LuaScriptInterface.h" #include "lua/LuaScriptInterface.h"
#include "lua/LuaScriptHelper.h" #include "lua/LuaScriptHelper.h"
#include "lua/LuaSmartRef.h"
#endif #endif
#include "hmap.h" #include "hmap.h"
#ifdef OGLR #ifdef OGLR

View File

@ -80,6 +80,7 @@ void Window::RemoveComponent(Component* c)
Components.erase(Components.begin() + i); Components.erase(Components.begin() + i);
// we're done // we're done
c->SetParentWindow(NULL);
return; return;
} }
} }

View File

@ -8,6 +8,7 @@
#include "Format.h" #include "Format.h"
#include "LuaScriptInterface.h" #include "LuaScriptInterface.h"
#include "LuaScriptHelper.h" #include "LuaScriptHelper.h"
#include "LuaSmartRef.h"
#include "Platform.h" #include "Platform.h"
#include "PowderToy.h" #include "PowderToy.h"
@ -136,7 +137,7 @@ int luacon_partsread(lua_State* l)
if (i < 0 || i >= NPART) if (i < 0 || i >= NPART)
return luaL_error(l, "array index out of bounds"); return luaL_error(l, "array index out of bounds");
lua_rawgeti(l, LUA_REGISTRYINDEX, tptPart); lua_rawgeti(l, LUA_REGISTRYINDEX, *tptPart);
cIndex = i; cIndex = i;
return 1; return 1;
} }
@ -317,12 +318,9 @@ int luatpt_element_func(lua_State *l)
{ {
int element = luaL_optint(l, 2, 0); int element = luaL_optint(l, 2, 0);
int replace = luaL_optint(l, 3, 0); int replace = luaL_optint(l, 3, 0);
int function;
lua_pushvalue(l, 1);
function = luaL_ref(l, LUA_REGISTRYINDEX);
if(element > 0 && element < PT_NUM) if(element > 0 && element < PT_NUM)
{ {
lua_el_func[element] = function; lua_el_func[element].Assign(1);
if (replace == 2) if (replace == 2)
lua_el_mode[element] = 3; //update before lua_el_mode[element] = 3; //update before
else if (replace) else if (replace)
@ -341,7 +339,7 @@ int luatpt_element_func(lua_State *l)
int element = luaL_optint(l, 2, 0); int element = luaL_optint(l, 2, 0);
if(element > 0 && element < PT_NUM) if(element > 0 && element < PT_NUM)
{ {
lua_el_func[element] = 0; lua_el_func[element].Clear();
lua_el_mode[element] = 0; lua_el_mode[element] = 0;
} }
else else
@ -390,12 +388,9 @@ int luatpt_graphics_func(lua_State *l)
if(lua_isfunction(l, 1)) if(lua_isfunction(l, 1))
{ {
int element = luaL_optint(l, 2, 0); int element = luaL_optint(l, 2, 0);
int function;
lua_pushvalue(l, 1);
function = luaL_ref(l, LUA_REGISTRYINDEX);
if (element > 0 && element < PT_NUM) if (element > 0 && element < PT_NUM)
{ {
lua_gr_func[element] = function; lua_gr_func[element].Assign(1);
luacon_ren->graphicscache[element].isready = 0; luacon_ren->graphicscache[element].isready = 0;
return 0; return 0;
} }
@ -409,7 +404,7 @@ int luatpt_graphics_func(lua_State *l)
int element = luaL_optint(l, 2, 0); int element = luaL_optint(l, 2, 0);
if (element > 0 && element < PT_NUM) if (element > 0 && element < PT_NUM)
{ {
lua_gr_func[element] = 0; lua_gr_func[element].Clear();
luacon_ren->graphicscache[element].isready = 0; luacon_ren->graphicscache[element].isready = 0;
return 0; return 0;
} }

View File

@ -20,7 +20,7 @@ Luna<LuaButton>::RegType LuaButton::methods[] = {
LuaButton::LuaButton(lua_State * l) : LuaButton::LuaButton(lua_State * l) :
LuaComponent(l), LuaComponent(l),
actionFunction(0) actionFunction(l)
{ {
int posX = luaL_optinteger(l, 1, 0); int posX = luaL_optinteger(l, 1, 0);
int posY = luaL_optinteger(l, 2, 0); int posY = luaL_optinteger(l, 2, 0);
@ -62,17 +62,7 @@ int LuaButton::enabled(lua_State * l)
int LuaButton::action(lua_State * l) int LuaButton::action(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return actionFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
actionFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
actionFunction = 0;
}
return 0;
} }
int LuaButton::text(lua_State * l) int LuaButton::text(lua_State * l)
@ -96,7 +86,7 @@ void LuaButton::triggerAction()
if(actionFunction) if(actionFunction)
{ {
lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction); lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction);
lua_rawgeti(l, LUA_REGISTRYINDEX, UserData); lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref);
if (lua_pcall(l, 1, 0, 0)) if (lua_pcall(l, 1, 0, 0))
{ {
ci->Log(CommandInterface::LogError, ByteString(lua_tostring(l, -1)).FromUtf8()); ci->Log(CommandInterface::LogError, ByteString(lua_tostring(l, -1)).FromUtf8());

View File

@ -13,7 +13,7 @@ class LuaScriptInterface;
class LuaButton: public LuaComponent class LuaButton: public LuaComponent
{ {
ui::Button * button; ui::Button * button;
int actionFunction; LuaComponentCallback actionFunction;
void triggerAction(); void triggerAction();
int action(lua_State * l); int action(lua_State * l);
int text(lua_State * l); int text(lua_State * l);

View File

@ -20,7 +20,7 @@ Luna<LuaCheckbox>::RegType LuaCheckbox::methods[] = {
LuaCheckbox::LuaCheckbox(lua_State * l) : LuaCheckbox::LuaCheckbox(lua_State * l) :
LuaComponent(l), LuaComponent(l),
actionFunction(0) actionFunction(l)
{ {
int posX = luaL_optinteger(l, 1, 0); int posX = luaL_optinteger(l, 1, 0);
int posY = luaL_optinteger(l, 2, 0); int posY = luaL_optinteger(l, 2, 0);
@ -60,17 +60,7 @@ int LuaCheckbox::checked(lua_State * l)
int LuaCheckbox::action(lua_State * l) int LuaCheckbox::action(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return actionFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
actionFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
actionFunction = 0;
}
return 0;
} }
int LuaCheckbox::text(lua_State * l) int LuaCheckbox::text(lua_State * l)
@ -93,7 +83,7 @@ void LuaCheckbox::triggerAction()
if(actionFunction) if(actionFunction)
{ {
lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction); lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction);
lua_rawgeti(l, LUA_REGISTRYINDEX, UserData); lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref);
lua_pushboolean(l, checkbox->GetChecked()); lua_pushboolean(l, checkbox->GetChecked());
if (lua_pcall(l, 2, 0, 0)) if (lua_pcall(l, 2, 0, 0))
{ {

View File

@ -13,7 +13,7 @@ class LuaScriptInterface;
class LuaCheckbox: public LuaComponent class LuaCheckbox: public LuaComponent
{ {
ui::Checkbox * checkbox; ui::Checkbox * checkbox;
int actionFunction; LuaComponentCallback actionFunction;
void triggerAction(); void triggerAction();
int action(lua_State * l); int action(lua_State * l);
int checked(lua_State * l); int checked(lua_State * l);

View File

@ -5,8 +5,17 @@
#include "LuaScriptInterface.h" #include "LuaScriptInterface.h"
#include "gui/interface/Component.h" #include "gui/interface/Component.h"
int LuaComponentCallback::CheckAndAssignArg1()
{
if (lua_type(l, 1) != LUA_TNIL)
{
luaL_checktype(l, 1, LUA_TFUNCTION);
}
LuaSmartRef::Assign(1);
return 0;
}
LuaComponent::LuaComponent(lua_State * l) LuaComponent::LuaComponent(lua_State * l) : owner_ref(LUA_REFNIL)
{ {
this->l = l; this->l = l;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "LuaLuna.h" #include "LuaLuna.h"
#include "LuaSmartRef.h"
namespace ui namespace ui
{ {
@ -9,6 +10,13 @@ namespace ui
class LuaScriptInterface; class LuaScriptInterface;
class LuaComponentCallback : public LuaSmartRef
{
public:
using LuaSmartRef::LuaSmartRef;
int CheckAndAssignArg1();
};
class LuaComponent class LuaComponent
{ {
protected: protected:
@ -19,7 +27,7 @@ protected:
int visible(lua_State * l); int visible(lua_State * l);
public: public:
LuaScriptInterface * ci; LuaScriptInterface * ci;
int UserData; int owner_ref;
ui::Component * GetComponent() { return component; } ui::Component * GetComponent() { return component; }
LuaComponent(lua_State * l); LuaComponent(lua_State * l);

View File

@ -133,9 +133,6 @@ private:
userdataType *ud = static_cast<userdataType*>(lua_newuserdata(L, sizeof(userdataType))); userdataType *ud = static_cast<userdataType*>(lua_newuserdata(L, sizeof(userdataType)));
ud->pT = obj; // store pointer to object in userdata ud->pT = obj; // store pointer to object in userdata
obj->UserData = luaL_ref(L, LUA_REGISTRYINDEX);
lua_rawgeti(L, LUA_REGISTRYINDEX, obj->UserData);
luaL_getmetatable(L, T::className); // lookup metatable in Lua registry luaL_getmetatable(L, T::className); // lookup metatable in Lua registry
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
return 1; // userdata containing pointer to T object return 1; // userdata containing pointer to T object

View File

@ -11,13 +11,16 @@ extern Renderer * luacon_ren;
extern bool *luacon_currentCommand; extern bool *luacon_currentCommand;
extern String *luacon_lastError; extern String *luacon_lastError;
extern int *lua_el_func, *lua_el_mode, *lua_gr_func; class LuaSmartRef;
extern int *lua_el_mode;
extern LuaSmartRef *lua_el_func, *lua_gr_func;
extern int getPartIndex_curIdx; extern int getPartIndex_curIdx;
extern int tptProperties; //Table for some TPT properties extern int tptProperties; //Table for some TPT properties
extern int tptPropertiesVersion; extern int tptPropertiesVersion;
extern int tptElements; //Table for TPT element names extern int tptElements; //Table for TPT element names
extern int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, tptPart, cIndex; extern int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, cIndex;
extern LuaSmartRef *tptPart;
void luaopen_eventcompat(lua_State *l); void luaopen_eventcompat(lua_State *l);
void luacon_hook(lua_State *L, lua_Debug *ar); void luacon_hook(lua_State *L, lua_Debug *ar);

View File

@ -62,13 +62,15 @@ bool *luacon_currentCommand;
String *luacon_lastError; String *luacon_lastError;
String lastCode; String lastCode;
int *lua_el_func, *lua_el_mode, *lua_gr_func; int *lua_el_mode;
LuaSmartRef *lua_el_func, *lua_gr_func;
int getPartIndex_curIdx; int getPartIndex_curIdx;
int tptProperties; //Table for some TPT properties int tptProperties; //Table for some TPT properties
int tptPropertiesVersion; int tptPropertiesVersion;
int tptElements; //Table for TPT element names int tptElements; //Table for TPT element names
int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, tptPart, cIndex; int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, cIndex;
LuaSmartRef *tptPart = nullptr;
int atPanic(lua_State *l) int atPanic(lua_State *l)
{ {
@ -261,16 +263,20 @@ tpt.partsdata = nil");
lua_setfield(l, tptProperties, "parts"); lua_setfield(l, tptProperties, "parts");
lua_newtable(l); lua_newtable(l);
tptPart = lua_gettop(l); {
lua_newtable(l); int top = lua_gettop(l);
tptPartMeta = lua_gettop(l); lua_newtable(l);
lua_pushcfunction(l, luacon_partwrite); tptPartMeta = lua_gettop(l);
lua_setfield(l, tptPartMeta, "__newindex"); lua_pushcfunction(l, luacon_partwrite);
lua_pushcfunction(l, luacon_partread); lua_setfield(l, tptPartMeta, "__newindex");
lua_setfield(l, tptPartMeta, "__index"); lua_pushcfunction(l, luacon_partread);
lua_setmetatable(l, tptPart); lua_setfield(l, tptPartMeta, "__index");
lua_setmetatable(l, top);
}
tptPart = luaL_ref(l, LUA_REGISTRYINDEX); tptPart = new LuaSmartRef(l);
tptPart->Assign(-1);
lua_pop(l, 1);
#endif #endif
lua_newtable(l); lua_newtable(l);
@ -314,14 +320,12 @@ tpt.partsdata = nil");
} }
lua_setfield(l, tptProperties, "eltransition"); lua_setfield(l, tptProperties, "eltransition");
lua_el_func = (int*)calloc(PT_NUM, sizeof(int)); lua_gr_func_v = std::vector<LuaSmartRef>(PT_NUM, l);
lua_el_mode = (int*)calloc(PT_NUM, sizeof(int)); lua_gr_func = &lua_gr_func_v[0];
lua_gr_func = (int*)calloc(PT_NUM, sizeof(int)); lua_el_func_v = std::vector<LuaSmartRef>(PT_NUM, l);
for (int i = 0; i < PT_NUM; i++) lua_el_func = &lua_el_func_v[0];
{ lua_el_mode = new int[PT_NUM];
lua_el_mode[i] = 0; std::fill(lua_el_mode, lua_el_mode + PT_NUM, 0);
lua_gr_func[i] = 0;
}
//make tpt.* a metatable //make tpt.* a metatable
lua_newtable(l); lua_newtable(l);
@ -459,47 +463,66 @@ void LuaScriptInterface::initInterfaceAPI()
int LuaScriptInterface::interface_addComponent(lua_State * l) int LuaScriptInterface::interface_addComponent(lua_State * l)
{ {
void * luaComponent = NULL; void *opaque = nullptr;
ui::Component * component = NULL; LuaComponent *luaComponent = nullptr;
if ((luaComponent = Luna<LuaButton>::tryGet(l, 1))) if ((opaque = Luna<LuaButton>::tryGet(l, 1)))
component = Luna<LuaButton>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaButton>::get(opaque);
else if ((luaComponent = Luna<LuaLabel>::tryGet(l, 1))) else if ((opaque = Luna<LuaLabel>::tryGet(l, 1)))
component = Luna<LuaLabel>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaLabel>::get(opaque);
else if ((luaComponent = Luna<LuaTextbox>::tryGet(l, 1))) else if ((opaque = Luna<LuaTextbox>::tryGet(l, 1)))
component = Luna<LuaTextbox>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaTextbox>::get(opaque);
else if ((luaComponent = Luna<LuaCheckbox>::tryGet(l, 1))) else if ((opaque = Luna<LuaCheckbox>::tryGet(l, 1)))
component = Luna<LuaCheckbox>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaCheckbox>::get(opaque);
else if ((luaComponent = Luna<LuaSlider>::tryGet(l, 1))) else if ((opaque = Luna<LuaSlider>::tryGet(l, 1)))
component = Luna<LuaSlider>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaSlider>::get(opaque);
else if ((luaComponent = Luna<LuaProgressBar>::tryGet(l, 1))) else if ((opaque = Luna<LuaProgressBar>::tryGet(l, 1)))
component = Luna<LuaProgressBar>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaProgressBar>::get(opaque);
else else
luaL_typerror(l, 1, "Component"); luaL_typerror(l, 1, "Component");
if (luacon_ci->Window && component) if (luacon_ci->Window && luaComponent)
luacon_ci->Window->AddComponent(component); {
auto ok = luacon_ci->grabbed_components.insert(std::make_pair(luaComponent, LuaSmartRef(l)));
if (ok.second)
{
auto it = ok.first;
it->second.Assign(1);
it->first->owner_ref = it->second;
}
luacon_ci->Window->AddComponent(luaComponent->GetComponent());
}
return 0; return 0;
} }
int LuaScriptInterface::interface_removeComponent(lua_State * l) int LuaScriptInterface::interface_removeComponent(lua_State * l)
{ {
void * luaComponent = NULL; void *opaque = nullptr;
ui::Component * component = NULL; LuaComponent *luaComponent = nullptr;
if ((luaComponent = Luna<LuaButton>::tryGet(l, 1))) if ((opaque = Luna<LuaButton>::tryGet(l, 1)))
component = Luna<LuaButton>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaButton>::get(opaque);
else if ((luaComponent = Luna<LuaLabel>::tryGet(l, 1))) else if ((opaque = Luna<LuaLabel>::tryGet(l, 1)))
component = Luna<LuaLabel>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaLabel>::get(opaque);
else if ((luaComponent = Luna<LuaTextbox>::tryGet(l, 1))) else if ((opaque = Luna<LuaTextbox>::tryGet(l, 1)))
component = Luna<LuaTextbox>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaTextbox>::get(opaque);
else if ((luaComponent = Luna<LuaCheckbox>::tryGet(l, 1))) else if ((opaque = Luna<LuaCheckbox>::tryGet(l, 1)))
component = Luna<LuaCheckbox>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaCheckbox>::get(opaque);
else if ((luaComponent = Luna<LuaSlider>::tryGet(l, 1))) else if ((opaque = Luna<LuaSlider>::tryGet(l, 1)))
component = Luna<LuaSlider>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaSlider>::get(opaque);
else if ((luaComponent = Luna<LuaProgressBar>::tryGet(l, 1))) else if ((opaque = Luna<LuaProgressBar>::tryGet(l, 1)))
component = Luna<LuaProgressBar>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaProgressBar>::get(opaque);
else else
luaL_typerror(l, 1, "Component"); luaL_typerror(l, 1, "Component");
if(luacon_ci->Window && component) if(luacon_ci->Window && luaComponent)
{
ui::Component *component = luaComponent->GetComponent();
luacon_ci->Window->RemoveComponent(component); luacon_ci->Window->RemoveComponent(component);
auto it = luacon_ci->grabbed_components.find(luaComponent);
if (it != luacon_ci->grabbed_components.end())
{
it->second.Clear();
it->first->owner_ref = it->second;
luacon_ci->grabbed_components.erase(it);
}
}
return 0; return 0;
} }
@ -2672,12 +2695,14 @@ int LuaScriptInterface::elements_element(lua_State * l)
lua_getfield(l, -1, "Update"); lua_getfield(l, -1, "Update");
if(lua_type(l, -1) == LUA_TFUNCTION) if(lua_type(l, -1) == LUA_TFUNCTION)
{ {
lua_el_func[id] = luaL_ref(l, LUA_REGISTRYINDEX); lua_el_func[id].Assign(-1);
lua_pop(l, 1);
lua_el_mode[id] = 1; lua_el_mode[id] = 1;
} }
else if(lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) else if(lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{ {
lua_el_func[id] = 0; lua_el_func[id].Clear();
lua_pop(l, 1);
lua_el_mode[id] = 0; lua_el_mode[id] = 0;
luacon_sim->elements[id].Update = NULL; luacon_sim->elements[id].Update = NULL;
} }
@ -2687,11 +2712,13 @@ int LuaScriptInterface::elements_element(lua_State * l)
lua_getfield(l, -1, "Graphics"); lua_getfield(l, -1, "Graphics");
if(lua_type(l, -1) == LUA_TFUNCTION) if(lua_type(l, -1) == LUA_TFUNCTION)
{ {
lua_gr_func[id] = luaL_ref(l, LUA_REGISTRYINDEX); lua_gr_func[id].Assign(-1);
lua_pop(l, 1);
} }
else if(lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) else if(lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{ {
lua_gr_func[id] = 0; lua_gr_func[id].Clear();
lua_pop(l, 1);
luacon_sim->elements[id].Graphics = NULL; luacon_sim->elements[id].Graphics = NULL;
} }
else else
@ -2781,12 +2808,11 @@ int LuaScriptInterface::elements_property(lua_State * l)
} }
else else
lua_el_mode[id] = 1; lua_el_mode[id] = 1;
lua_pushvalue(l, 3); lua_el_func[id].Assign(3);
lua_el_func[id] = luaL_ref(l, LUA_REGISTRYINDEX);
} }
else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{ {
lua_el_func[id] = 0; lua_el_func[id].Clear();
lua_el_mode[id] = 0; lua_el_mode[id] = 0;
luacon_sim->elements[id].Update = NULL; luacon_sim->elements[id].Update = NULL;
} }
@ -2795,12 +2821,11 @@ int LuaScriptInterface::elements_property(lua_State * l)
{ {
if(lua_type(l, 3) == LUA_TFUNCTION) if(lua_type(l, 3) == LUA_TFUNCTION)
{ {
lua_pushvalue(l, 3); lua_gr_func[id].Assign(3);
lua_gr_func[id] = luaL_ref(l, LUA_REGISTRYINDEX);
} }
else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{ {
lua_gr_func[id] = 0; lua_gr_func[id].Clear();
luacon_sim->elements[id].Graphics = NULL; luacon_sim->elements[id].Graphics = NULL;
} }
luacon_ren->graphicscache[id].isready = 0; luacon_ren->graphicscache[id].isready = 0;
@ -3709,6 +3734,16 @@ String LuaScriptInterface::FormatCommand(String command)
} }
LuaScriptInterface::~LuaScriptInterface() { LuaScriptInterface::~LuaScriptInterface() {
delete tptPart;
for (auto &component_and_ref : grabbed_components)
{
luacon_ci->Window->RemoveComponent(component_and_ref.first->GetComponent());
component_and_ref.second.Clear();
component_and_ref.first->owner_ref = component_and_ref.second;
}
delete[] lua_el_mode;
lua_el_func_v.clear();
lua_gr_func_v.clear();
lua_close(l); lua_close(l);
delete legacy; delete legacy;
} }

View File

@ -2,11 +2,14 @@
#define LUASCRIPTINTERFACE_H_ #define LUASCRIPTINTERFACE_H_
#include "LuaCompat.h" #include "LuaCompat.h"
#include "LuaSmartRef.h"
#include "CommandInterface.h" #include "CommandInterface.h"
#include "lua/LuaEvents.h" #include "lua/LuaEvents.h"
#include "simulation/Simulation.h" #include "simulation/Simulation.h"
#include <map>
namespace ui namespace ui
{ {
class Window; class Window;
@ -35,6 +38,7 @@ class Tool;
lua_setfield(L, -2, #NAME) lua_setfield(L, -2, #NAME)
class TPTScriptInterface; class TPTScriptInterface;
class LuaComponent;
class LuaScriptInterface: public CommandInterface class LuaScriptInterface: public CommandInterface
{ {
@ -177,6 +181,8 @@ class LuaScriptInterface: public CommandInterface
static int event_unregister(lua_State * l); static int event_unregister(lua_State * l);
static int event_getmodifiers(lua_State * l); static int event_getmodifiers(lua_State * l);
std::vector<LuaSmartRef> lua_el_func_v, lua_gr_func_v;
public: public:
int tpt_index(lua_State *l); int tpt_index(lua_State *l);
int tpt_newIndex(lua_State *l); int tpt_newIndex(lua_State *l);
@ -186,6 +192,7 @@ public:
ui::Window * Window; ui::Window * Window;
lua_State *l; lua_State *l;
std::map<LuaComponent *, LuaSmartRef> grabbed_components;
LuaScriptInterface(GameController * c, GameModel * m); LuaScriptInterface(GameController * c, GameModel * m);
void OnTick() override; void OnTick() override;

View File

@ -20,7 +20,7 @@ Luna<LuaSlider>::RegType LuaSlider::methods[] = {
LuaSlider::LuaSlider(lua_State * l) : LuaSlider::LuaSlider(lua_State * l) :
LuaComponent(l), LuaComponent(l),
onValueChangedFunction(0) onValueChangedFunction(l)
{ {
int posX = luaL_optinteger(l, 1, 0); int posX = luaL_optinteger(l, 1, 0);
int posY = luaL_optinteger(l, 2, 0); int posY = luaL_optinteger(l, 2, 0);
@ -60,17 +60,7 @@ int LuaSlider::steps(lua_State * l)
int LuaSlider::onValueChanged(lua_State * l) int LuaSlider::onValueChanged(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onValueChangedFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onValueChangedFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onValueChangedFunction = 0;
}
return 0;
} }
int LuaSlider::value(lua_State * l) int LuaSlider::value(lua_State * l)
@ -93,7 +83,7 @@ void LuaSlider::triggerOnValueChanged()
if(onValueChangedFunction) if(onValueChangedFunction)
{ {
lua_rawgeti(l, LUA_REGISTRYINDEX, onValueChangedFunction); lua_rawgeti(l, LUA_REGISTRYINDEX, onValueChangedFunction);
lua_rawgeti(l, LUA_REGISTRYINDEX, UserData); lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref);
lua_pushinteger(l, slider->GetValue()); lua_pushinteger(l, slider->GetValue());
if (lua_pcall(l, 2, 0, 0)) if (lua_pcall(l, 2, 0, 0))
{ {

View File

@ -13,7 +13,7 @@ class LuaScriptInterface;
class LuaSlider: public LuaComponent class LuaSlider: public LuaComponent
{ {
ui::Slider * slider; ui::Slider * slider;
int onValueChangedFunction; LuaComponentCallback onValueChangedFunction;
void triggerOnValueChanged(); void triggerOnValueChanged();
int onValueChanged(lua_State * l); int onValueChanged(lua_State * l);
int steps(lua_State * l); int steps(lua_State * l);

36
src/lua/LuaSmartRef.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "LuaSmartRef.h"
void LuaSmartRef::Clear()
{
luaL_unref(l, LUA_REGISTRYINDEX, ref);
ref = LUA_REFNIL;
}
LuaSmartRef::LuaSmartRef(lua_State *state) :
ref(LUA_REFNIL),
l(state)
{
}
LuaSmartRef::~LuaSmartRef()
{
Clear();
}
void LuaSmartRef::Assign(int index)
{
Clear();
lua_pushvalue(l, index);
ref = luaL_ref(l, LUA_REGISTRYINDEX);
}
LuaSmartRef::operator int() const
{
return ref;
}
LuaSmartRef::operator bool() const
{
return ref != LUA_REFNIL;
}

20
src/lua/LuaSmartRef.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include "LuaCompat.h"
class LuaSmartRef
{
int ref;
protected:
lua_State *l;
public:
LuaSmartRef(lua_State *l);
~LuaSmartRef();
void Assign(int index); // Copies the value before getting reference, stack unchanged.
void Clear();
operator int() const;
operator bool() const;
};

View File

@ -20,7 +20,7 @@ Luna<LuaTextbox>::RegType LuaTextbox::methods[] = {
LuaTextbox::LuaTextbox(lua_State * l) : LuaTextbox::LuaTextbox(lua_State * l) :
LuaComponent(l), LuaComponent(l),
onTextChangedFunction(0) onTextChangedFunction(l)
{ {
this->l = l; this->l = l;
int posX = luaL_optinteger(l, 1, 0); int posX = luaL_optinteger(l, 1, 0);
@ -64,17 +64,7 @@ int LuaTextbox::readonly(lua_State * l)
int LuaTextbox::onTextChanged(lua_State * l) int LuaTextbox::onTextChanged(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onTextChangedFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onTextChangedFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onTextChangedFunction = 0;
}
return 0;
} }
void LuaTextbox::triggerOnTextChanged() void LuaTextbox::triggerOnTextChanged()
@ -82,7 +72,7 @@ void LuaTextbox::triggerOnTextChanged()
if(onTextChangedFunction) if(onTextChangedFunction)
{ {
lua_rawgeti(l, LUA_REGISTRYINDEX, onTextChangedFunction); lua_rawgeti(l, LUA_REGISTRYINDEX, onTextChangedFunction);
lua_rawgeti(l, LUA_REGISTRYINDEX, UserData); lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref);
if (lua_pcall(l, 1, 0, 0)) if (lua_pcall(l, 1, 0, 0))
{ {
ci->Log(CommandInterface::LogError, ByteString(lua_tostring(l, -1)).FromUtf8()); ci->Log(CommandInterface::LogError, ByteString(lua_tostring(l, -1)).FromUtf8());

View File

@ -12,7 +12,7 @@ class LuaScriptInterface;
class LuaTextbox: public LuaComponent class LuaTextbox: public LuaComponent
{ {
int onTextChangedFunction; LuaComponentCallback onTextChangedFunction;
ui::Textbox * textbox; ui::Textbox * textbox;
int text(lua_State * l); int text(lua_State * l);
int readonly(lua_State * l); int readonly(lua_State * l);

View File

@ -39,20 +39,20 @@ Luna<LuaWindow>::RegType LuaWindow::methods[] = {
}; };
LuaWindow::LuaWindow(lua_State * l) : LuaWindow::LuaWindow(lua_State * l) :
onInitializedFunction(0), onInitializedFunction(l),
onExitFunction(0), onExitFunction(l),
onTickFunction(0), onTickFunction(l),
onDrawFunction(0), onDrawFunction(l),
onFocusFunction(0), onFocusFunction(l),
onBlurFunction(0), onBlurFunction(l),
onTryExitFunction(0), onTryExitFunction(l),
onTryOkayFunction(0), onTryOkayFunction(l),
onMouseMoveFunction(0), onMouseMoveFunction(l),
onMouseDownFunction(0), onMouseDownFunction(l),
onMouseUpFunction(0), onMouseUpFunction(l),
onMouseWheelFunction(0), onMouseWheelFunction(l),
onKeyPressFunction(0), onKeyPressFunction(l),
onKeyReleaseFunction(0) onKeyReleaseFunction(l)
{ {
this->l = l; this->l = l;
int posX = luaL_optinteger(l, 1, 1); int posX = luaL_optinteger(l, 1, 1);
@ -107,47 +107,66 @@ LuaWindow::LuaWindow(lua_State * l) :
int LuaWindow::addComponent(lua_State * l) int LuaWindow::addComponent(lua_State * l)
{ {
void * luaComponent = NULL; void *opaque = nullptr;
ui::Component * component = NULL; LuaComponent *luaComponent = nullptr;
if ((luaComponent = Luna<LuaButton>::tryGet(l, 1))) if ((opaque = Luna<LuaButton>::tryGet(l, 1)))
component = Luna<LuaButton>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaButton>::get(opaque);
else if ((luaComponent = Luna<LuaLabel>::tryGet(l, 1))) else if ((opaque = Luna<LuaLabel>::tryGet(l, 1)))
component = Luna<LuaLabel>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaLabel>::get(opaque);
else if ((luaComponent = Luna<LuaTextbox>::tryGet(l, 1))) else if ((opaque = Luna<LuaTextbox>::tryGet(l, 1)))
component = Luna<LuaTextbox>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaTextbox>::get(opaque);
else if ((luaComponent = Luna<LuaCheckbox>::tryGet(l, 1))) else if ((opaque = Luna<LuaCheckbox>::tryGet(l, 1)))
component = Luna<LuaCheckbox>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaCheckbox>::get(opaque);
else if ((luaComponent = Luna<LuaSlider>::tryGet(l, 1))) else if ((opaque = Luna<LuaSlider>::tryGet(l, 1)))
component = Luna<LuaSlider>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaSlider>::get(opaque);
else if ((luaComponent = Luna<LuaProgressBar>::tryGet(l, 1))) else if ((opaque = Luna<LuaProgressBar>::tryGet(l, 1)))
component = Luna<LuaProgressBar>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaProgressBar>::get(opaque);
else else
luaL_typerror(l, 1, "Component"); luaL_typerror(l, 1, "Component");
if(component) if (luaComponent)
window->AddComponent(component); {
auto ok = grabbed_components.insert(std::make_pair(luaComponent, LuaSmartRef(l)));
if (ok.second)
{
auto it = ok.first;
it->second.Assign(1);
it->first->owner_ref = it->second;
}
window->AddComponent(luaComponent->GetComponent());
}
return 0; return 0;
} }
int LuaWindow::removeComponent(lua_State * l) int LuaWindow::removeComponent(lua_State * l)
{ {
void * luaComponent = NULL; void *opaque = nullptr;
ui::Component * component = NULL; LuaComponent *luaComponent = nullptr;
if ((luaComponent = Luna<LuaButton>::tryGet(l, 1))) if ((opaque = Luna<LuaButton>::tryGet(l, 1)))
component = Luna<LuaButton>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaButton>::get(opaque);
else if ((luaComponent = Luna<LuaLabel>::tryGet(l, 1))) else if ((opaque = Luna<LuaLabel>::tryGet(l, 1)))
component = Luna<LuaLabel>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaLabel>::get(opaque);
else if ((luaComponent = Luna<LuaTextbox>::tryGet(l, 1))) else if ((opaque = Luna<LuaTextbox>::tryGet(l, 1)))
component = Luna<LuaTextbox>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaTextbox>::get(opaque);
else if ((luaComponent = Luna<LuaCheckbox>::tryGet(l, 1))) else if ((opaque = Luna<LuaCheckbox>::tryGet(l, 1)))
component = Luna<LuaCheckbox>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaCheckbox>::get(opaque);
else if ((luaComponent = Luna<LuaSlider>::tryGet(l, 1))) else if ((opaque = Luna<LuaSlider>::tryGet(l, 1)))
component = Luna<LuaSlider>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaSlider>::get(opaque);
else if ((luaComponent = Luna<LuaProgressBar>::tryGet(l, 1))) else if ((opaque = Luna<LuaProgressBar>::tryGet(l, 1)))
component = Luna<LuaProgressBar>::get(luaComponent)->GetComponent(); luaComponent = Luna<LuaProgressBar>::get(opaque);
else else
luaL_typerror(l, 1, "Component"); luaL_typerror(l, 1, "Component");
if(component) if (luaComponent)
{
ui::Component *component = luaComponent->GetComponent();
window->RemoveComponent(component); window->RemoveComponent(component);
auto it = grabbed_components.find(luaComponent);
if (it != grabbed_components.end())
{
it->second.Clear();
it->first->owner_ref = it->second;
grabbed_components.erase(it);
}
}
return 0; return 0;
} }
@ -395,217 +414,83 @@ void LuaWindow::triggerOnKeyRelease(int key, int scan, bool repeat, bool shift,
int LuaWindow::onInitialized(lua_State * l) int LuaWindow::onInitialized(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onInitializedFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onInitializedFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onInitializedFunction = 0;
}
return 0;
} }
int LuaWindow::onExit(lua_State * l) int LuaWindow::onExit(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onExitFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onExitFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onExitFunction = 0;
}
return 0;
} }
int LuaWindow::onTick(lua_State * l) int LuaWindow::onTick(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onTickFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onTickFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onTickFunction = 0;
}
return 0;
} }
int LuaWindow::onDraw(lua_State * l) int LuaWindow::onDraw(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onDrawFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onDrawFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onDrawFunction = 0;
}
return 0;
} }
int LuaWindow::onFocus(lua_State * l) int LuaWindow::onFocus(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onFocusFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onFocusFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onFocusFunction = 0;
}
return 0;
} }
int LuaWindow::onBlur(lua_State * l) int LuaWindow::onBlur(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onBlurFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onBlurFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onBlurFunction = 0;
}
return 0;
} }
int LuaWindow::onTryExit(lua_State * l) int LuaWindow::onTryExit(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onTryExitFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onTryExitFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onTryExitFunction = 0;
}
return 0;
} }
int LuaWindow::onTryOkay(lua_State * l) int LuaWindow::onTryOkay(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onTryOkayFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onTryOkayFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onTryOkayFunction = 0;
}
return 0;
} }
int LuaWindow::onMouseMove(lua_State * l) int LuaWindow::onMouseMove(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onMouseMoveFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onMouseMoveFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onMouseMoveFunction = 0;
}
return 0;
} }
int LuaWindow::onMouseDown(lua_State * l) int LuaWindow::onMouseDown(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onMouseDownFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onMouseDownFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onMouseDownFunction = 0;
}
return 0;
} }
int LuaWindow::onMouseUp(lua_State * l) int LuaWindow::onMouseUp(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onMouseUpFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onMouseUpFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onMouseUpFunction = 0;
}
return 0;
} }
int LuaWindow::onMouseWheel(lua_State * l) int LuaWindow::onMouseWheel(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onMouseWheelFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onMouseWheelFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onMouseWheelFunction = 0;
}
return 0;
} }
int LuaWindow::onKeyPress(lua_State * l) int LuaWindow::onKeyPress(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onKeyPressFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onKeyPressFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onKeyPressFunction = 0;
}
return 0;
} }
int LuaWindow::onKeyRelease(lua_State * l) int LuaWindow::onKeyRelease(lua_State * l)
{ {
if(lua_type(l, 1) != LUA_TNIL) return onKeyReleaseFunction.CheckAndAssignArg1();
{
luaL_checktype(l, 1, LUA_TFUNCTION);
lua_pushvalue(l, 1);
onKeyReleaseFunction = luaL_ref(l, LUA_REGISTRYINDEX);
}
else
{
onKeyReleaseFunction = 0;
}
return 0;
} }
LuaWindow::~LuaWindow() LuaWindow::~LuaWindow()
{ {
for (auto &component_and_ref : grabbed_components)
{
window->RemoveComponent(component_and_ref.first->GetComponent());
component_and_ref.second.Clear();
component_and_ref.first->owner_ref = component_and_ref.second;
}
window->CloseActiveWindow(); window->CloseActiveWindow();
delete window; delete window;
} }

View File

@ -1,6 +1,10 @@
#pragma once #pragma once
#include "LuaLuna.h" #include "LuaLuna.h"
#include "LuaComponent.h"
#include "LuaSmartRef.h"
#include <map>
namespace ui namespace ui
{ {
@ -10,20 +14,22 @@ namespace ui
class LuaScriptInterface; class LuaScriptInterface;
class LuaWindow class LuaWindow
{ {
int onInitializedFunction; LuaComponentCallback onInitializedFunction;
int onExitFunction; LuaComponentCallback onExitFunction;
int onTickFunction; LuaComponentCallback onTickFunction;
int onDrawFunction; LuaComponentCallback onDrawFunction;
int onFocusFunction; LuaComponentCallback onFocusFunction;
int onBlurFunction; LuaComponentCallback onBlurFunction;
int onTryExitFunction; LuaComponentCallback onTryExitFunction;
int onTryOkayFunction; LuaComponentCallback onTryOkayFunction;
int onMouseMoveFunction; LuaComponentCallback onMouseMoveFunction;
int onMouseDownFunction; LuaComponentCallback onMouseDownFunction;
int onMouseUpFunction; LuaComponentCallback onMouseUpFunction;
int onMouseWheelFunction; LuaComponentCallback onMouseWheelFunction;
int onKeyPressFunction; LuaComponentCallback onKeyPressFunction;
int onKeyReleaseFunction; LuaComponentCallback onKeyReleaseFunction;
std::map<LuaComponent *, LuaSmartRef> grabbed_components;
ui::Window * window; ui::Window * window;
lua_State * l; lua_State * l;
@ -65,7 +71,6 @@ class LuaWindow
public: public:
LuaScriptInterface * ci; LuaScriptInterface * ci;
int UserData;
static const char className[]; static const char className[];
static Luna<LuaWindow>::RegType methods[]; static Luna<LuaWindow>::RegType methods[];