Skip to content

Commit

Permalink
Implement a per-save lua init script.
Browse files Browse the repository at this point in the history
  • Loading branch information
angavrilov committed Dec 21, 2012
1 parent bba9649 commit bb3a491
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 3 deletions.
27 changes: 26 additions & 1 deletion Lua API.html
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,10 @@ <h1 class="title">DFHack Lua API</h1>
<li><a class="reference internal" href="#sort" id="id54">sort</a></li>
</ul>
</li>
<li><a class="reference internal" href="#scripts" id="id55">Scripts</a></li>
<li><a class="reference internal" href="#scripts" id="id55">Scripts</a><ul>
<li><a class="reference internal" href="#save-init-script" id="id56">Save init script</a></li>
</ul>
</li>
</ul>
</div>
<p>The current version of DFHack has extensive support for
Expand Down Expand Up @@ -1034,6 +1037,9 @@ <h2><a class="toc-backref" href="#id18">C++ function wrappers</a></h2>
<li><p class="first"><tt class="docutils literal">dfhack.getHackPath()</tt></p>
<p>Returns the dfhack directory path, i.e. <tt class="docutils literal"><span class="pre">&quot;.../df/hack/&quot;</span></tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.getSavePath()</tt></p>
<p>Returns the path to the current save directory, or <em>nil</em> if no save loaded.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.getTickCount()</tt></p>
<p>Returns the tick count in ms, exactly as DF ui uses.</p>
</li>
Expand Down Expand Up @@ -3064,6 +3070,25 @@ <h1><a class="toc-backref" href="#id55">Scripts</a></h1>
</li>
</ul>
<p>Note that this function lets errors propagate to the caller.</p>
<div class="section" id="save-init-script">
<h2><a class="toc-backref" href="#id56">Save init script</a></h2>
<p>If a save directory contains a file called <tt class="docutils literal">raw/init.lua</tt>, it is
automatically loaded and executed every time the save is loaded. It
can also define the following functions to be called by dfhack:</p>
<ul>
<li><p class="first"><tt class="docutils literal">function onStateChange(op) ... end</tt></p>
<p>Automatically called from the regular onStateChange event as long
as the save is still loaded. This avoids the need to install a hook
into the global <tt class="docutils literal">dfhack.onStateChange</tt> table, with associated
cleanup concerns.</p>
</li>
<li><p class="first"><tt class="docutils literal">function onUnload() ... end</tt></p>
<p>Called when the save containing the script is unloaded. This function
should clean up any global hooks installed by the script.</p>
</li>
</ul>
<p>Within the init script, the path to the save directory is available as <tt class="docutils literal">SAVE_PATH</tt>.</p>
</div>
</div>
</div>
</body>
Expand Down
25 changes: 25 additions & 0 deletions Lua API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,10 @@ can be omitted.

Returns the dfhack directory path, i.e. ``".../df/hack/"``.

* ``dfhack.getSavePath()``

Returns the path to the current save directory, or *nil* if no save loaded.

* ``dfhack.getTickCount()``

Returns the tick count in ms, exactly as DF ui uses.
Expand Down Expand Up @@ -2993,3 +2997,24 @@ from other scripts) in any context, via the same function the core uses:
The ``name`` argument should be the name stem, as would be used on the command line.

Note that this function lets errors propagate to the caller.

Save init script
================

If a save directory contains a file called ``raw/init.lua``, it is
automatically loaded and executed every time the save is loaded. It
can also define the following functions to be called by dfhack:

* ``function onStateChange(op) ... end``

Automatically called from the regular onStateChange event as long
as the save is still loaded. This avoids the need to install a hook
into the global ``dfhack.onStateChange`` table, with associated
cleanup concerns.

* ``function onUnload() ... end``

Called when the save containing the script is unloaded. This function
should clean up any global hooks installed by the script.

Within the init script, the path to the save directory is available as ``SAVE_PATH``.
12 changes: 12 additions & 0 deletions library/LuaTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,10 @@ void DFHack::Lua::Notification::bind(lua_State *state, const char *name)

void OpenDFHackApi(lua_State *state);

namespace DFHack { namespace Lua { namespace Core {
static void InitCoreContext();
}}}

lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
{
if (!state)
Expand Down Expand Up @@ -1654,6 +1658,10 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
lua_dup(state);
lua_rawseti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);

// Init core-context specific stuff before loading dfhack.lua
if (IsCoreContext(state))
Lua::Core::InitCoreContext();

// load dfhack.lua
Require(out, state, "dfhack");

Expand Down Expand Up @@ -1829,8 +1837,12 @@ void DFHack::Lua::Core::Init(color_ostream &out)

State = luaL_newstate();

// Calls InitCoreContext after checking IsCoreContext
Lua::Open(out, State);
}

static void Lua::Core::InitCoreContext()
{
lua_newtable(State);
lua_rawsetp(State, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);

Expand Down
43 changes: 41 additions & 2 deletions library/lua/dfhack.lua
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,11 @@ end

-- Command scripts

dfhack.internal.scripts = dfhack.internal.scripts or {}
local internal = dfhack.internal

local scripts = dfhack.internal.scripts
internal.scripts = internal.scripts or {}

local scripts = internal.scripts
local hack_path = dfhack.getHackPath()

function dfhack.run_script(name,...)
Expand All @@ -349,5 +351,42 @@ function dfhack.run_script(name,...)
return f(...)
end

-- Per-save init file

function dfhack.getSavePath()
if dfhack.isWorldLoaded() then
return dfhack.getDFPath() .. '/data/save/' .. df.global.world.cur_savegame.save_dir
end
end

if dfhack.is_core_context then
dfhack.onStateChange.DFHACK_PER_SAVE = function(op)
if op == SC_WORLD_LOADED or op == SC_WORLD_UNLOADED then
if internal.save_init then
if internal.save_init.onUnload then
safecall(internal.save_init.onUnload)
end
internal.save_init = nil
end

local path = dfhack.getSavePath()

if path and op == SC_WORLD_LOADED then
local env = setmetatable({ SAVE_PATH = path }, { __index = base_env })
local f,perr = loadfile(path..'/raw/init.lua', 't', env)
if f == nil then
if not string.match(perr, 'No such file or directory') then
dfhack.printerr(perr)
end
elseif safecall(f) then
internal.save_init = env
end
end
elseif internal.save_init and internal.save_init.onStateChange then
safecall(internal.save_init.onStateChange, op)
end
end
end

-- Feed the table back to the require() mechanism.
return dfhack

0 comments on commit bb3a491

Please sign in to comment.