Improve modules and sandbox system

This commit is contained in:
Eduardo Bart 2012-07-23 21:22:38 -03:00
parent 61d64c7417
commit 1c3e630237
12 changed files with 238 additions and 145 deletions

View File

@ -12,7 +12,8 @@ local MaxHistory = 1000
local terminalWindow local terminalWindow
local terminalButton local terminalButton
local logLocked = false local logLocked = false
local commandEnv = newenv() local commandEnv = {}
setmetatable(commandEnv, { __index = getfenv() } )
local commandTextEdit local commandTextEdit
local terminalBuffer local terminalBuffer
local commandHistory = { } local commandHistory = { }

View File

@ -110,6 +110,46 @@ function extends(base)
return derived return derived
end 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) function export(what, key)
if key ~= nil then if key ~= nil then
_G[key] = what _G[key] = what
@ -130,17 +170,6 @@ function unexport(key)
end end
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) function getfsrcpath(depth)
depth = depth or 2 depth = depth or 2
local info = debug.getinfo(1+depth, "Sn") local info = debug.getinfo(1+depth, "Sn")

View File

@ -1,17 +1,52 @@
Skills = {} skillsWindow = nil
skillsButton = nil
-- private variables function init()
local skillsWindow connect(LocalPlayer, {
local skillsButton onExperienceChange = onExperienceChange,
onLevelChange = onLevelChange,
onHealthChange = onHealthChange,
onManaChange = onManaChange,
onSoulChange = onSoulChange,
onFreeCapacityChange = onFreeCapacityChange,
onStaminaChange = onStaminaChange,
onMagicLevelChange = onMagicLevelChange,
onSkillChange = onSkillChange
})
-- private functions skillsWindow = g_ui.loadUI('skills.otui', GameInterface.getRightPanel())
local function setSkillValue(id, value) 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 skill = skillsWindow:recursiveGetChildById(id)
local widget = skill:getChildById('value') local widget = skill:getChildById('value')
widget:setText(value) widget:setText(value)
end end
local function setSkillPercent(id, percent, tooltip) function setSkillPercent(id, percent, tooltip)
local skill = skillsWindow:recursiveGetChildById(id) local skill = skillsWindow:recursiveGetChildById(id)
local widget = skill:getChildById('percent') local widget = skill:getChildById('percent')
widget:setPercent(percent) widget:setPercent(percent)
@ -21,69 +56,25 @@ local function setSkillPercent(id, percent, tooltip)
end end
end end
-- public functions function refresh()
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()
local player = g_game.getLocalPlayer() local player = g_game.getLocalPlayer()
if not player then return end if not player then return end
Skills.onExperienceChange(player, player:getExperience()) onExperienceChange(player, player:getExperience())
Skills.onLevelChange(player, player:getLevel(), player:getLevelPercent()) onLevelChange(player, player:getLevel(), player:getLevelPercent())
Skills.onHealthChange(player, player:getHealth(), player:getMaxHealth()) onHealthChange(player, player:getHealth(), player:getMaxHealth())
Skills.onManaChange(player, player:getMana(), player:getMaxMana()) onManaChange(player, player:getMana(), player:getMaxMana())
Skills.onSoulChange(player, player:getSoul()) onSoulChange(player, player:getSoul())
Skills.onFreeCapacityChange(player, player:getFreeCapacity()) onFreeCapacityChange(player, player:getFreeCapacity())
Skills.onStaminaChange(player, player:getStamina()) onStaminaChange(player, player:getStamina())
Skills.onMagicLevelChange(player, player:getMagicLevel(), player:getMagicLevelPercent()) onMagicLevelChange(player, player:getMagicLevel(), player:getMagicLevelPercent())
for i=0,6 do 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
end end
function Skills.toggle() function toggle()
if skillsButton:isOn() then if skillsButton:isOn() then
skillsWindow:close() skillsWindow:close()
skillsButton:setOn(false) skillsButton:setOn(false)
@ -93,11 +84,11 @@ function Skills.toggle()
end end
end end
function Skills.onMiniWindowClose() function onMiniWindowClose()
skillsButton:setOn(false) skillsButton:setOn(false)
end end
function Skills.onSkillButtonClick(button) function onSkillButtonClick(button)
local percentBar = button:getChildById('percent') local percentBar = button:getChildById('percent')
if percentBar then if percentBar then
percentBar:setVisible(not percentBar:isVisible()) percentBar:setVisible(not percentBar:isVisible())
@ -109,33 +100,32 @@ function Skills.onSkillButtonClick(button)
end end
end end
-- hooked events function onExperienceChange(localPlayer, value)
function Skills.onExperienceChange(localPlayer, value)
setSkillValue('experience', tr(value)) setSkillValue('experience', tr(value))
end end
function Skills.onLevelChange(localPlayer, value, percent) function onLevelChange(localPlayer, value, percent)
setSkillValue('level', tr(value)) setSkillValue('level', tr(value))
setSkillPercent('level', percent, tr('You have %s percent to go', 100 - percent)) setSkillPercent('level', percent, tr('You have %s percent to go', 100 - percent))
end end
function Skills.onHealthChange(localPlayer, health, maxHealth) function onHealthChange(localPlayer, health, maxHealth)
setSkillValue('health', tr(health)) setSkillValue('health', tr(health))
end end
function Skills.onManaChange(localPlayer, mana, maxMana) function onManaChange(localPlayer, mana, maxMana)
setSkillValue('mana', tr(mana)) setSkillValue('mana', tr(mana))
end end
function Skills.onSoulChange(localPlayer, soul) function onSoulChange(localPlayer, soul)
setSkillValue('soul', soul) setSkillValue('soul', soul)
end end
function Skills.onFreeCapacityChange(localPlayer, freeCapacity) function onFreeCapacityChange(localPlayer, freeCapacity)
setSkillValue('capacity', freeCapacity) setSkillValue('capacity', freeCapacity)
end end
function Skills.onStaminaChange(localPlayer, stamina) function onStaminaChange(localPlayer, stamina)
local hours = math.floor(stamina / 60) local hours = math.floor(stamina / 60)
local minutes = stamina % 60 local minutes = stamina % 60
if minutes < 10 then if minutes < 10 then
@ -147,12 +137,12 @@ function Skills.onStaminaChange(localPlayer, stamina)
setSkillPercent('stamina', percent, tr('You have %s percent', percent)) setSkillPercent('stamina', percent, tr('You have %s percent', percent))
end end
function Skills.onMagicLevelChange(localPlayer, value, percent) function onMagicLevelChange(localPlayer, value, percent)
setSkillValue('magiclevel', value) setSkillValue('magiclevel', value)
setSkillPercent('magiclevel', percent, tr('You have %s percent to go', 100 - percent)) setSkillPercent('magiclevel', percent, tr('You have %s percent to go', 100 - percent))
end end
function Skills.onSkillChange(localPlayer, id, level, percent) function onSkillChange(localPlayer, id, level, percent)
setSkillValue('skillId' .. id, level) setSkillValue('skillId' .. id, level)
setSkillPercent('skillId' .. id, percent, tr('You have %s percent to go', 100 - percent)) setSkillPercent('skillId' .. id, percent, tr('You have %s percent to go', 100 - percent))
end end

