Improve modules and sandbox system
This commit is contained in:
parent
61d64c7417
commit
1c3e630237
|
@ -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 = { }
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue