|
|
|
@ -386,15 +386,33 @@ end
|
|
|
|
|
|
|
|
|
|
local internal = dfhack.internal
|
|
|
|
|
|
|
|
|
|
internal.scripts = internal.scripts or {}
|
|
|
|
|
internal.scriptPath = internal.scriptPath or {}
|
|
|
|
|
internal.scriptMtime = internal.scriptMtime or {}
|
|
|
|
|
internal.scriptRun = internal.scriptRun or {}
|
|
|
|
|
Script = defclass(Script)
|
|
|
|
|
function Script:init(path)
|
|
|
|
|
self.path = path
|
|
|
|
|
self.mtime = dfhack.filesystem.mtime(path)
|
|
|
|
|
self._flags = {}
|
|
|
|
|
end
|
|
|
|
|
function Script:get_flags()
|
|
|
|
|
if self.flags_mtime ~= dfhack.filesystem.mtime(self.path) then
|
|
|
|
|
self.flags_mtime = dfhack.filesystem.mtime(self.path)
|
|
|
|
|
self._flags = {}
|
|
|
|
|
local f = io.open(self.path)
|
|
|
|
|
local contents = f:read('*all')
|
|
|
|
|
f:close()
|
|
|
|
|
for line in contents:gmatch('%-%-@([^\n]+)') do
|
|
|
|
|
local chunk = load(line, self.path, 't', self._flags)
|
|
|
|
|
if chunk then
|
|
|
|
|
chunk()
|
|
|
|
|
else
|
|
|
|
|
dfhack.printerr('Parse error: ' .. line)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return self._flags
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
internal.scripts = internal.scripts or {}
|
|
|
|
|
local scripts = internal.scripts
|
|
|
|
|
local scriptPath = internal.scriptPath
|
|
|
|
|
local scriptMtime = internal.scriptMtime
|
|
|
|
|
local scriptRun = internal.scriptRun
|
|
|
|
|
|
|
|
|
|
local hack_path = dfhack.getHackPath()
|
|
|
|
|
|
|
|
|
@ -419,28 +437,69 @@ function dfhack.findScript(name)
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local valid_script_flags = {
|
|
|
|
|
enable = {required = true, error = 'Does not recognize enable/disable commands'},
|
|
|
|
|
enable_state = {required = false},
|
|
|
|
|
module = {
|
|
|
|
|
required = function(flags)
|
|
|
|
|
if flags.module_strict == false then return false end
|
|
|
|
|
return true
|
|
|
|
|
end,
|
|
|
|
|
error = 'Cannot be used as a module'
|
|
|
|
|
},
|
|
|
|
|
module_strict = {required = false},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function dfhack.run_script(name,...)
|
|
|
|
|
return dfhack.run_script_with_env(nil,name,...)
|
|
|
|
|
return dfhack.run_script_with_env(nil, name, nil, ...)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function dfhack.enable_script(name, state)
|
|
|
|
|
local res, err = dfhack.pcall(dfhack.run_script_with_env, nil, name, {enable=true, enable_state=state})
|
|
|
|
|
if not res then
|
|
|
|
|
dfhack.printerr(err.message)
|
|
|
|
|
qerror(('Cannot %s Lua script: %s'):format(state and 'enable' or 'disable', name))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function dfhack.reqscript(name)
|
|
|
|
|
_, env = dfhack.run_script_with_env(nil, name, {module=true})
|
|
|
|
|
return env
|
|
|
|
|
end
|
|
|
|
|
reqscript = dfhack.reqscript
|
|
|
|
|
|
|
|
|
|
function dfhack.script_environment(name)
|
|
|
|
|
_, env = dfhack.run_script_with_env({moduleMode=true}, name)
|
|
|
|
|
_, env = dfhack.run_script_with_env(nil, name, {module=true, module_strict=false})
|
|
|
|
|
return env
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function dfhack.run_script_with_env(envVars,name,...)
|
|
|
|
|
function dfhack.run_script_with_env(envVars, name, flags, ...)
|
|
|
|
|
if type(flags) ~= 'table' then flags = {} end
|
|
|
|
|
local file = dfhack.findScript(name)
|
|
|
|
|
if not file then
|
|
|
|
|
error('Could not find script ' .. name)
|
|
|
|
|
end
|
|
|
|
|
if scriptPath[name] and scriptPath[name] ~= file then
|
|
|
|
|
--new file path: must have loaded a different save or unloaded
|
|
|
|
|
scriptPath[name] = file
|
|
|
|
|
scriptMtime[file] = dfhack.filesystem.mtime(file)
|
|
|
|
|
--it is the responsibility of the script to clear its own data on unload so it's safe for us to not delete it here
|
|
|
|
|
|
|
|
|
|
if scripts[file] == nil then
|
|
|
|
|
scripts[file] = Script(file)
|
|
|
|
|
end
|
|
|
|
|
local script_flags = scripts[file]:get_flags()
|
|
|
|
|
for flag, value in pairs(flags) do
|
|
|
|
|
if value then
|
|
|
|
|
local v = valid_script_flags[flag]
|
|
|
|
|
if not v then
|
|
|
|
|
error('Invalid flag: ' .. flag)
|
|
|
|
|
elseif ((type(v.required) == 'boolean' and v.required) or
|
|
|
|
|
(type(v.required) == 'function' and v.required(flags))) then
|
|
|
|
|
if not script_flags[flag] then
|
|
|
|
|
local msg = v.error or 'Flag "' .. flag .. '" not recognized'
|
|
|
|
|
error(name .. ': ' .. msg)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local env = scripts[file]
|
|
|
|
|
local env = scripts[file].env
|
|
|
|
|
if env == nil then
|
|
|
|
|
env = {}
|
|
|
|
|
setmetatable(env, { __index = base_env })
|
|
|
|
@ -448,11 +507,13 @@ function dfhack.run_script_with_env(envVars,name,...)
|
|
|
|
|
for x,y in pairs(envVars or {}) do
|
|
|
|
|
env[x] = y
|
|
|
|
|
end
|
|
|
|
|
env.dfhack_flags = flags
|
|
|
|
|
env.moduleMode = flags.module
|
|
|
|
|
local f
|
|
|
|
|
local perr
|
|
|
|
|
local time = dfhack.filesystem.mtime(file)
|
|
|
|
|
if time == scriptMtime[file] and scriptRun[file] then
|
|
|
|
|
f = scriptRun[file]
|
|
|
|
|
if time == scripts[file].mtime and scripts[file].run then
|
|
|
|
|
f = scripts[file].run
|
|
|
|
|
else
|
|
|
|
|
--reload
|
|
|
|
|
f, perr = loadfile(file, 't', env)
|
|
|
|
@ -460,10 +521,10 @@ function dfhack.run_script_with_env(envVars,name,...)
|
|
|
|
|
error(perr)
|
|
|
|
|
end
|
|
|
|
|
-- avoid updating mtime if the script failed to load
|
|
|
|
|
scriptMtime[file] = time
|
|
|
|
|
scripts[file].mtime = time
|
|
|
|
|
end
|
|
|
|
|
scripts[file] = env
|
|
|
|
|
scriptRun[file] = f
|
|
|
|
|
scripts[file].env = env
|
|
|
|
|
scripts[file].run = f
|
|
|
|
|
return f(...), env
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|