View File

@ -3,13 +3,12 @@ Module
description: Manage skills window description: Manage skills window
author: baxnie, edubart author: baxnie, edubart
website: www.otclient.info website: www.otclient.info
sandboxed: true
scripts:
- skills.lua
dependencies: dependencies:
- game_interface - game_interface
@onLoad: | @onLoad: init()
dofile 'skills' @onUnload: terminate()
Skills.init()
@onUnload: |
Skills.terminate()

View File

@ -3,7 +3,7 @@ SkillFirstWidget < UIWidget
SkillButton < UIButton SkillButton < UIButton
height: 21 height: 21
margin-bottom: 2 margin-bottom: 2
&onClick: Skills.onSkillButtonClick &onClick: onSkillButtonClick
SkillNameLabel < GameLabel SkillNameLabel < GameLabel
font: verdana-11px-monochrome font: verdana-11px-monochrome
@ -35,7 +35,7 @@ MiniWindow
!text: tr('Skills') !text: tr('Skills')
height: 150 height: 150
icon: skills.png icon: skills.png
@onClose: Skills.onMiniWindowClose() @onClose: onMiniWindowClose()
&save: true &save: true
MiniWindowContents MiniWindowContents

View File

@ -30,8 +30,7 @@
Module::Module(const std::string& name) Module::Module(const std::string& name)
{ {
m_name = name; m_name = name;
g_lua.newEnvironment(); m_sandboxEnv = g_lua.newSandboxEnv();
m_sandboxEnv = g_lua.ref();
} }
bool Module::load() bool Module::load()
@ -49,12 +48,11 @@ bool Module::load()
stdext::throw_exception(stdext::format("dependency '%s' has failed to load", m_name, depName)); 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) { for(const std::string& script : m_scripts) {
g_lua.loadScript(script); g_lua.loadScript(script);
if(m_sandboxed) {
g_lua.getRef(m_sandboxEnv);
g_lua.setEnv();
}
g_lua.safeCall(0, 0); g_lua.safeCall(0, 0);
} }
@ -69,8 +67,13 @@ bool Module::load()
g_lua.safeCall(0, 0); g_lua.safeCall(0, 0);
} }
if(m_sandboxed)
g_lua.resetGlobalEnvironment();
g_logger.debug(stdext::format("Loaded module '%s'", m_name)); g_logger.debug(stdext::format("Loaded module '%s'", m_name));
} catch(stdext::exception& e) { } 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())); g_logger.error(stdext::format("Unable to load module '%s': %s", m_name, e.what()));
return false; return false;
} }
@ -93,20 +96,29 @@ void Module::unload()
{ {
if(m_loaded) { if(m_loaded) {
try { try {
if(m_sandboxed)
g_lua.setGlobalEnvironment(m_sandboxEnv);
const std::string& onUnloadBuffer = std::get<0>(m_onUnloadFunc); const std::string& onUnloadBuffer = std::get<0>(m_onUnloadFunc);
const std::string& onUnloadSource = std::get<1>(m_onUnloadFunc); const std::string& onUnloadSource = std::get<1>(m_onUnloadFunc);
if(!onUnloadBuffer.empty()) { if(!onUnloadBuffer.empty()) {
g_lua.loadBuffer(onUnloadBuffer, onUnloadSource); g_lua.loadBuffer(onUnloadBuffer, onUnloadSource);
if(m_sandboxed) {
g_lua.getRef(m_sandboxEnv);
g_lua.setEnv();
}
g_lua.safeCall(0, 0); g_lua.safeCall(0, 0);
} }
if(m_sandboxed)
g_lua.resetGlobalEnvironment();
} catch(stdext::exception& e) { } 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())); 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; m_loaded = false;
//g_logger.info(stdext::format("Unloaded module '%s'", m_name)); //g_logger.info(stdext::format("Unloaded module '%s'", m_name));
g_modules.updateModuleLoadOrder(asModule()); g_modules.updateModuleLoadOrder(asModule());
@ -135,6 +147,12 @@ bool Module::hasDependency(const std::string& name)
return false; return false;
} }
int Module::getSandbox(LuaInterface* lua)
{
lua->getRef(m_sandboxEnv);
return 1;
}
void Module::discover(const OTMLNodePtr& moduleNode) void Module::discover(const OTMLNodePtr& moduleNode)
{ {
const static std::string none = "none"; const static std::string none = "none";

View File

@ -43,7 +43,9 @@ public:
bool isLoaded() { return m_loaded; } bool isLoaded() { return m_loaded; }
bool isReloadable() { return m_reloadable; } bool isReloadable() { return m_reloadable; }
bool isDependent(); bool isDependent();
bool isSandboxed() { return m_sandboxed; }
bool hasDependency(const std::string& name); bool hasDependency(const std::string& name);
int getSandbox(LuaInterface *lua);
std::string getDescription() { return m_description; } std::string getDescription() { return m_description; }
std::string getName() { return m_name; } std::string getName() { return m_name; }

View File

@ -151,7 +151,7 @@ void ResourceManager::loadFile(const std::string& fileName, std::iostream& out)
PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str()); PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str());
if(!file) { if(!file) {
out.clear(std::ios::failbit); 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 { } else {
int fileSize = PHYSFS_fileLength(file); int fileSize = PHYSFS_fileLength(file);
if(fileSize > 0) { if(fileSize > 0) {
@ -167,7 +167,7 @@ void ResourceManager::loadFile(const std::string& fileName, std::iostream& out)
std::ifstream fin(fileName); std::ifstream fin(fileName);
if(!fin) { if(!fin) {
out.clear(std::ios::failbit); 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 { } else {
out << fin.rdbuf(); out << fin.rdbuf();
} }

View File

@ -47,6 +47,12 @@ void LuaInterface::init()
{ {
createLuaState(); createLuaState();
// store global environment reference
pushThread();
getEnv();
m_globalEnv = ref();
pop();
// check if demangle_type is working as expected // check if demangle_type is working as expected
assert(stdext::demangle_type<LuaObject>() == "LuaObject"); assert(stdext::demangle_type<LuaObject>() == "LuaObject");
@ -297,7 +303,7 @@ bool LuaInterface::safeRunScript(const std::string& fileName)
try { try {
runScript(fileName); runScript(fileName);
return true; return true;
} catch(LuaException& e) { } catch(stdext::exception& e) {
g_logger.error(stdext::format("Failed to load script '%s': %s", fileName, e.what())); g_logger.error(stdext::format("Failed to load script '%s': %s", fileName, e.what()));
return false; return false;
} }
@ -322,13 +328,9 @@ void LuaInterface::loadScript(const std::string& fileName)
if(!boost::starts_with(fileName, "/")) if(!boost::starts_with(fileName, "/"))
filePath = getCurrentSourcePath() + "/" + filePath; filePath = getCurrentSourcePath() + "/" + filePath;
try {
std::string buffer = g_resources.loadFile(fileName); std::string buffer = g_resources.loadFile(fileName);
std::string source = "@" + filePath; std::string source = "@" + filePath;
loadBuffer(buffer, source); loadBuffer(buffer, source);
} catch(stdext::exception& e) {
throw LuaException(e.what());
}
} }
void LuaInterface::loadFunction(const std::string& buffer, const std::string& source) void LuaInterface::loadFunction(const std::string& buffer, const std::string& source)
@ -515,7 +517,7 @@ int LuaInterface::signalCall(int numArgs, int numRets)
else { else {
throw LuaException("attempt to call a non function value", 0); 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())); 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; return rets;
} }
void LuaInterface::newEnvironment() int LuaInterface::newSandboxEnv()
{ {
newTable(); // pushes the new environment table newTable(); // pushes the new environment table
newTable(); // pushes the new environment metatable 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 setField("__index"); // sets metatable __index to the global environment
setMetatable(); // assigns environment metatable setMetatable(); // assigns environment metatable
return ref(); // return a reference to the environment table
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// lua C functions // lua C functions
@ -550,13 +552,13 @@ int LuaInterface::luaScriptLoader(lua_State* L)
try { try {
g_lua.loadScript(fileName); g_lua.loadScript(fileName);
return 1; return 1;
} catch(LuaException& e) { } catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what())); g_lua.pushString(stdext::mkstr("\n\t", e.what()));
return 0; return 1;
} }
} }
int LuaInterface::luaScriptRunner(lua_State* L) int LuaInterface::lua_dofile(lua_State* L)
{ {
std::string fileName = g_lua.popString(); std::string fileName = g_lua.popString();
if(!boost::ends_with(fileName, ".lua")) if(!boost::ends_with(fileName, ".lua"))
@ -566,13 +568,14 @@ int LuaInterface::luaScriptRunner(lua_State* L)
g_lua.loadScript(fileName); g_lua.loadScript(fileName);
g_lua.call(0, LUA_MULTRET); g_lua.call(0, LUA_MULTRET);
return g_lua.stackSize(); return g_lua.stackSize();
} catch(LuaException& e) { } catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what())); g_lua.pushString(e.what());
g_lua.error();
return 0; return 0;
} }
} }
int LuaInterface::luaScriptsRunner(lua_State* L) int LuaInterface::lua_dofiles(lua_State* L)
{ {
std::string directory = g_lua.popString(); std::string directory = g_lua.popString();
@ -583,13 +586,31 @@ int LuaInterface::luaScriptsRunner(lua_State* L)
try { try {
g_lua.loadScript(directory + "/" + fileName); g_lua.loadScript(directory + "/" + fileName);
g_lua.call(0, 0); g_lua.call(0, 0);
} catch(LuaException& e) { } catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what())); g_lua.pushString(e.what());
g_lua.error();
} }
} }
return 0; 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) int LuaInterface::luaErrorHandler(lua_State* L)
{ {
// pops the error message // pops the error message
@ -618,12 +639,13 @@ int LuaInterface::luaCppFunctionCallback(lua_State* L)
numRets = (*(funcPtr->get()))(&g_lua); numRets = (*(funcPtr->get()))(&g_lua);
g_lua.m_cppCallbackDepth--; g_lua.m_cppCallbackDepth--;
assert(numRets == g_lua.stackSize()); assert(numRets == g_lua.stackSize());
} catch(stdext::exception &e) { } catch(stdext::exception& e) {
// cleanup stack // cleanup stack
while(g_lua.stackSize() > 0) while(g_lua.stackSize() > 0)
g_lua.pop(); g_lua.pop();
numRets = 0; 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; return numRets;
@ -670,13 +692,24 @@ void LuaInterface::createLuaState()
rawSeti(5); rawSeti(5);
pop(2); pop(2);
// replace loadfile
getGlobal("package");
getField("loaders");
pushCFunction(&LuaInterface::luaScriptLoader);
rawSeti(5);
pop(2);
// replace dofile // replace dofile
pushCFunction(&LuaInterface::luaScriptRunner); pushCFunction(&LuaInterface::lua_dofile);
setGlobal("dofile"); setGlobal("dofile");
// dofiles // dofiles
pushCFunction(&LuaInterface::luaScriptsRunner); pushCFunction(&LuaInterface::lua_dofiles);
setGlobal("dofiles"); setGlobal("dofiles");
// replace loadfile
pushCFunction(&LuaInterface::lua_loadfile);
setGlobal("loadfile");
} }
void LuaInterface::closeLuaState() void LuaInterface::closeLuaState()
@ -833,18 +866,13 @@ void LuaInterface::getWeakRef(int weakRef)
remove(-2); remove(-2);
} }
void LuaInterface::getGlobalEnvironment() void LuaInterface::setGlobalEnvironment(int env)
{ {
pushThread(); pushThread();
getEnv(); getRef(env);
remove(-2); assert(isTable());
}
void LuaInterface::setGlobalEnvironment()
{
pushThread();
insert(-2);
setEnv(); setEnv();
pop();
} }
void LuaInterface::setMetatable(int index) void LuaInterface::setMetatable(int index)
@ -899,6 +927,24 @@ void LuaInterface::setTable(int index)
lua_settable(L, 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) void LuaInterface::getGlobal(const std::string& key)
{ {
lua_getglobal(L, key.c_str()); lua_getglobal(L, key.c_str());

View File

@ -186,7 +186,7 @@ public:
/// The new environment table is redirected to the global environment (aka _G), /// 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 /// 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 /// prevents new variables in this new environment to be set on the global environment
void newEnvironment(); int newSandboxEnv();
template<typename... T> template<typename... T>
int callGlobalField(const std::string& global, const std::string& field, const T&... args); int callGlobalField(const std::string& global, const std::string& field, const T&... args);
@ -200,9 +200,11 @@ private:
/// Load scripts requested by lua 'require' /// Load scripts requested by lua 'require'
static int luaScriptLoader(lua_State* L); static int luaScriptLoader(lua_State* L);
/// Run scripts requested by lua 'dofile' /// 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' /// 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 /// Handle lua errors from safeCall
static int luaErrorHandler(lua_State* L); static int luaErrorHandler(lua_State* L);
/// Handle bound cpp functions callbacks /// Handle bound cpp functions callbacks
@ -240,8 +242,9 @@ public:
void getRef(int ref); void getRef(int ref);
void getWeakRef(int weakRef); void getWeakRef(int weakRef);
void getGlobalEnvironment(); int getGlobalEnvironment() { return m_globalEnv; }
void setGlobalEnvironment(); void setGlobalEnvironment(int env);
void resetGlobalEnvironment() { setGlobalEnvironment(m_globalEnv); }
void setMetatable(int index = -2); void setMetatable(int index = -2);
void getMetatable(int index = -1); void getMetatable(int index = -1);
@ -253,6 +256,7 @@ public:
void getTable(int index = -2); void getTable(int index = -2);
void setTable(int index = -3); void setTable(int index = -3);
void clearTable(int index = -1);
void getEnv(int index = -1); void getEnv(int index = -1);
void setEnv(int index = -2); void setEnv(int index = -2);
@ -334,6 +338,7 @@ private:
int m_cppCallbackDepth; int m_cppCallbackDepth;
int m_totalObjRefs; int m_totalObjRefs;
int m_totalFuncRefs; int m_totalFuncRefs;
int m_globalEnv;
}; };
extern LuaInterface g_lua; extern LuaInterface g_lua;

