more scripting features (dynamic fields)
This commit is contained in:
parent
f7bb044f48
commit
9e90ae0ee4
|
@ -67,6 +67,7 @@ SET(SOURCES
|
||||||
src/framework/core/modules.cpp
|
src/framework/core/modules.cpp
|
||||||
|
|
||||||
# framework script
|
# framework script
|
||||||
|
src/framework/script/scriptable.cpp
|
||||||
src/framework/script/luascript.cpp
|
src/framework/script/luascript.cpp
|
||||||
src/framework/script/luafunctions.cpp
|
src/framework/script/luafunctions.cpp
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,7 @@ window#enterGameWindow:
|
||||||
size: [236, 178]
|
size: [236, 178]
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
onLoad: self:getParent():lock(self)
|
onLoad: self.locked = true
|
||||||
onDestroy: self:getParent():unlock(self)
|
|
||||||
|
|
||||||
label#accountNameLabel:
|
label#accountNameLabel:
|
||||||
text: Account name
|
text: Account name
|
||||||
|
@ -52,7 +51,7 @@ window#enterGameWindow:
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
margin.bottom: 10
|
margin.bottom: 10
|
||||||
margin.right: 13
|
margin.right: 13
|
||||||
onClick: self:getParent():destroy()
|
onClick: self.parent:destroy()
|
||||||
|
|
||||||
textEdit#accountNameTextEdit:
|
textEdit#accountNameTextEdit:
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
|
@ -3,8 +3,7 @@ window#infoWindow:
|
||||||
size: [244, 221]
|
size: [244, 221]
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
onLoad: self:getParent():lock(self)
|
onLoad: self.locked = true
|
||||||
onDestroy: self:getParent():unlock(self)
|
|
||||||
|
|
||||||
panel#infoPanel:
|
panel#infoPanel:
|
||||||
skin: flatPanel
|
skin: flatPanel
|
||||||
|
@ -60,4 +59,4 @@ window#infoWindow:
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
margin.top: 191
|
margin.top: 191
|
||||||
margin.left: 188
|
margin.left: 188
|
||||||
onClick: self:getParent():destroy()
|
onClick: self.parent:destroy()
|
||||||
|
|
|
@ -49,4 +49,4 @@ panel#background:
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
margin.top: 136
|
margin.top: 136
|
||||||
onClick: App.exit()
|
onClick: onApplicationClose()
|
||||||
|
|
|
@ -5,11 +5,12 @@ end
|
||||||
|
|
||||||
function onLeaveMenuState()
|
function onLeaveMenuState()
|
||||||
mainMenu:destroy()
|
mainMenu:destroy()
|
||||||
|
mainMenu = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function onApplicationClose()
|
function onApplicationClose()
|
||||||
onLeaveMenuState()
|
onLeaveMenuState()
|
||||||
exitGame()
|
App.exit()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- here is where everything starts
|
-- here is where everything starts
|
||||||
|
|
|
@ -3,8 +3,7 @@ window#optionsWindow:
|
||||||
size: [286, 262]
|
size: [286, 262]
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
onLoad: self:getParent():lock(self)
|
onLoad: self.locked = true
|
||||||
onDestroy: self:getParent():unlock(self)
|
|
||||||
|
|
||||||
# general
|
# general
|
||||||
button#generalButton:
|
button#generalButton:
|
||||||
|
@ -111,4 +110,4 @@ window#optionsWindow:
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
margin.right: 10
|
margin.right: 10
|
||||||
margin.bottom: 13
|
margin.bottom: 13
|
||||||
onClick: self:getParent():destroy()
|
onClick: self.parent:destroy()
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
function messageBox(title, text)
|
function messageBox(title, text)
|
||||||
local messageBoxWindow = UI.load("modules/messagebox/messagebox.yml")
|
local messageBoxWindow = UI.load("modules/messagebox/messagebox.yml")
|
||||||
local messageBoxLabel = messageBoxWindow:getChildByID("messageBoxLabel")
|
local messageBoxLabel = messageBoxWindow:getChildById("messageBoxLabel")
|
||||||
local messageBoxOkButton = messageBoxWindow:getChildByID("messageBoxOkButton")
|
local messageBoxOkButton = messageBoxWindow:getChildById("messageBoxOkButton")
|
||||||
local uiRoot = UI.getRootContainer()
|
messageBoxWindow.locked = true
|
||||||
uiRoot:lock(messageBoxWindow)
|
messageBoxWindow.title = title
|
||||||
messageBoxWindow:setTitle(title)
|
messageBoxLabel.text = text
|
||||||
messageBoxLabel:setText(text)
|
|
||||||
--messageBoxWindow:setSize(messageBoxLabel:getSize() + Size{20, 20})
|
--messageBoxWindow:setSize(messageBoxLabel:getSize() + Size{20, 20})
|
||||||
messageBoxWindow:setOnDestroy(function() uiRoot:unlock(self) end)
|
messageBoxWindow.onDestroy = function() self.locked = false end
|
||||||
messageBoxOkButton:setOnClick(function() messageBoxWindow:destroy() end)
|
messageBoxOkButton.onClick = function() messageBoxWindow:destroy() end
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,11 +31,15 @@ Dispatcher g_dispatcher;
|
||||||
void Dispatcher::poll()
|
void Dispatcher::poll()
|
||||||
{
|
{
|
||||||
while(!m_taskList.empty()) {
|
while(!m_taskList.empty()) {
|
||||||
Task *task = m_taskList.top();
|
m_taskList.front()();
|
||||||
|
m_taskList.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!m_scheduledTaskList.empty()) {
|
||||||
|
ScheduledTask *task = m_scheduledTaskList.top();
|
||||||
if(g_engine.getCurrentFrameTicks() < task->ticks)
|
if(g_engine.getCurrentFrameTicks() < task->ticks)
|
||||||
break;
|
break;
|
||||||
m_taskList.pop();
|
m_scheduledTaskList.pop();
|
||||||
|
|
||||||
task->callback();
|
task->callback();
|
||||||
delete task;
|
delete task;
|
||||||
}
|
}
|
||||||
|
@ -43,10 +47,13 @@ void Dispatcher::poll()
|
||||||
|
|
||||||
void Dispatcher::scheduleTask(const SimpleCallback& callback, int delay)
|
void Dispatcher::scheduleTask(const SimpleCallback& callback, int delay)
|
||||||
{
|
{
|
||||||
m_taskList.push(new Task(g_engine.getCurrentFrameTicks() + delay, callback));
|
m_scheduledTaskList.push(new ScheduledTask(g_engine.getCurrentFrameTicks() + delay, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dispatcher::addTask(const SimpleCallback& callback)
|
void Dispatcher::addTask(const SimpleCallback& callback, bool pushFront)
|
||||||
{
|
{
|
||||||
m_taskList.push(new Task(callback));
|
if(pushFront)
|
||||||
|
m_taskList.push_front(callback);
|
||||||
|
else
|
||||||
|
m_taskList.push_back(callback);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,18 +27,18 @@
|
||||||
|
|
||||||
#include <prerequisites.h>
|
#include <prerequisites.h>
|
||||||
|
|
||||||
class Task {
|
class ScheduledTask {
|
||||||
public:
|
public:
|
||||||
inline Task(const SimpleCallback& _callback) : ticks(0), callback(_callback) { }
|
inline ScheduledTask(const SimpleCallback& _callback) : ticks(0), callback(_callback) { }
|
||||||
inline Task(int _ticks, const SimpleCallback& _callback) : ticks(_ticks), callback(_callback) { }
|
inline ScheduledTask(int _ticks, const SimpleCallback& _callback) : ticks(_ticks), callback(_callback) { }
|
||||||
inline bool operator<(const Task& other) const { return ticks > other.ticks; }
|
inline bool operator<(const ScheduledTask& other) const { return ticks > other.ticks; }
|
||||||
int ticks;
|
int ticks;
|
||||||
SimpleCallback callback;
|
SimpleCallback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
class lessTask : public std::binary_function<Task*&, Task*&, bool> {
|
class lessScheduledTask : public std::binary_function<ScheduledTask*&, ScheduledTask*&, bool> {
|
||||||
public:
|
public:
|
||||||
bool operator()(Task*& t1,Task*& t2) { return (*t1) < (*t2); }
|
bool operator()(ScheduledTask*& t1,ScheduledTask*& t2) { return (*t1) < (*t2); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dispatcher
|
class Dispatcher
|
||||||
|
@ -50,13 +50,14 @@ public:
|
||||||
void poll();
|
void poll();
|
||||||
|
|
||||||
/// Add an event
|
/// Add an event
|
||||||
void addTask(const SimpleCallback& callback);
|
void addTask(const SimpleCallback& callback, bool pushFront = false);
|
||||||
|
|
||||||
/// Schedula an event
|
/// Schedula an event
|
||||||
void scheduleTask(const SimpleCallback& callback, int delay);
|
void scheduleTask(const SimpleCallback& callback, int delay);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::priority_queue<Task*, std::vector<Task*>, lessTask> m_taskList;
|
std::list<SimpleCallback> m_taskList;
|
||||||
|
std::priority_queue<ScheduledTask*, std::vector<ScheduledTask*>, lessScheduledTask> m_scheduledTaskList;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Dispatcher g_dispatcher;
|
extern Dispatcher g_dispatcher;
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <core/engine.h>
|
#include <core/engine.h>
|
||||||
#include <core/resources.h>
|
#include <core/resources.h>
|
||||||
#include <ui/ui.h>
|
#include <ui/ui.h>
|
||||||
|
#include <core/dispatcher.h>
|
||||||
|
|
||||||
void registerLuaFunctions()
|
void registerLuaFunctions()
|
||||||
{
|
{
|
||||||
|
@ -45,31 +46,28 @@ void registerLuaFunctions()
|
||||||
g_lua.registerClass("UILayout");
|
g_lua.registerClass("UILayout");
|
||||||
|
|
||||||
// UIElement
|
// UIElement
|
||||||
g_lua.registerClass("UIElement", "UILayout");
|
g_lua.registerClass("UIElement", "UILayout");
|
||||||
g_lua.registerMemberFunction("UIElement", "setOnLoad", &lua_UIElement_setOnLoad);
|
g_lua.registerMemberField("UIElement", "onLoad", NULL, &lua_UIElement_setOnLoad);
|
||||||
g_lua.registerMemberFunction("UIElement", "setOnDestroy", &lua_UIElement_setOnDestroy);
|
g_lua.registerMemberField("UIElement", "onDestroy", NULL, &lua_UIElement_setOnDestroy);
|
||||||
g_lua.registerMemberFunction("UIElement", "getParent", &lua_UIElement_getParent);
|
g_lua.registerMemberField("UIElement", "parent", &lua_UIElement_getParent);
|
||||||
g_lua.registerMemberFunction("UIElement", "destroy", &lua_UIElement_destroy);
|
g_lua.registerMemberFunction("UIElement", "destroy", &lua_UIElement_destroy);
|
||||||
|
|
||||||
// UIContainer
|
// UIContainer
|
||||||
g_lua.registerClass("UIContainer", "UIElement");
|
g_lua.registerClass("UIContainer", "UIElement");
|
||||||
g_lua.registerMemberFunction("UIContainer", "getChildByID", &lua_UIContainer_getChildByID);
|
g_lua.registerMemberFunction("UIContainer", "getChildById", &lua_UIContainer_getChildById);
|
||||||
g_lua.registerMemberFunction("UIContainer", "lock", &lua_UIContainer_lock);
|
g_lua.registerMemberField("UIContainer", "locked", NULL, &lua_UIContainer_setLocked);
|
||||||
g_lua.registerMemberFunction("UIContainer", "unlock", &lua_UIContainer_unlock);
|
|
||||||
|
|
||||||
// UILabel
|
// UILabel
|
||||||
g_lua.registerClass("UILabel", "UIElement");
|
g_lua.registerClass("UILabel", "UIElement");
|
||||||
g_lua.registerMemberFunction("UILabel", "setText", &lua_UILabel_setText);
|
g_lua.registerMemberField("UILabel", "text", &lua_UILabel_getText, &lua_UILabel_setText);
|
||||||
g_lua.registerMemberFunction("UILabel", "getText", &lua_UILabel_getText);
|
|
||||||
|
|
||||||
// UIButton
|
// UIButton
|
||||||
g_lua.registerClass("UIButton", "UIElement");
|
g_lua.registerClass("UIButton", "UIElement");
|
||||||
g_lua.registerMemberFunction("UIButton", "setOnClick", &lua_UIButton_setOnClick);
|
g_lua.registerMemberField("UIButton", "onClick", NULL, &lua_UIButton_setOnClick);
|
||||||
|
|
||||||
// UIWindow
|
// UIWindow
|
||||||
g_lua.registerClass("UIWindow", "UIContainer");
|
g_lua.registerClass("UIWindow", "UIContainer");
|
||||||
g_lua.registerMemberFunction("UIWindow", "setTitle", &lua_UIWindow_setTitle);
|
g_lua.registerMemberField("UIWindow", "title", &lua_UIWindow_getTitle, &lua_UIWindow_setTitle);
|
||||||
g_lua.registerMemberFunction("UIWindow", "getTitle", &lua_UIWindow_getTitle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,19 +124,24 @@ int lua_UI_getRootContainer()
|
||||||
|
|
||||||
int lua_UIElement_setOnLoad()
|
int lua_UIElement_setOnLoad()
|
||||||
{
|
{
|
||||||
g_lua.moveTop(-2);
|
g_lua.insert(-2);
|
||||||
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
|
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) {
|
||||||
element->setOnLoad(g_lua.createScriptableSelfFuncCallback(g_lua.popFunction()));
|
int funcRef = g_lua.popFunction();
|
||||||
else
|
element->associateLuaRef(__FUNCTION__, funcRef);
|
||||||
|
element->setOnLoad(g_lua.createScriptableSelfFuncCallback(funcRef));
|
||||||
|
} else
|
||||||
g_lua.pop();
|
g_lua.pop();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_UIElement_setOnDestroy()
|
int lua_UIElement_setOnDestroy()
|
||||||
{
|
{
|
||||||
g_lua.moveTop(-2);
|
g_lua.insert(-2);
|
||||||
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
|
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) {
|
||||||
element->setOnDestroy(g_lua.createScriptableSelfFuncCallback(g_lua.popFunction()));
|
int funcRef = g_lua.popFunction();
|
||||||
|
element->associateLuaRef(__FUNCTION__, funcRef);
|
||||||
|
element->setOnDestroy(g_lua.createScriptableSelfFuncCallback(funcRef));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
g_lua.pop();
|
g_lua.pop();
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -157,6 +160,7 @@ int lua_UIElement_destroy()
|
||||||
{
|
{
|
||||||
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
|
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
|
||||||
element->destroy();
|
element->destroy();
|
||||||
|
g_dispatcher.addTask(boost::bind(&LuaScript::collectGarbage, &g_lua));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +168,7 @@ int lua_UIElement_destroy()
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// UIContainer
|
// UIContainer
|
||||||
|
|
||||||
int lua_UIContainer_getChildByID()
|
int lua_UIContainer_getChildById()
|
||||||
{
|
{
|
||||||
std::string id = g_lua.popString();
|
std::string id = g_lua.popString();
|
||||||
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance()))
|
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance()))
|
||||||
|
@ -174,35 +178,22 @@ int lua_UIContainer_getChildByID()
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_UIContainer_lock()
|
int lua_UIContainer_setLocked()
|
||||||
{
|
{
|
||||||
|
bool locked = g_lua.popBoolean();
|
||||||
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) {
|
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) {
|
||||||
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance()))
|
if(UIContainerPtr container = element->getParent()) {
|
||||||
g_lua.pushBoolean(container->lockElement(element));
|
if(locked)
|
||||||
else
|
container->lockElement(element);
|
||||||
g_lua.pushBoolean(false);
|
else
|
||||||
|
container->unlockElement(element);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g_lua.reportFuncErrorWithTraceback("invalid element");
|
g_lua.reportFuncErrorWithTraceback("invalid element");
|
||||||
g_lua.pushBoolean(false);
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_UIContainer_unlock()
|
|
||||||
{
|
|
||||||
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) {
|
|
||||||
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance()))
|
|
||||||
g_lua.pushBoolean(container->unlockElement(element));
|
|
||||||
else
|
|
||||||
g_lua.pushBoolean(false);
|
|
||||||
} else {
|
|
||||||
g_lua.reportFuncErrorWithTraceback("invalid element");
|
|
||||||
g_lua.pushBoolean(false);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// UILabel
|
// UILabel
|
||||||
|
|
||||||
|
@ -229,10 +220,12 @@ int lua_UILabel_getText()
|
||||||
|
|
||||||
int lua_UIButton_setOnClick()
|
int lua_UIButton_setOnClick()
|
||||||
{
|
{
|
||||||
g_lua.moveTop(-2);
|
g_lua.insert(-2);
|
||||||
if(UIButtonPtr button = boost::dynamic_pointer_cast<UIButton>(g_lua.popClassInstance()))
|
if(UIButtonPtr button = boost::dynamic_pointer_cast<UIButton>(g_lua.popClassInstance())) {
|
||||||
button->setOnClick(g_lua.createScriptableSelfFuncCallback(g_lua.popFunction()));
|
int funcRef = g_lua.popFunction();
|
||||||
else
|
button->associateLuaRef(__FUNCTION__, funcRef);
|
||||||
|
button->setOnClick(g_lua.createScriptableSelfFuncCallback(funcRef));
|
||||||
|
} else
|
||||||
g_lua.pop();
|
g_lua.pop();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,8 @@ int lua_UIElement_getParent();
|
||||||
int lua_UIElement_destroy();
|
int lua_UIElement_destroy();
|
||||||
|
|
||||||
// UIContainer
|
// UIContainer
|
||||||
int lua_UIContainer_getChildByID();
|
int lua_UIContainer_getChildById();
|
||||||
int lua_UIContainer_lock();
|
int lua_UIContainer_setLocked();
|
||||||
int lua_UIContainer_unlock();
|
|
||||||
|
|
||||||
// UILabel
|
// UILabel
|
||||||
int lua_UILabel_setText();
|
int lua_UILabel_setText();
|
||||||
|
|
|
@ -128,16 +128,37 @@ void LuaScript::reportErrorWithTraceback(const std::string& errorDesc, const cha
|
||||||
reportError(popString(), funcName);
|
reportError(popString(), funcName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LuaScript::collectGarbage()
|
||||||
|
{
|
||||||
|
for(int i=0;i<2;i++)
|
||||||
|
lua_gc(L, LUA_GCCOLLECT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int LuaScript::getStackSize()
|
int LuaScript::getStackSize()
|
||||||
{
|
{
|
||||||
return lua_gettop(L);
|
return lua_gettop(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaScript::moveTop(int index)
|
void LuaScript::insert(int index)
|
||||||
{
|
{
|
||||||
lua_insert(L, index);
|
lua_insert(L, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LuaScript::ref()
|
||||||
|
{
|
||||||
|
return luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScript::unref(int ref)
|
||||||
|
{
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScript::getRef(int ref)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||||
|
}
|
||||||
|
|
||||||
void LuaScript::pop(int n)
|
void LuaScript::pop(int n)
|
||||||
{
|
{
|
||||||
lua_pop(L, n);
|
lua_pop(L, n);
|
||||||
|
@ -191,11 +212,16 @@ void LuaScript::pushUserdata(void* ptr)
|
||||||
lua_pushlightuserdata(L, ptr);
|
lua_pushlightuserdata(L, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LuaScript::pushValue(int index)
|
||||||
|
{
|
||||||
|
lua_pushvalue(L, index);
|
||||||
|
}
|
||||||
|
|
||||||
void LuaScript::pushClassInstance(const ScriptablePtr& object)
|
void LuaScript::pushClassInstance(const ScriptablePtr& object)
|
||||||
{
|
{
|
||||||
if(object) {
|
if(object) {
|
||||||
// create weak_ptr to the scriptable object stored as userdata
|
// create weak_ptr to the scriptable object stored as userdata
|
||||||
new(lua_newuserdata(L, sizeof(ScriptableWeakPtr))) ScriptableWeakPtr(object);
|
new(lua_newuserdata(L, sizeof(ScriptablePtr))) ScriptablePtr(object);
|
||||||
// set object metatable
|
// set object metatable
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, (std::string(object->getScriptableName()) + "_mt").c_str());
|
lua_getfield(L, LUA_REGISTRYINDEX, (std::string(object->getScriptableName()) + "_mt").c_str());
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
|
@ -208,7 +234,7 @@ ScriptablePtr LuaScript::popClassInstance()
|
||||||
{
|
{
|
||||||
ScriptablePtr object;
|
ScriptablePtr object;
|
||||||
if(lua_isuserdata(L, -1)) { // instances are store as userdata
|
if(lua_isuserdata(L, -1)) { // instances are store as userdata
|
||||||
object = ((ScriptableWeakPtr *)lua_touserdata(L, -1))->lock();
|
object = *((ScriptablePtr *)lua_touserdata(L, -1));
|
||||||
if(!object)
|
if(!object)
|
||||||
reportErrorWithTraceback("attempt to retrive class instance from a object that is already expired");
|
reportErrorWithTraceback("attempt to retrive class instance from a object that is already expired");
|
||||||
} else if(!lua_isnil(L, -1)) // we accept nil values
|
} else if(!lua_isnil(L, -1)) // we accept nil values
|
||||||
|
@ -224,18 +250,18 @@ void LuaScript::pushFunction(int functionRef)
|
||||||
|
|
||||||
int LuaScript::popFunction()
|
int LuaScript::popFunction()
|
||||||
{
|
{
|
||||||
return luaL_ref(L, LUA_REGISTRYINDEX);
|
return ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaScript::releaseFunction(int functionRef)
|
void LuaScript::releaseFunction(int functionRef)
|
||||||
{
|
{
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, functionRef);
|
unref(functionRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaScript::callFunction(int numArgs)
|
void LuaScript::callFunction(int numArgs)
|
||||||
{
|
{
|
||||||
int size = lua_gettop(L);
|
int size = lua_gettop(L);
|
||||||
int errorIndex = size - numArgs;
|
int errorIndex = -(numArgs + 2);
|
||||||
lua_pushcfunction(L, &LuaScript::luaErrorHandler);
|
lua_pushcfunction(L, &LuaScript::luaErrorHandler);
|
||||||
lua_insert(L, errorIndex);
|
lua_insert(L, errorIndex);
|
||||||
|
|
||||||
|
@ -244,9 +270,10 @@ void LuaScript::callFunction(int numArgs)
|
||||||
reportError(popString());
|
reportError(popString());
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_remove(L, errorIndex);
|
// pop error func
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
if(lua_gettop(L) + numArgs + 1 != size)
|
if(lua_gettop(L) != size - numArgs - 1)
|
||||||
reportError("stack size changed!");
|
reportError("stack size changed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,18 +288,20 @@ SimpleCallback LuaScript::createSimpleFuncCallback(int funcRef)
|
||||||
boost::function<void(ScriptablePtr)> LuaScript::createScriptableSelfFuncCallback(int funcRef)
|
boost::function<void(ScriptablePtr)> LuaScript::createScriptableSelfFuncCallback(int funcRef)
|
||||||
{
|
{
|
||||||
return [this, funcRef](ScriptablePtr scriptable) {
|
return [this, funcRef](ScriptablePtr scriptable) {
|
||||||
|
pushClassInstance(scriptable);
|
||||||
|
setGlobal("self");
|
||||||
|
|
||||||
pushFunction(funcRef);
|
pushFunction(funcRef);
|
||||||
setLocal(scriptable, "self");
|
|
||||||
callFunction();
|
callFunction();
|
||||||
|
|
||||||
|
pushNil();
|
||||||
|
setGlobal("self");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaScript::setLocal(const ScriptablePtr& scriptable, const char *varName, int envIndex)
|
void LuaScript::setGlobal(const char *varName)
|
||||||
{
|
{
|
||||||
lua_getfenv(L, envIndex);
|
lua_setfield(L, LUA_GLOBALSINDEX, varName);
|
||||||
pushClassInstance(scriptable);
|
|
||||||
lua_setfield(L, -2, varName);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaScript::setupPackageLoader()
|
void LuaScript::setupPackageLoader()
|
||||||
|
@ -295,46 +324,78 @@ void LuaScript::setupPackageLoader()
|
||||||
void LuaScript::registerClass(const std::string& klass, const std::string& baseClass)
|
void LuaScript::registerClass(const std::string& klass, const std::string& baseClass)
|
||||||
{
|
{
|
||||||
// klass_mt = {}
|
// klass_mt = {}
|
||||||
lua_newtable(L); // klass metatable
|
lua_newtable(L);
|
||||||
lua_pushvalue(L, -1); // another reference to the metatable
|
lua_pushvalue(L, -1);
|
||||||
lua_setfield(L, LUA_REGISTRYINDEX, (klass + "_mt").c_str()); // register the metatable at registry index
|
lua_setfield(L, LUA_REGISTRYINDEX, (klass + "_mt").c_str());
|
||||||
|
|
||||||
// set __gc metamethod, which collects userdata
|
// set __index metamethod
|
||||||
lua_pushcfunction(L, &LuaScript::luaCollectClassInstance);
|
lua_pushcfunction(L, &LuaScript::luaIndexMetaMethod);
|
||||||
lua_setfield(L, -2, "__gc");
|
|
||||||
|
|
||||||
// set __eq metamethod
|
|
||||||
lua_pushcfunction(L, &LuaScript::luaCompareClassInstances);
|
|
||||||
lua_setfield(L, -2, "__eq");
|
|
||||||
|
|
||||||
// klass = {}
|
|
||||||
lua_newtable(L); // klass table
|
|
||||||
lua_pushvalue(L, -1); // another reference to the table
|
|
||||||
lua_setfield(L, LUA_GLOBALSINDEX, klass.c_str()); // register at globals index
|
|
||||||
|
|
||||||
// klass.className = "klass"
|
|
||||||
lua_pushstring(L, klass.c_str());
|
|
||||||
lua_setfield(L, -2, "className");
|
|
||||||
|
|
||||||
// klass_mt.__index = klass
|
|
||||||
lua_setfield(L, -2, "__index");
|
lua_setfield(L, -2, "__index");
|
||||||
|
|
||||||
// pop the class metatable
|
// set __newindex metamethod
|
||||||
|
lua_pushcfunction(L, &LuaScript::luaNewIndexMetaMethod);
|
||||||
|
lua_setfield(L, -2, "__newindex");
|
||||||
|
|
||||||
|
// set __eq metamethod
|
||||||
|
lua_pushcfunction(L, &LuaScript::luaEqualMetaMethod);
|
||||||
|
lua_setfield(L, -2, "__eq");
|
||||||
|
|
||||||
|
// set __gc metamethod, which collects userdata
|
||||||
|
lua_pushcfunction(L, &LuaScript::luaGarbageCollectMetaMethod);
|
||||||
|
lua_setfield(L, -2, "__gc");
|
||||||
|
|
||||||
|
// klass_mt.methods = { }
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_setfield(L, LUA_GLOBALSINDEX, klass.c_str());
|
||||||
|
lua_setfield(L, -2, "methods");
|
||||||
|
|
||||||
|
// klass_mt.fieldmethods = { }
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_setfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str());
|
||||||
|
lua_setfield(L, -2, "fieldmethods");
|
||||||
|
|
||||||
|
if(baseClass.length()) {
|
||||||
|
// klass_mt.base = baseClass_mt
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, (baseClass + "_mt").c_str());
|
||||||
|
lua_setfield(L, -2, "base");
|
||||||
|
}
|
||||||
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if(baseClass.length() > 0) {
|
void LuaScript::registerMemberField(const std::string& klass, const std::string& field, LuaScript::LuaCFunction getFunction, LuaScript::LuaCFunction setFunction)
|
||||||
// add klass table to the top of the stack
|
{
|
||||||
lua_getfield(L, LUA_GLOBALSINDEX, klass.c_str());
|
if(getFunction) {
|
||||||
|
int functionId = m_functions.size();
|
||||||
|
m_functions.push_back(getFunction);
|
||||||
|
|
||||||
// redirect = { __index = baseClass }
|
// push the class table
|
||||||
lua_newtable(L);
|
lua_getfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str());
|
||||||
lua_getfield(L, LUA_GLOBALSINDEX, baseClass.c_str());
|
// push the function id
|
||||||
lua_setfield(L, -2, "__index");
|
lua_pushnumber(L, functionId);
|
||||||
|
// store id in the closure
|
||||||
|
lua_pushcclosure(L, &LuaScript::luaFunctionCallback, 1);
|
||||||
|
// store the function at the class field functionName
|
||||||
|
lua_setfield(L, -2, ("get_" + field).c_str());
|
||||||
|
// pop the table
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// setmetatable(klass, redirect)
|
if(setFunction) {
|
||||||
lua_setmetatable(L, -2);
|
int functionId = m_functions.size();
|
||||||
|
m_functions.push_back(setFunction);
|
||||||
|
|
||||||
// pop the derived class table
|
// push the class table
|
||||||
|
lua_getfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str());
|
||||||
|
// push the function id
|
||||||
|
lua_pushnumber(L, functionId);
|
||||||
|
// store id in the closure
|
||||||
|
lua_pushcclosure(L, &LuaScript::luaFunctionCallback, 1);
|
||||||
|
// store the function at the class field functionName
|
||||||
|
lua_setfield(L, -2, ("set_" + field).c_str());
|
||||||
|
// pop the table
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,24 +450,106 @@ int LuaScript::luaPackageLoader(lua_State* L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LuaScript::luaCollectClassInstance(lua_State* L)
|
int LuaScript::luaIndexMetaMethod(lua_State* L)
|
||||||
{
|
{
|
||||||
ScriptableWeakPtr *objectRef = (ScriptableWeakPtr *)lua_touserdata(L, -1);
|
std::string key = lua_tostring(L, -1); // key, obj
|
||||||
objectRef->reset();
|
lua_pop(L, 1); // obj
|
||||||
|
lua_getmetatable(L, -1); // mt, obj
|
||||||
|
while(!lua_isnil(L, -1)) {
|
||||||
|
lua_getfield(L, -1, "fieldmethods"); // mt.fieldmethods, mt, obj
|
||||||
|
lua_getfield(L, -1, ("get_" + key).c_str()); // mt.fieldmethods[get_key], mt.fieldmethods, mt, obj
|
||||||
|
lua_remove(L, -2); // mt.fieldmethods[get_key], mt, obj
|
||||||
|
if(!lua_isnil(L, -1)) {
|
||||||
|
lua_remove(L, -2); // mt.fieldmethods[get_key], obj
|
||||||
|
lua_insert(L, -2); // obj, mt.fieldmethods[get_key]
|
||||||
|
lua_pushcfunction(L, &LuaScript::luaErrorHandler); // errorfunc, obj, mt.fieldmethods[get_key]
|
||||||
|
lua_insert(L, -3); // obj, mt.fieldmethods[get_key], errorfunc
|
||||||
|
int ret = lua_pcall(L, 1, 1, -3); // ret, errorfunc
|
||||||
|
if(ret != 0) {
|
||||||
|
g_lua.reportError(g_lua.popString()); // errofunc
|
||||||
|
lua_pop(L, 1); // (empty)
|
||||||
|
lua_pushnil(L); // nil
|
||||||
|
} else {
|
||||||
|
lua_remove(L, -2); // ret
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
lua_pop(L, 1); // mt, obj
|
||||||
|
lua_getfield(L, -1, "methods"); // mt.methods, mt, obj
|
||||||
|
lua_getfield(L, -1, key.c_str()); // mt.methods[key], mt.methods, mt, obj
|
||||||
|
lua_remove(L, -2); // mt.methods[key], mt, obj
|
||||||
|
if(!lua_isnil(L, -1)) {
|
||||||
|
lua_insert(L, -3);
|
||||||
|
lua_pop(L, 2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_getfield(L, -1, "base"); // mt.base, mt, obj
|
||||||
|
lua_remove(L, -2); // mt.base, obj
|
||||||
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
ScriptablePtr scriptable = g_lua.popClassInstance();
|
||||||
|
int refId = scriptable->getLuaRef(key);
|
||||||
|
if(refId != -1)
|
||||||
|
g_lua.getRef(refId);
|
||||||
|
else
|
||||||
|
g_lua.pushNil();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LuaScript::luaCompareClassInstances(lua_State* L)
|
int LuaScript::luaNewIndexMetaMethod(lua_State* L)
|
||||||
|
{
|
||||||
|
// stack: value, key, obj
|
||||||
|
lua_insert(L, -2);
|
||||||
|
std::string key = lua_tostring(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_getmetatable(L, -2);
|
||||||
|
// stack: mt, value, obj
|
||||||
|
while(!lua_isnil(L, -1)) {
|
||||||
|
lua_getfield(L, -1, "fieldmethods");
|
||||||
|
lua_getfield(L, -1, ("set_" + key).c_str());
|
||||||
|
lua_remove(L, -2); // stack: set method, mt, value, obj
|
||||||
|
if(!lua_isnil(L, -1)) {
|
||||||
|
lua_remove(L, -2); // mt.fieldmethods[get_key], value, obj
|
||||||
|
lua_insert(L, -3); // value, obj, mt.fieldmethods[get_key]
|
||||||
|
lua_pushcfunction(L, &LuaScript::luaErrorHandler); // errorfunc, value, obj, mt.fieldmethods[get_key]
|
||||||
|
lua_insert(L, -4); // value, obj, mt.fieldmethods[get_key], errorfunc
|
||||||
|
int ret = lua_pcall(L, 2, 0, -4); // errorfunc
|
||||||
|
if(ret != 0)
|
||||||
|
g_lua.reportError(g_lua.popString()); // errofunc
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_pop(L, 1); // mt, value, obj
|
||||||
|
lua_getfield(L, -1, "base"); // mt.base, mt, value, obj
|
||||||
|
lua_remove(L, -2); // mt.base, value, obj
|
||||||
|
}
|
||||||
|
|
||||||
|
// stack:
|
||||||
|
g_lua.pop(); // value, obj
|
||||||
|
g_lua.insert(-2); // obj, value
|
||||||
|
ScriptablePtr scriptable = g_lua.popClassInstance();
|
||||||
|
g_lua.pushValue(); // value, value
|
||||||
|
int refId = g_lua.ref();
|
||||||
|
scriptable->associateLuaRef(key, refId);
|
||||||
|
g_lua.pop();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LuaScript::luaEqualMetaMethod(lua_State* L)
|
||||||
{
|
{
|
||||||
if(!lua_isuserdata(L, -1) || !lua_isuserdata(L, -2)) {
|
if(!lua_isuserdata(L, -1) || !lua_isuserdata(L, -2)) {
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
} else {
|
} else {
|
||||||
ScriptableWeakPtr *objectRef1 = (ScriptableWeakPtr *)lua_touserdata(L, -1);
|
ScriptablePtr *objectRef1 = (ScriptablePtr *)lua_touserdata(L, -1);
|
||||||
ScriptableWeakPtr *objectRef2 = (ScriptableWeakPtr *)lua_touserdata(L, -2);
|
ScriptablePtr *objectRef2 = (ScriptablePtr *)lua_touserdata(L, -2);
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
if(objectRef1->lock() == objectRef2->lock())
|
if(objectRef1 == objectRef2)
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
else
|
else
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
|
@ -414,6 +557,14 @@ int LuaScript::luaCompareClassInstances(lua_State* L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LuaScript::luaGarbageCollectMetaMethod(lua_State* L)
|
||||||
|
{
|
||||||
|
ScriptablePtr *objectRef = (ScriptablePtr *)lua_touserdata(L, -1);
|
||||||
|
objectRef->reset();
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int LuaScript::luaFunctionCallback(lua_State* L)
|
int LuaScript::luaFunctionCallback(lua_State* L)
|
||||||
{
|
{
|
||||||
// look for function id
|
// look for function id
|
||||||
|
|
|
@ -45,14 +45,20 @@ public:
|
||||||
void reportError(const std::string& errorDesc, const char *funcName = NULL);
|
void reportError(const std::string& errorDesc, const char *funcName = NULL);
|
||||||
void reportErrorWithTraceback(const std::string& errorDesc, const char *funcName = NULL);
|
void reportErrorWithTraceback(const std::string& errorDesc, const char *funcName = NULL);
|
||||||
|
|
||||||
|
void collectGarbage();
|
||||||
int getStackSize();
|
int getStackSize();
|
||||||
void moveTop(int index);
|
void insert(int index);
|
||||||
|
|
||||||
|
int ref();
|
||||||
|
void unref(int ref);
|
||||||
|
void getRef(int ref);
|
||||||
|
|
||||||
void pushNil();
|
void pushNil();
|
||||||
void pushBoolean(bool b);
|
void pushBoolean(bool b);
|
||||||
void pushInteger(int i);
|
void pushInteger(int i);
|
||||||
void pushString(const std::string& str);
|
void pushString(const std::string& str);
|
||||||
void pushUserdata(void* ptr);
|
void pushUserdata(void* ptr);
|
||||||
|
void pushValue(int index = -1);
|
||||||
|
|
||||||
void pop(int n = 1);
|
void pop(int n = 1);
|
||||||
bool popBoolean();
|
bool popBoolean();
|
||||||
|
@ -67,7 +73,7 @@ public:
|
||||||
SimpleCallback createSimpleFuncCallback(int funcRef);
|
SimpleCallback createSimpleFuncCallback(int funcRef);
|
||||||
boost::function<void(ScriptablePtr)> createScriptableSelfFuncCallback(int funcRef);
|
boost::function<void(ScriptablePtr)> createScriptableSelfFuncCallback(int funcRef);
|
||||||
|
|
||||||
void setLocal(const ScriptablePtr& scriptable, const char *varName, int envIndex = -1);
|
void setGlobal(const char *varName);
|
||||||
|
|
||||||
void pushClassInstance(const ScriptablePtr& object);
|
void pushClassInstance(const ScriptablePtr& object);
|
||||||
ScriptablePtr popClassInstance();
|
ScriptablePtr popClassInstance();
|
||||||
|
@ -76,14 +82,19 @@ public:
|
||||||
|
|
||||||
void setupPackageLoader();
|
void setupPackageLoader();
|
||||||
void registerClass(const std::string& klass, const std::string& baseClass = "");
|
void registerClass(const std::string& klass, const std::string& baseClass = "");
|
||||||
|
void registerMemberField(const std::string& klass, const std::string& field, LuaCFunction getFunction, LuaCFunction setFunction = NULL);
|
||||||
void registerMemberFunction(const std::string& klass, const std::string& functionName, LuaCFunction function);
|
void registerMemberFunction(const std::string& klass, const std::string& functionName, LuaCFunction function);
|
||||||
void registerGlobalFunction(const std::string& functionName, LuaCFunction function);
|
void registerGlobalFunction(const std::string& functionName, LuaCFunction function);
|
||||||
void registerModule(const std::string& module);
|
void registerModule(const std::string& module);
|
||||||
|
|
||||||
static int luaFunctionCallback(lua_State* L);
|
|
||||||
static int luaPackageLoader(lua_State* L);
|
static int luaPackageLoader(lua_State* L);
|
||||||
static int luaCollectClassInstance(lua_State* L);
|
|
||||||
static int luaCompareClassInstances(lua_State* L);
|
static int luaIndexMetaMethod(lua_State* L);
|
||||||
|
static int luaNewIndexMetaMethod(lua_State* L);
|
||||||
|
static int luaEqualMetaMethod(lua_State* L);
|
||||||
|
static int luaGarbageCollectMetaMethod(lua_State* L);
|
||||||
|
|
||||||
|
static int luaFunctionCallback(lua_State* L);
|
||||||
static int luaErrorHandler(lua_State *L);
|
static int luaErrorHandler(lua_State *L);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <prerequisites.h>
|
||||||
|
#include <script/scriptable.h>
|
||||||
|
#include <script/luascript.h>
|
||||||
|
#include <core/dispatcher.h>
|
||||||
|
|
||||||
|
void Scriptable::associateLuaRef(const std::string& refName, int refId)
|
||||||
|
{
|
||||||
|
// check if there is already a ref with this name
|
||||||
|
if(m_luaRefs.find(refName) != m_luaRefs.end())
|
||||||
|
g_lua.unref(m_luaRefs[refName]);
|
||||||
|
m_luaRefs[refName] = refId;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Scriptable::getLuaRef(const std::string& refName)
|
||||||
|
{
|
||||||
|
if(m_luaRefs.find(refName) != m_luaRefs.end())
|
||||||
|
return m_luaRefs[refName];
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scriptable::clearLuaRefs()
|
||||||
|
{
|
||||||
|
foreach(auto pair, m_luaRefs) {
|
||||||
|
g_lua.unref(pair.second);
|
||||||
|
}
|
||||||
|
m_luaRefs.clear();
|
||||||
|
}
|
|
@ -31,9 +31,15 @@ class Scriptable : public boost::enable_shared_from_this<Scriptable>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual const char *getScriptableName() const { return NULL; }
|
virtual const char *getScriptableName() const { return NULL; }
|
||||||
|
|
||||||
|
void associateLuaRef(const std::string& refName, int refId);
|
||||||
|
int getLuaRef(const std::string& refName);
|
||||||
|
void clearLuaRefs();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, int> m_luaRefs;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef boost::shared_ptr<Scriptable> ScriptablePtr;
|
typedef boost::shared_ptr<Scriptable> ScriptablePtr;
|
||||||
typedef boost::weak_ptr<Scriptable> ScriptableWeakPtr;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -66,6 +66,9 @@ void UIContainer::removeChild(UIElementPtr child)
|
||||||
if(m_focusedElement == child)
|
if(m_focusedElement == child)
|
||||||
setFocusedElement(UIElementPtr());
|
setFocusedElement(UIElementPtr());
|
||||||
|
|
||||||
|
// try to unlock
|
||||||
|
unlockElement(child);
|
||||||
|
|
||||||
// remove from children list
|
// remove from children list
|
||||||
m_children.remove(child);
|
m_children.remove(child);
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,17 @@ void UIElement::internalOnDestroy()
|
||||||
getParent()->removeChild(me);
|
getParent()->removeChild(me);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// free script stuff
|
||||||
|
clearLuaRefs();
|
||||||
|
|
||||||
|
g_dispatcher.addTask(boost::bind(&UIElement::internalDestroyCheck, asUIElement()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIElement::internalDestroyCheck()
|
||||||
|
{
|
||||||
|
//logTraceDebug(getId());
|
||||||
|
|
||||||
|
UIElementPtr me = asUIElement();
|
||||||
// check for leaks, the number of references must be always 2 here
|
// check for leaks, the number of references must be always 2 here
|
||||||
if(me.use_count() != 2 && me != UIContainer::getRoot()) {
|
if(me.use_count() != 2 && me != UIContainer::getRoot()) {
|
||||||
flogWarning("destroyed element with id '%s', but it still have %d references left", getId() % (me.use_count()-2));
|
flogWarning("destroyed element with id '%s', but it still have %d references left", getId() % (me.use_count()-2));
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
/// Destroy this element by removing it from its parent
|
/// Destroy this element by removing it from its parent
|
||||||
void destroy();
|
void destroy();
|
||||||
virtual void internalOnDestroy();
|
virtual void internalOnDestroy();
|
||||||
|
virtual void internalDestroyCheck();
|
||||||
|
|
||||||
/// Draw element
|
/// Draw element
|
||||||
virtual void render();
|
virtual void render();
|
||||||
|
|
|
@ -215,7 +215,7 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
|
||||||
// load events
|
// load events
|
||||||
if(node.FindValue("onLoad")) {
|
if(node.FindValue("onLoad")) {
|
||||||
const YAML::Node& cnode = node["onLoad"];
|
const YAML::Node& cnode = node["onLoad"];
|
||||||
int funcRef = g_lua.loadBufferAsFunction(cnode.Read<std::string>());
|
int funcRef = g_lua.loadBufferAsFunction(cnode.Read<std::string>(), element->getId() + ":onLoad");
|
||||||
if(funcRef != LUA_REFNIL) {
|
if(funcRef != LUA_REFNIL) {
|
||||||
g_lua.pushClassInstance(element);
|
g_lua.pushClassInstance(element);
|
||||||
g_lua.pushFunction(funcRef);
|
g_lua.pushFunction(funcRef);
|
||||||
|
@ -226,7 +226,7 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
|
||||||
|
|
||||||
if(node.FindValue("onDestroy")) {
|
if(node.FindValue("onDestroy")) {
|
||||||
const YAML::Node& cnode = node["onDestroy"];
|
const YAML::Node& cnode = node["onDestroy"];
|
||||||
int funcRef = g_lua.loadBufferAsFunction(cnode.Read<std::string>());
|
int funcRef = g_lua.loadBufferAsFunction(cnode.Read<std::string>(), element->getId() + ":onDestroy");
|
||||||
if(funcRef != LUA_REFNIL) {
|
if(funcRef != LUA_REFNIL) {
|
||||||
g_lua.pushClassInstance(element);
|
g_lua.pushClassInstance(element);
|
||||||
g_lua.pushFunction(funcRef);
|
g_lua.pushFunction(funcRef);
|
||||||
|
@ -314,7 +314,7 @@ void UILoader::loadButton(const UIButtonPtr& button, const YAML::Node& node)
|
||||||
|
|
||||||
// set on click event
|
// set on click event
|
||||||
if(node.FindValue("onClick")) {
|
if(node.FindValue("onClick")) {
|
||||||
int funcRef = g_lua.loadBufferAsFunction(node["onClick"].Read<std::string>());
|
int funcRef = g_lua.loadBufferAsFunction(node["onClick"].Read<std::string>(), button->getId() + ":onClick");
|
||||||
if(funcRef != LUA_REFNIL) {
|
if(funcRef != LUA_REFNIL) {
|
||||||
g_lua.pushClassInstance(button);
|
g_lua.pushClassInstance(button);
|
||||||
g_lua.pushFunction(funcRef);
|
g_lua.pushFunction(funcRef);
|
||||||
|
|
Loading…
Reference in New Issue