From 1c3e6302370a094092803e7dc5d1660e6e1683f1 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Mon, 23 Jul 2012 21:22:38 -0300 Subject: [PATCH] Improve modules and sandbox system --- modules/client_terminal/terminal.lua | 3 +- modules/corelib/util.lua | 51 +++++++-- modules/game_skills/skills.lua | 138 +++++++++++------------ modules/game_skills/skills.otmod | 11 +- modules/game_skills/skills.otui | 4 +- src/framework/core/module.cpp | 38 +++++-- src/framework/core/module.h | 2 + src/framework/core/resourcemanager.cpp | 4 +- src/framework/luaengine/luainterface.cpp | 114 +++++++++++++------ src/framework/luaengine/luainterface.h | 15 ++- src/framework/luafunctions.cpp | 2 + src/framework/ui/uiwidgetbasestyle.cpp | 1 + 12 files changed, 238 insertions(+), 145 deletions(-) diff --git a/modules/client_terminal/terminal.lua b/modules/client_terminal/terminal.lua index 2c88bf00..3d685bc6 100644 --- a/modules/client_terminal/terminal.lua +++ b/modules/client_terminal/terminal.lua @@ -12,7 +12,8 @@ local MaxHistory = 1000 local terminalWindow local terminalButton local logLocked = false -local commandEnv = newenv() +local commandEnv = {} +setmetatable(commandEnv, { __index = getfenv() } ) local commandTextEdit local terminalBuffer local commandHistory = { } diff --git a/modules/corelib/util.lua b/modules/corelib/util.lua index eead1ee2..066638e1 100644 --- a/modules/corelib/util.lua +++ b/modules/corelib/util.lua @@ -110,6 +110,46 @@ function extends(base) return derived end +function runinsandbox(func, ...) + if type(func) == 'string' then + func, err = loadfile(resolvepath(func, 2)) + if not func then + error(err) + end + end + local env = { } + local oldenv = getfenv(0) + setmetatable(env, { __index = oldenv } ) + setfenv(0, env) + func(...) + setfenv(0, oldenv) + return env +end + +function loadasmodule(name, file) + file = file or resolvepath(name, 2) + if package.loaded[name] then + return package.loaded[name] + end + local env = runinsandbox(file) + package.loaded[name] = env + return env +end + +local function module_loader(modname) + local module = g_modules.getModule(modname) + if not module then + return '\n\tno module \'' .. modname .. '\'' + end + return function() + if not module:load() then + error('unable to load required module ' .. modname) + end + return module:getSandbox() + end +end +table.insert(package.loaders, 1, module_loader) + function export(what, key) if key ~= nil then _G[key] = what @@ -130,17 +170,6 @@ function unexport(key) end end -function sandbox(what) - what = what or 2 - setfenv(what, newenv()) -end - -function newenv() - local env = { } - setmetatable(env, { __index = getfenv() } ) - return env -end - function getfsrcpath(depth) depth = depth or 2 local info = debug.getinfo(1+depth, "Sn") diff --git a/modules/game_skills/skills.lua b/modules/game_skills/skills.lua index ecaec384..229050e2 100644 --- a/modules/game_skills/skills.lua +++ b/modules/game_skills/skills.lua @@ -1,17 +1,52 @@ -Skills = {} +skillsWindow = nil +skillsButton = nil --- private variables -local skillsWindow -local skillsButton +function init() + connect(LocalPlayer, { + onExperienceChange = onExperienceChange, + onLevelChange = onLevelChange, + onHealthChange = onHealthChange, + onManaChange = onManaChange, + onSoulChange = onSoulChange, + onFreeCapacityChange = onFreeCapacityChange, + onStaminaChange = onStaminaChange, + onMagicLevelChange = onMagicLevelChange, + onSkillChange = onSkillChange + }) --- private functions -local function setSkillValue(id, value) + skillsWindow = g_ui.loadUI('skills.otui', GameInterface.getRightPanel()) + skillsButton = TopMenu.addRightGameToggleButton('skillsButton', tr('Skills') .. ' (Ctrl+S)', 'skills.png', toggle) + skillsButton:setOn(true) + g_keyboard.bindKeyDown('Ctrl+S', toggle) + + refresh() +end + +function terminate() + disconnect(LocalPlayer, { + onExperienceChange = onExperienceChange, + onLevelChange = onLevelChange, + onHealthChange = onHealthChange, + onManaChange = onManaChange, + onSoulChange = onSoulChange, + onFreeCapacityChange = onFreeCapacityChange, + onStaminaChange = onStaminaChange, + onMagicLevelChange = onMagicLevelChange, + onSkillChange = onSkillChange + }) + + g_keyboard.unbindKeyDown('Ctrl+S') + skillsButton:destroy() + skillsWindow:destroy() +end + +function setSkillValue(id, value) local skill = skillsWindow:recursiveGetChildById(id) local widget = skill:getChildById('value') widget:setText(value) end -local function setSkillPercent(id, percent, tooltip) +function setSkillPercent(id, percent, tooltip) local skill = skillsWindow:recursiveGetChildById(id) local widget = skill:getChildById('percent') widget:setPercent(percent) @@ -21,69 +56,25 @@ local function setSkillPercent(id, percent, tooltip) end end --- public functions -function Skills.init() - connect(LocalPlayer, { - onExperienceChange = Skills.onExperienceChange, - onLevelChange = Skills.onLevelChange, - onHealthChange = Skills.onHealthChange, - onManaChange = Skills.onManaChange, - onSoulChange = Skills.onSoulChange, - onFreeCapacityChange = Skills.onFreeCapacityChange, - onStaminaChange = Skills.onStaminaChange, - onMagicLevelChange = Skills.onMagicLevelChange, - onSkillChange = Skills.onSkillChange - }) - - skillsWindow = g_ui.loadUI('skills.otui', GameInterface.getRightPanel()) - skillsButton = TopMenu.addRightGameToggleButton('skillsButton', tr('Skills') .. ' (Ctrl+S)', 'skills.png', Skills.toggle) - skillsButton:setOn(true) - g_keyboard.bindKeyDown('Ctrl+S', Skills.toggle) - - Skills.refresh() -end - -function Skills.terminate() - disconnect(LocalPlayer, { - onExperienceChange = Skills.onExperienceChange, - onLevelChange = Skills.onLevelChange, - onHealthChange = Skills.onHealthChange, - onManaChange = Skills.onManaChange, - onSoulChange = Skills.onSoulChange, - onFreeCapacityChange = Skills.onFreeCapacityChange, - onStaminaChange = Skills.onStaminaChange, - onMagicLevelChange = Skills.onMagicLevelChange, - onSkillChange = Skills.onSkillChange - }) - - g_keyboard.unbindKeyDown('Ctrl+S') - skillsButton:destroy() - skillsButton = nil - skillsWindow:destroy() - skillsWindow = nil - - Skills = nil -end - -function Skills.refresh() +function refresh() local player = g_game.getLocalPlayer() if not player then return end - Skills.onExperienceChange(player, player:getExperience()) - Skills.onLevelChange(player, player:getLevel(), player:getLevelPercent()) - Skills.onHealthChange(player, player:getHealth(), player:getMaxHealth()) - Skills.onManaChange(player, player:getMana(), player:getMaxMana()) - Skills.onSoulChange(player, player:getSoul()) - Skills.onFreeCapacityChange(player, player:getFreeCapacity()) - Skills.onStaminaChange(player, player:getStamina()) - Skills.onMagicLevelChange(player, player:getMagicLevel(), player:getMagicLevelPercent()) + onExperienceChange(player, player:getExperience()) + onLevelChange(player, player:getLevel(), player:getLevelPercent()) + onHealthChange(player, player:getHealth(), player:getMaxHealth()) + onManaChange(player, player:getMana(), player:getMaxMana()) + onSoulChange(player, player:getSoul()) + onFreeCapacityChange(player, player:getFreeCapacity()) + onStaminaChange(player, player:getStamina()) + onMagicLevelChange(player, player:getMagicLevel(), player:getMagicLevelPercent()) for i=0,6 do - Skills.onSkillChange(player, i, player:getSkillLevel(i), player:getSkillLevelPercent(i)) + onSkillChange(player, i, player:getSkillLevel(i), player:getSkillLevelPercent(i)) end end -function Skills.toggle() +function toggle() if skillsButton:isOn() then skillsWindow:close() skillsButton:setOn(false) @@ -93,11 +84,11 @@ function Skills.toggle() end end -function Skills.onMiniWindowClose() +function onMiniWindowClose() skillsButton:setOn(false) end -function Skills.onSkillButtonClick(button) +function onSkillButtonClick(button) local percentBar = button:getChildById('percent') if percentBar then percentBar:setVisible(not percentBar:isVisible()) @@ -109,33 +100,32 @@ function Skills.onSkillButtonClick(button) end end --- hooked events -function Skills.onExperienceChange(localPlayer, value) +function onExperienceChange(localPlayer, value) setSkillValue('experience', tr(value)) end -function Skills.onLevelChange(localPlayer, value, percent) +function onLevelChange(localPlayer, value, percent) setSkillValue('level', tr(value)) setSkillPercent('level', percent, tr('You have %s percent to go', 100 - percent)) end -function Skills.onHealthChange(localPlayer, health, maxHealth) +function onHealthChange(localPlayer, health, maxHealth) setSkillValue('health', tr(health)) end -function Skills.onManaChange(localPlayer, mana, maxMana) +function onManaChange(localPlayer, mana, maxMana) setSkillValue('mana', tr(mana)) end -function Skills.onSoulChange(localPlayer, soul) +function onSoulChange(localPlayer, soul) setSkillValue('soul', soul) end -function Skills.onFreeCapacityChange(localPlayer, freeCapacity) +function onFreeCapacityChange(localPlayer, freeCapacity) setSkillValue('capacity', freeCapacity) end -function Skills.onStaminaChange(localPlayer, stamina) +function onStaminaChange(localPlayer, stamina) local hours = math.floor(stamina / 60) local minutes = stamina % 60 if minutes < 10 then @@ -147,12 +137,12 @@ function Skills.onStaminaChange(localPlayer, stamina) setSkillPercent('stamina', percent, tr('You have %s percent', percent)) end -function Skills.onMagicLevelChange(localPlayer, value, percent) +function onMagicLevelChange(localPlayer, value, percent) setSkillValue('magiclevel', value) setSkillPercent('magiclevel', percent, tr('You have %s percent to go', 100 - percent)) end -function Skills.onSkillChange(localPlayer, id, level, percent) +function onSkillChange(localPlayer, id, level, percent) setSkillValue('skillId' .. id, level) setSkillPercent('skillId' .. id, percent, tr('You have %s percent to go', 100 - percent)) end diff --git a/modules/game_skills/skills.otmod b/modules/game_skills/skills.otmod index 04cff361..c4ff4016 100644 --- a/modules/game_skills/skills.otmod +++ b/modules/game_skills/skills.otmod @@ -3,13 +3,12 @@ Module description: Manage skills window author: baxnie, edubart website: www.otclient.info + sandboxed: true + scripts: + - skills.lua dependencies: - game_interface - @onLoad: | - dofile 'skills' - Skills.init() - - @onUnload: | - Skills.terminate() + @onLoad: init() + @onUnload: terminate() diff --git a/modules/game_skills/skills.otui b/modules/game_skills/skills.otui index be1082b0..a3792382 100644 --- a/modules/game_skills/skills.otui +++ b/modules/game_skills/skills.otui @@ -3,7 +3,7 @@ SkillFirstWidget < UIWidget SkillButton < UIButton height: 21 margin-bottom: 2 - &onClick: Skills.onSkillButtonClick + &onClick: onSkillButtonClick SkillNameLabel < GameLabel font: verdana-11px-monochrome @@ -35,7 +35,7 @@ MiniWindow !text: tr('Skills') height: 150 icon: skills.png - @onClose: Skills.onMiniWindowClose() + @onClose: onMiniWindowClose() &save: true MiniWindowContents diff --git a/src/framework/core/module.cpp b/src/framework/core/module.cpp index 63a55455..563cf6bf 100644 --- a/src/framework/core/module.cpp +++ b/src/framework/core/module.cpp @@ -30,8 +30,7 @@ Module::Module(const std::string& name) { m_name = name; - g_lua.newEnvironment(); - m_sandboxEnv = g_lua.ref(); + m_sandboxEnv = g_lua.newSandboxEnv(); } bool Module::load() @@ -49,12 +48,11 @@ bool Module::load() stdext::throw_exception(stdext::format("dependency '%s' has failed to load", m_name, depName)); } + if(m_sandboxed) + g_lua.setGlobalEnvironment(m_sandboxEnv); + for(const std::string& script : m_scripts) { g_lua.loadScript(script); - if(m_sandboxed) { - g_lua.getRef(m_sandboxEnv); - g_lua.setEnv(); - } g_lua.safeCall(0, 0); } @@ -69,8 +67,13 @@ bool Module::load() g_lua.safeCall(0, 0); } + if(m_sandboxed) + g_lua.resetGlobalEnvironment(); + g_logger.debug(stdext::format("Loaded module '%s'", m_name)); } catch(stdext::exception& e) { + if(m_sandboxed) + g_lua.resetGlobalEnvironment(); g_logger.error(stdext::format("Unable to load module '%s': %s", m_name, e.what())); return false; } @@ -93,20 +96,29 @@ void Module::unload() { if(m_loaded) { try { + if(m_sandboxed) + g_lua.setGlobalEnvironment(m_sandboxEnv); + const std::string& onUnloadBuffer = std::get<0>(m_onUnloadFunc); const std::string& onUnloadSource = std::get<1>(m_onUnloadFunc); if(!onUnloadBuffer.empty()) { g_lua.loadBuffer(onUnloadBuffer, onUnloadSource); - if(m_sandboxed) { - g_lua.getRef(m_sandboxEnv); - g_lua.setEnv(); - } g_lua.safeCall(0, 0); } + + if(m_sandboxed) + g_lua.resetGlobalEnvironment(); } catch(stdext::exception& e) { + if(m_sandboxed) + g_lua.resetGlobalEnvironment(); g_logger.error(stdext::format("Unable to unload module '%s': %s", m_name, e.what())); } + // clear all env references + g_lua.getRef(m_sandboxEnv); + g_lua.clearTable(); + g_lua.pop(); + m_loaded = false; //g_logger.info(stdext::format("Unloaded module '%s'", m_name)); g_modules.updateModuleLoadOrder(asModule()); @@ -135,6 +147,12 @@ bool Module::hasDependency(const std::string& name) return false; } +int Module::getSandbox(LuaInterface* lua) +{ + lua->getRef(m_sandboxEnv); + return 1; +} + void Module::discover(const OTMLNodePtr& moduleNode) { const static std::string none = "none"; diff --git a/src/framework/core/module.h b/src/framework/core/module.h index 16250b0a..7ac37c31 100644 --- a/src/framework/core/module.h +++ b/src/framework/core/module.h @@ -43,7 +43,9 @@ public: bool isLoaded() { return m_loaded; } bool isReloadable() { return m_reloadable; } bool isDependent(); + bool isSandboxed() { return m_sandboxed; } bool hasDependency(const std::string& name); + int getSandbox(LuaInterface *lua); std::string getDescription() { return m_description; } std::string getName() { return m_name; } diff --git a/src/framework/core/resourcemanager.cpp b/src/framework/core/resourcemanager.cpp index e94610fa..2dacba5e 100644 --- a/src/framework/core/resourcemanager.cpp +++ b/src/framework/core/resourcemanager.cpp @@ -151,7 +151,7 @@ void ResourceManager::loadFile(const std::string& fileName, std::iostream& out) PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str()); if(!file) { out.clear(std::ios::failbit); - stdext::throw_exception(stdext::format("failed to load file '%s': %s", fullPath.c_str(), PHYSFS_getLastError())); + stdext::throw_exception(stdext::format("unable to load file '%s': %s", fullPath.c_str(), PHYSFS_getLastError())); } else { int fileSize = PHYSFS_fileLength(file); if(fileSize > 0) { @@ -167,7 +167,7 @@ void ResourceManager::loadFile(const std::string& fileName, std::iostream& out) std::ifstream fin(fileName); if(!fin) { out.clear(std::ios::failbit); - stdext::throw_exception(stdext::format("failed to load file '%s': %s", fileName.c_str(), PHYSFS_getLastError())); + stdext::throw_exception(stdext::format("unable to file '%s': %s", fileName.c_str(), PHYSFS_getLastError())); } else { out << fin.rdbuf(); } diff --git a/src/framework/luaengine/luainterface.cpp b/src/framework/luaengine/luainterface.cpp index db3c34e8..e2e0d80f 100644 --- a/src/framework/luaengine/luainterface.cpp +++ b/src/framework/luaengine/luainterface.cpp @@ -47,6 +47,12 @@ void LuaInterface::init() { createLuaState(); + // store global environment reference + pushThread(); + getEnv(); + m_globalEnv = ref(); + pop(); + // check if demangle_type is working as expected assert(stdext::demangle_type() == "LuaObject"); @@ -297,7 +303,7 @@ bool LuaInterface::safeRunScript(const std::string& fileName) try { runScript(fileName); return true; - } catch(LuaException& e) { + } catch(stdext::exception& e) { g_logger.error(stdext::format("Failed to load script '%s': %s", fileName, e.what())); return false; } @@ -322,13 +328,9 @@ void LuaInterface::loadScript(const std::string& fileName) if(!boost::starts_with(fileName, "/")) filePath = getCurrentSourcePath() + "/" + filePath; - try { - std::string buffer = g_resources.loadFile(fileName); - std::string source = "@" + filePath; - loadBuffer(buffer, source); - } catch(stdext::exception& e) { - throw LuaException(e.what()); - } + std::string buffer = g_resources.loadFile(fileName); + std::string source = "@" + filePath; + loadBuffer(buffer, source); } void LuaInterface::loadFunction(const std::string& buffer, const std::string& source) @@ -515,7 +517,7 @@ int LuaInterface::signalCall(int numArgs, int numRets) else { throw LuaException("attempt to call a non function value", 0); } - } catch(LuaException &e) { + } catch(stdext::exception& e) { g_logger.error(stdext::format("protected lua call failed: %s", e.what())); } @@ -529,16 +531,16 @@ int LuaInterface::signalCall(int numArgs, int numRets) return rets; } -void LuaInterface::newEnvironment() +int LuaInterface::newSandboxEnv() { newTable(); // pushes the new environment table newTable(); // pushes the new environment metatable - getGlobalEnvironment(); // pushes the global environment + getRef(getGlobalEnvironment()); // pushes the global environment setField("__index"); // sets metatable __index to the global environment setMetatable(); // assigns environment metatable + return ref(); // return a reference to the environment table } - /////////////////////////////////////////////////////////////////////////////// // lua C functions @@ -550,13 +552,13 @@ int LuaInterface::luaScriptLoader(lua_State* L) try { g_lua.loadScript(fileName); return 1; - } catch(LuaException& e) { - g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what())); - return 0; + } catch(stdext::exception& e) { + g_lua.pushString(stdext::mkstr("\n\t", e.what())); + return 1; } } -int LuaInterface::luaScriptRunner(lua_State* L) +int LuaInterface::lua_dofile(lua_State* L) { std::string fileName = g_lua.popString(); if(!boost::ends_with(fileName, ".lua")) @@ -566,13 +568,14 @@ int LuaInterface::luaScriptRunner(lua_State* L) g_lua.loadScript(fileName); g_lua.call(0, LUA_MULTRET); return g_lua.stackSize(); - } catch(LuaException& e) { - g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what())); + } catch(stdext::exception& e) { + g_lua.pushString(e.what()); + g_lua.error(); return 0; } } -int LuaInterface::luaScriptsRunner(lua_State* L) +int LuaInterface::lua_dofiles(lua_State* L) { std::string directory = g_lua.popString(); @@ -583,13 +586,31 @@ int LuaInterface::luaScriptsRunner(lua_State* L) try { g_lua.loadScript(directory + "/" + fileName); g_lua.call(0, 0); - } catch(LuaException& e) { - g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what())); + } catch(stdext::exception& e) { + g_lua.pushString(e.what()); + g_lua.error(); } } return 0; } +int LuaInterface::lua_loadfile(lua_State* L) +{ + std::string fileName = g_lua.popString(); + if(!boost::ends_with(fileName, ".lua")) + fileName += ".lua"; + + try { + g_lua.loadScript(fileName); + return 1; + } catch(stdext::exception& e) { + g_lua.pushNil(); + g_lua.pushString(e.what()); + g_lua.error(); + return 2; + } +} + int LuaInterface::luaErrorHandler(lua_State* L) { // pops the error message @@ -618,12 +639,13 @@ int LuaInterface::luaCppFunctionCallback(lua_State* L) numRets = (*(funcPtr->get()))(&g_lua); g_lua.m_cppCallbackDepth--; assert(numRets == g_lua.stackSize()); - } catch(stdext::exception &e) { + } catch(stdext::exception& e) { // cleanup stack while(g_lua.stackSize() > 0) g_lua.pop(); numRets = 0; - g_logger.error(stdext::format("C++ call failed: %s", g_lua.traceback(e.what()))); + g_lua.pushString(stdext::format("C++ call failed: %s", g_lua.traceback(e.what()))); + g_lua.error(); } return numRets; @@ -670,13 +692,24 @@ void LuaInterface::createLuaState() rawSeti(5); pop(2); + // replace loadfile + getGlobal("package"); + getField("loaders"); + pushCFunction(&LuaInterface::luaScriptLoader); + rawSeti(5); + pop(2); + // replace dofile - pushCFunction(&LuaInterface::luaScriptRunner); + pushCFunction(&LuaInterface::lua_dofile); setGlobal("dofile"); // dofiles - pushCFunction(&LuaInterface::luaScriptsRunner); + pushCFunction(&LuaInterface::lua_dofiles); setGlobal("dofiles"); + + // replace loadfile + pushCFunction(&LuaInterface::lua_loadfile); + setGlobal("loadfile"); } void LuaInterface::closeLuaState() @@ -833,18 +866,13 @@ void LuaInterface::getWeakRef(int weakRef) remove(-2); } -void LuaInterface::getGlobalEnvironment() +void LuaInterface::setGlobalEnvironment(int env) { pushThread(); - getEnv(); - remove(-2); -} - -void LuaInterface::setGlobalEnvironment() -{ - pushThread(); - insert(-2); + getRef(env); + assert(isTable()); setEnv(); + pop(); } void LuaInterface::setMetatable(int index) @@ -899,6 +927,24 @@ void LuaInterface::setTable(int index) lua_settable(L, index); } +void LuaInterface::clearTable(int index) +{ + assert(hasIndex(index) && isTable(index)); + pushNil(); + bool stop = false; + while(!stop && next(index-1)) { + pop(); + pushValue(); + if(next(index-2)) + pop(); + else + stop = true; + insert(-2); + pushNil(); + rawSet(index-3); + } +} + void LuaInterface::getGlobal(const std::string& key) { lua_getglobal(L, key.c_str()); diff --git a/src/framework/luaengine/luainterface.h b/src/framework/luaengine/luainterface.h index 86175baa..eb2ce366 100644 --- a/src/framework/luaengine/luainterface.h +++ b/src/framework/luaengine/luainterface.h @@ -186,7 +186,7 @@ public: /// The new environment table is redirected to the global environment (aka _G), /// this allows to access global variables from _G in the new environment and /// prevents new variables in this new environment to be set on the global environment - void newEnvironment(); + int newSandboxEnv(); template int callGlobalField(const std::string& global, const std::string& field, const T&... args); @@ -200,9 +200,11 @@ private: /// Load scripts requested by lua 'require' static int luaScriptLoader(lua_State* L); /// Run scripts requested by lua 'dofile' - static int luaScriptRunner(lua_State* L); + static int lua_dofile(lua_State* L); /// Run scripts requested by lua 'dofiles' - static int luaScriptsRunner(lua_State* L); + static int lua_dofiles(lua_State* L); + /// Run scripts requested by lua 'dofiles' + static int lua_loadfile(lua_State* L); /// Handle lua errors from safeCall static int luaErrorHandler(lua_State* L); /// Handle bound cpp functions callbacks @@ -240,8 +242,9 @@ public: void getRef(int ref); void getWeakRef(int weakRef); - void getGlobalEnvironment(); - void setGlobalEnvironment(); + int getGlobalEnvironment() { return m_globalEnv; } + void setGlobalEnvironment(int env); + void resetGlobalEnvironment() { setGlobalEnvironment(m_globalEnv); } void setMetatable(int index = -2); void getMetatable(int index = -1); @@ -253,6 +256,7 @@ public: void getTable(int index = -2); void setTable(int index = -3); + void clearTable(int index = -1); void getEnv(int index = -1); void setEnv(int index = -2); @@ -334,6 +338,7 @@ private: int m_cppCallbackDepth; int m_totalObjRefs; int m_totalFuncRefs; + int m_globalEnv; }; extern LuaInterface g_lua; diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 3251040c..a1191865 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -148,11 +148,13 @@ void Application::registerLuaFunctions() g_lua.bindClassMemberFunction("canUnload", &Module::canUnload); g_lua.bindClassMemberFunction("isLoaded", &Module::isLoaded); g_lua.bindClassMemberFunction("isReloadble", &Module::isReloadable); + g_lua.bindClassMemberFunction("isSandboxed", &Module::isSandboxed); g_lua.bindClassMemberFunction("getDescription", &Module::getDescription); g_lua.bindClassMemberFunction("getName", &Module::getName); g_lua.bindClassMemberFunction("getAuthor", &Module::getAuthor); g_lua.bindClassMemberFunction("getWebsite", &Module::getWebsite); g_lua.bindClassMemberFunction("getVersion", &Module::getVersion); + g_lua.bindClassMemberFunction("getSandbox", &Module::getSandbox); g_lua.bindClassMemberFunction("isAutoLoad", &Module::isAutoLoad); g_lua.bindClassMemberFunction("getAutoLoadPriority", &Module::getAutoLoadPriority); diff --git a/src/framework/ui/uiwidgetbasestyle.cpp b/src/framework/ui/uiwidgetbasestyle.cpp index 2126c624..cf9ea1ac 100644 --- a/src/framework/ui/uiwidgetbasestyle.cpp +++ b/src/framework/ui/uiwidgetbasestyle.cpp @@ -312,6 +312,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) } else if(boost::starts_with(node->tag(), "&")) { std::string fieldName = node->tag().substr(1); std::string fieldOrigin = "@" + node->source() + "[" + node->tag() + "]"; + g_lua.evaluateExpression(node->value(), fieldOrigin); luaSetField(fieldName); }