View File

@ -148,11 +148,13 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<Module>("canUnload", &Module::canUnload); g_lua.bindClassMemberFunction<Module>("canUnload", &Module::canUnload);
g_lua.bindClassMemberFunction<Module>("isLoaded", &Module::isLoaded); g_lua.bindClassMemberFunction<Module>("isLoaded", &Module::isLoaded);
g_lua.bindClassMemberFunction<Module>("isReloadble", &Module::isReloadable); g_lua.bindClassMemberFunction<Module>("isReloadble", &Module::isReloadable);
g_lua.bindClassMemberFunction<Module>("isSandboxed", &Module::isSandboxed);
g_lua.bindClassMemberFunction<Module>("getDescription", &Module::getDescription); g_lua.bindClassMemberFunction<Module>("getDescription", &Module::getDescription);
g_lua.bindClassMemberFunction<Module>("getName", &Module::getName); g_lua.bindClassMemberFunction<Module>("getName", &Module::getName);
g_lua.bindClassMemberFunction<Module>("getAuthor", &Module::getAuthor); g_lua.bindClassMemberFunction<Module>("getAuthor", &Module::getAuthor);
g_lua.bindClassMemberFunction<Module>("getWebsite", &Module::getWebsite); g_lua.bindClassMemberFunction<Module>("getWebsite", &Module::getWebsite);
g_lua.bindClassMemberFunction<Module>("getVersion", &Module::getVersion); g_lua.bindClassMemberFunction<Module>("getVersion", &Module::getVersion);
g_lua.bindClassMemberFunction<Module>("getSandbox", &Module::getSandbox);
g_lua.bindClassMemberFunction<Module>("isAutoLoad", &Module::isAutoLoad); g_lua.bindClassMemberFunction<Module>("isAutoLoad", &Module::isAutoLoad);
g_lua.bindClassMemberFunction<Module>("getAutoLoadPriority", &Module::getAutoLoadPriority); g_lua.bindClassMemberFunction<Module>("getAutoLoadPriority", &Module::getAutoLoadPriority);

View File

@ -312,6 +312,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode)
} else if(boost::starts_with(node->tag(), "&")) { } else if(boost::starts_with(node->tag(), "&")) {
std::string fieldName = node->tag().substr(1); std::string fieldName = node->tag().substr(1);
std::string fieldOrigin = "@" + node->source() + "[" + node->tag() + "]"; std::string fieldOrigin = "@" + node->source() + "[" + node->tag() + "]";
g_lua.evaluateExpression(node->value(), fieldOrigin); g_lua.evaluateExpression(node->value(), fieldOrigin);
luaSetField(fieldName); luaSetField(fieldName);
} }