Update the Lua API document with info about scripts.

develop
Alexander Gavrilov 2012-06-22 20:17:55 +04:00
parent dedc59c709
commit bd37cc09c5
3 changed files with 256 additions and 101 deletions

@ -4,9 +4,26 @@ DFHack Lua API
.. contents:: .. contents::
==================== The current version of DFHack has extensive support for
DF structure wrapper the Lua scripting language, providing access to:
====================
1. Raw data structures used by the game.
2. Many C++ functions for high-level access to these
structures, and interaction with dfhack itself.
3. Some functions exported by C++ plugins.
Lua code can be used both for writing scripts, which
are treated by DFHack command line prompt almost as
native C++ commands, and invoked by plugins written in c++.
This document describes native API available to Lua in detail.
For the most part it does not describe utility functions
implemented by Lua files located in hack/lua/...
=========================
DF data structure wrapper
=========================
DF structures described by the xml files in library/xml are exported DF structures described by the xml files in library/xml are exported
to lua code as a tree of objects and functions under the ``df`` global, to lua code as a tree of objects and functions under the ``df`` global,
@ -479,29 +496,6 @@ Input & Output
If the interactive console is not accessible, returns *nil, error*. If the interactive console is not accessible, returns *nil, error*.
Miscellaneous
-------------
* ``dfhack.run_script(name[,args...])``
Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
The ``name`` argument should be the name stem, as would be used on the command line.
Note that the script is re-read from the file every time it is called, and errors
are propagated to the caller.
* ``dfhack.with_suspend(f[,args...])``
Calls ``f`` with arguments after grabbing the DF core suspend lock.
Suspending is necessary for accessing a consistent state of DF memory.
Returned values and errors are propagated through after releasing
the lock. It is safe to nest suspends.
Every thread is allowed only one suspend per DF frame, so it is best
to group operations together in one big critical section. A plugin
can choose to run all lua code inside a C++-side suspend lock.
Exception handling Exception handling
------------------ ------------------
@ -531,30 +525,6 @@ Exception handling
Compares to coroutine.resume like dfhack.safecall vs pcall. Compares to coroutine.resume like dfhack.safecall vs pcall.
* ``dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])``
Invokes ``fn`` with ``args``, and after it returns or throws an
error calls ``cleanup_fn`` with ``cleanup_args``. Any return values from
``fn`` are propagated, and errors are re-thrown.
The ``num_cleanup_args`` integer specifies the number of ``cleanup_args``,
and the ``always`` boolean specifies if cleanup should be called in any case,
or only in case of an error.
* ``dfhack.with_finalize(cleanup_fn,fn[,args...])``
Calls ``fn`` with arguments, then finalizes with ``cleanup_fn``.
Implemented using ``call_with_finalizer(0,true,...)``.
* ``dfhack.with_onerror(cleanup_fn,fn[,args...])``
Calls ``fn`` with arguments, then finalizes with ``cleanup_fn`` on any thrown error.
Implemented using ``call_with_finalizer(0,false,...)``.
* ``dfhack.with_temp_object(obj,fn[,args...])``
Calls ``fn(obj,args...)``, then finalizes with ``obj:delete()``.
* ``dfhack.exception`` * ``dfhack.exception``
Metatable of error objects used by dfhack. The objects have the Metatable of error objects used by dfhack. The objects have the
@ -580,6 +550,46 @@ Exception handling
The default value of the ``verbose`` argument of ``err:tostring()``. The default value of the ``verbose`` argument of ``err:tostring()``.
Locking and finalization
------------------------
* ``dfhack.with_suspend(f[,args...])``
Calls ``f`` with arguments after grabbing the DF core suspend lock.
Suspending is necessary for accessing a consistent state of DF memory.
Returned values and errors are propagated through after releasing
the lock. It is safe to nest suspends.
Every thread is allowed only one suspend per DF frame, so it is best
to group operations together in one big critical section. A plugin
can choose to run all lua code inside a C++-side suspend lock.
* ``dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])``
Invokes ``fn`` with ``args``, and after it returns or throws an
error calls ``cleanup_fn`` with ``cleanup_args``. Any return values from
``fn`` are propagated, and errors are re-thrown.
The ``num_cleanup_args`` integer specifies the number of ``cleanup_args``,
and the ``always`` boolean specifies if cleanup should be called in any case,
or only in case of an error.
* ``dfhack.with_finalize(cleanup_fn,fn[,args...])``
Calls ``fn`` with arguments, then finalizes with ``cleanup_fn``.
Implemented using ``call_with_finalizer(0,true,...)``.
* ``dfhack.with_onerror(cleanup_fn,fn[,args...])``
Calls ``fn`` with arguments, then finalizes with ``cleanup_fn`` on any thrown error.
Implemented using ``call_with_finalizer(0,false,...)``.
* ``dfhack.with_temp_object(obj,fn[,args...])``
Calls ``fn(obj,args...)``, then finalizes with ``obj:delete()``.
Persistent configuration storage Persistent configuration storage
-------------------------------- --------------------------------
@ -1312,6 +1322,42 @@ Features:
Invokes all listeners contained in the event in an arbitrary Invokes all listeners contained in the event in an arbitrary
order using ``dfhack.safecall``. order using ``dfhack.safecall``.
=======
Modules
=======
DFHack sets up the lua interpreter so that the built-in ``require``
function can be used to load shared lua code from hack/lua/.
The ``dfhack`` namespace reference itself may be obtained via
``require('dfhack')``, although it is initially created as a
global by C++ bootstrap code.
The following functions are provided:
* ``mkmodule(name)``
Creates an environment table for the module. Intended to be used as::
local _ENV = mkmodule('foo')
...
return _ENV
If called the second time, returns the same table; thus providing reload support.
* ``reload(name)``
Reloads a previously ``require``-d module *"name"* from the file.
Intended as a help for module development.
* ``dfhack.BASE_G``
This variable contains the root global environment table, which is
used as a base for all module and script environments. Its contents
should be kept limited to the standard Lua library and API described
in this document.
======= =======
Plugins Plugins
======= =======
@ -1373,3 +1419,40 @@ sort
Does not export any native functions as of now. Instead, it Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items. calls lua code to perform the actual ordering of list items.
=======
Scripts
=======
Any files with the .lua extension placed into hack/scripts/*
are automatically used by the DFHack core as commands. The
matching command name consists of the name of the file sans
the extension.
**NOTE:** Scripts placed in subdirectories still can be accessed, but
do not clutter the ``ls`` command list; thus it is preferred
for obscure developer-oriented scripts and scripts used by tools.
When calling such scripts, always use '/' as the separator for
directories, e.g. ``devel/lua-example``.
Scripts are re-read from disk every time they are used
(this may be changed later to check the file change time); however
the global variable values persist in memory between calls.
Every script gets its own separate environment for global
variables.
Arguments are passed in to the scripts via the **...** built-in
quasi-variable; when the script is called by the DFHack core,
they are all guaranteed to be non-nil strings.
DFHack core invokes the scripts in the *core context* (see above);
however it is possible to call them from any lua code (including
from other scripts) in any context, via the same function the core uses:
* ``dfhack.run_script(name[,args...])``
Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
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.

@ -320,7 +320,7 @@ ul.auto-toc {
<div class="contents topic" id="contents"> <div class="contents topic" id="contents">
<p class="topic-title first">Contents</p> <p class="topic-title first">Contents</p>
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#df-structure-wrapper" id="id1">DF structure wrapper</a><ul> <li><a class="reference internal" href="#df-data-structure-wrapper" id="id1">DF data structure wrapper</a><ul>
<li><a class="reference internal" href="#typed-object-references" id="id2">Typed object references</a><ul> <li><a class="reference internal" href="#typed-object-references" id="id2">Typed object references</a><ul>
<li><a class="reference internal" href="#primitive-references" id="id3">Primitive references</a></li> <li><a class="reference internal" href="#primitive-references" id="id3">Primitive references</a></li>
<li><a class="reference internal" href="#struct-references" id="id4">Struct references</a></li> <li><a class="reference internal" href="#struct-references" id="id4">Struct references</a></li>
@ -336,8 +336,8 @@ ul.auto-toc {
<li><a class="reference internal" href="#dfhack-api" id="id10">DFHack API</a><ul> <li><a class="reference internal" href="#dfhack-api" id="id10">DFHack API</a><ul>
<li><a class="reference internal" href="#native-utilities" id="id11">Native utilities</a><ul> <li><a class="reference internal" href="#native-utilities" id="id11">Native utilities</a><ul>
<li><a class="reference internal" href="#input-output" id="id12">Input &amp; Output</a></li> <li><a class="reference internal" href="#input-output" id="id12">Input &amp; Output</a></li>
<li><a class="reference internal" href="#miscellaneous" id="id13">Miscellaneous</a></li> <li><a class="reference internal" href="#exception-handling" id="id13">Exception handling</a></li>
<li><a class="reference internal" href="#exception-handling" id="id14">Exception handling</a></li> <li><a class="reference internal" href="#locking-and-finalization" id="id14">Locking and finalization</a></li>
<li><a class="reference internal" href="#persistent-configuration-storage" id="id15">Persistent configuration storage</a></li> <li><a class="reference internal" href="#persistent-configuration-storage" id="id15">Persistent configuration storage</a></li>
<li><a class="reference internal" href="#material-info-lookup" id="id16">Material info lookup</a></li> <li><a class="reference internal" href="#material-info-lookup" id="id16">Material info lookup</a></li>
</ul> </ul>
@ -360,15 +360,31 @@ ul.auto-toc {
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#plugins" id="id29">Plugins</a><ul> <li><a class="reference internal" href="#modules" id="id29">Modules</a></li>
<li><a class="reference internal" href="#burrows" id="id30">burrows</a></li> <li><a class="reference internal" href="#plugins" id="id30">Plugins</a><ul>
<li><a class="reference internal" href="#sort" id="id31">sort</a></li> <li><a class="reference internal" href="#burrows" id="id31">burrows</a></li>
<li><a class="reference internal" href="#sort" id="id32">sort</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#scripts" id="id33">Scripts</a></li>
</ul> </ul>
</div> </div>
<div class="section" id="df-structure-wrapper"> <p>The current version of DFHack has extensive support for
<h1><a class="toc-backref" href="#id1">DF structure wrapper</a></h1> the Lua scripting language, providing access to:</p>
<ol class="arabic simple">
<li>Raw data structures used by the game.</li>
<li>Many C++ functions for high-level access to these
structures, and interaction with dfhack itself.</li>
<li>Some functions exported by C++ plugins.</li>
</ol>
<p>Lua code can be used both for writing scripts, which
are treated by DFHack command line prompt almost as
native C++ commands, and invoked by plugins written in c++.</p>
<p>This document describes native API available to Lua in detail.
For the most part it does not describe utility functions
implemented by Lua files located in hack/lua/...</p>
<div class="section" id="df-data-structure-wrapper">
<h1><a class="toc-backref" href="#id1">DF data structure wrapper</a></h1>
<p>DF structures described by the xml files in library/xml are exported <p>DF structures described by the xml files in library/xml are exported
to lua code as a tree of objects and functions under the <tt class="docutils literal">df</tt> global, to lua code as a tree of objects and functions under the <tt class="docutils literal">df</tt> global,
which broadly maps to the <tt class="docutils literal">df</tt> namespace in C++.</p> which broadly maps to the <tt class="docutils literal">df</tt> namespace in C++.</p>
@ -764,28 +780,8 @@ string, global environment and command-line history file.</p>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="miscellaneous">
<h3><a class="toc-backref" href="#id13">Miscellaneous</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.run_script(name[,args...])</span></tt></p>
<p>Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
The <tt class="docutils literal">name</tt> argument should be the name stem, as would be used on the command line.
Note that the script is re-read from the file every time it is called, and errors
are propagated to the caller.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_suspend(f[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal">f</tt> with arguments after grabbing the DF core suspend lock.
Suspending is necessary for accessing a consistent state of DF memory.</p>
<p>Returned values and errors are propagated through after releasing
the lock. It is safe to nest suspends.</p>
<p>Every thread is allowed only one suspend per DF frame, so it is best
to group operations together in one big critical section. A plugin
can choose to run all lua code inside a C++-side suspend lock.</p>
</li>
</ul>
</div>
<div class="section" id="exception-handling"> <div class="section" id="exception-handling">
<h3><a class="toc-backref" href="#id14">Exception handling</a></h3> <h3><a class="toc-backref" href="#id13">Exception handling</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.error(msg[,level[,verbose]])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.error(msg[,level[,verbose]])</span></tt></p>
<p>Throws a dfhack exception object with location and stack trace. <p>Throws a dfhack exception object with location and stack trace.
@ -808,25 +804,6 @@ returning. Intended as a convenience function.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.saferesume(coroutine[,args...])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.saferesume(coroutine[,args...])</span></tt></p>
<p>Compares to coroutine.resume like dfhack.safecall vs pcall.</p> <p>Compares to coroutine.resume like dfhack.safecall vs pcall.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])</span></tt></p>
<p>Invokes <tt class="docutils literal">fn</tt> with <tt class="docutils literal">args</tt>, and after it returns or throws an
error calls <tt class="docutils literal">cleanup_fn</tt> with <tt class="docutils literal">cleanup_args</tt>. Any return values from
<tt class="docutils literal">fn</tt> are propagated, and errors are re-thrown.</p>
<p>The <tt class="docutils literal">num_cleanup_args</tt> integer specifies the number of <tt class="docutils literal">cleanup_args</tt>,
and the <tt class="docutils literal">always</tt> boolean specifies if cleanup should be called in any case,
or only in case of an error.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_finalize(cleanup_fn,fn[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal">fn</tt> with arguments, then finalizes with <tt class="docutils literal">cleanup_fn</tt>.
Implemented using <tt class="docutils literal"><span class="pre">call_with_finalizer(0,true,...)</span></tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_onerror(cleanup_fn,fn[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal">fn</tt> with arguments, then finalizes with <tt class="docutils literal">cleanup_fn</tt> on any thrown error.
Implemented using <tt class="docutils literal"><span class="pre">call_with_finalizer(0,false,...)</span></tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_temp_object(obj,fn[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal"><span class="pre">fn(obj,args...)</span></tt>, then finalizes with <tt class="docutils literal">obj:delete()</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.exception</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.exception</tt></p>
<p>Metatable of error objects used by dfhack. The objects have the <p>Metatable of error objects used by dfhack. The objects have the
following properties:</p> following properties:</p>
@ -859,6 +836,39 @@ following properties:</p>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="locking-and-finalization">
<h3><a class="toc-backref" href="#id14">Locking and finalization</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_suspend(f[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal">f</tt> with arguments after grabbing the DF core suspend lock.
Suspending is necessary for accessing a consistent state of DF memory.</p>
<p>Returned values and errors are propagated through after releasing
the lock. It is safe to nest suspends.</p>
<p>Every thread is allowed only one suspend per DF frame, so it is best
to group operations together in one big critical section. A plugin
can choose to run all lua code inside a C++-side suspend lock.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])</span></tt></p>
<p>Invokes <tt class="docutils literal">fn</tt> with <tt class="docutils literal">args</tt>, and after it returns or throws an
error calls <tt class="docutils literal">cleanup_fn</tt> with <tt class="docutils literal">cleanup_args</tt>. Any return values from
<tt class="docutils literal">fn</tt> are propagated, and errors are re-thrown.</p>
<p>The <tt class="docutils literal">num_cleanup_args</tt> integer specifies the number of <tt class="docutils literal">cleanup_args</tt>,
and the <tt class="docutils literal">always</tt> boolean specifies if cleanup should be called in any case,
or only in case of an error.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_finalize(cleanup_fn,fn[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal">fn</tt> with arguments, then finalizes with <tt class="docutils literal">cleanup_fn</tt>.
Implemented using <tt class="docutils literal"><span class="pre">call_with_finalizer(0,true,...)</span></tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_onerror(cleanup_fn,fn[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal">fn</tt> with arguments, then finalizes with <tt class="docutils literal">cleanup_fn</tt> on any thrown error.
Implemented using <tt class="docutils literal"><span class="pre">call_with_finalizer(0,false,...)</span></tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_temp_object(obj,fn[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal"><span class="pre">fn(obj,args...)</span></tt>, then finalizes with <tt class="docutils literal">obj:delete()</tt>.</p>
</li>
</ul>
</div>
<div class="section" id="persistent-configuration-storage"> <div class="section" id="persistent-configuration-storage">
<h3><a class="toc-backref" href="#id15">Persistent configuration storage</a></h3> <h3><a class="toc-backref" href="#id15">Persistent configuration storage</a></h3>
<p>This api is intended for storing configuration options in the world itself. <p>This api is intended for storing configuration options in the world itself.
@ -1470,15 +1480,45 @@ order using <tt class="docutils literal">dfhack.safecall</tt>.</p>
</div> </div>
</div> </div>
</div> </div>
<div class="section" id="modules">
<h1><a class="toc-backref" href="#id29">Modules</a></h1>
<p>DFHack sets up the lua interpreter so that the built-in <tt class="docutils literal">require</tt>
function can be used to load shared lua code from hack/lua/.
The <tt class="docutils literal">dfhack</tt> namespace reference itself may be obtained via
<tt class="docutils literal"><span class="pre">require('dfhack')</span></tt>, although it is initially created as a
global by C++ bootstrap code.</p>
<p>The following functions are provided:</p>
<ul>
<li><p class="first"><tt class="docutils literal">mkmodule(name)</tt></p>
<p>Creates an environment table for the module. Intended to be used as:</p>
<pre class="literal-block">
local _ENV = mkmodule('foo')
...
return _ENV
</pre>
<p>If called the second time, returns the same table; thus providing reload support.</p>
</li>
<li><p class="first"><tt class="docutils literal">reload(name)</tt></p>
<p>Reloads a previously <tt class="docutils literal">require</tt>-d module <em>&quot;name&quot;</em> from the file.
Intended as a help for module development.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.BASE_G</tt></p>
<p>This variable contains the root global environment table, which is
used as a base for all module and script environments. Its contents
should be kept limited to the standard Lua library and API described
in this document.</p>
</li>
</ul>
</div>
<div class="section" id="plugins"> <div class="section" id="plugins">
<h1><a class="toc-backref" href="#id29">Plugins</a></h1> <h1><a class="toc-backref" href="#id30">Plugins</a></h1>
<p>DFHack plugins may export native functions and events <p>DFHack plugins may export native functions and events
to lua contexts. They are automatically imported by to lua contexts. They are automatically imported by
<tt class="docutils literal"><span class="pre">mkmodule('plugins.&lt;name&gt;')</span></tt>; this means that a lua <tt class="docutils literal"><span class="pre">mkmodule('plugins.&lt;name&gt;')</span></tt>; this means that a lua
module file is still necessary for <tt class="docutils literal">require</tt> to read.</p> module file is still necessary for <tt class="docutils literal">require</tt> to read.</p>
<p>The following plugins have lua support.</p> <p>The following plugins have lua support.</p>
<div class="section" id="burrows"> <div class="section" id="burrows">
<h2><a class="toc-backref" href="#id30">burrows</a></h2> <h2><a class="toc-backref" href="#id31">burrows</a></h2>
<p>Implements extended burrow manipulations.</p> <p>Implements extended burrow manipulations.</p>
<p>Events:</p> <p>Events:</p>
<ul> <ul>
@ -1516,11 +1556,41 @@ set is the same as used by the command line.</p>
<p>The lua module file also re-exports functions from <tt class="docutils literal">dfhack.burrows</tt>.</p> <p>The lua module file also re-exports functions from <tt class="docutils literal">dfhack.burrows</tt>.</p>
</div> </div>
<div class="section" id="sort"> <div class="section" id="sort">
<h2><a class="toc-backref" href="#id31">sort</a></h2> <h2><a class="toc-backref" href="#id32">sort</a></h2>
<p>Does not export any native functions as of now. Instead, it <p>Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.</p> calls lua code to perform the actual ordering of list items.</p>
</div> </div>
</div> </div>
<div class="section" id="scripts">
<h1><a class="toc-backref" href="#id33">Scripts</a></h1>
<p>Any files with the .lua extension placed into hack/scripts/*
are automatically used by the DFHack core as commands. The
matching command name consists of the name of the file sans
the extension.</p>
<p><strong>NOTE:</strong> Scripts placed in subdirectories still can be accessed, but
do not clutter the <tt class="docutils literal">ls</tt> command list; thus it is preferred
for obscure developer-oriented scripts and scripts used by tools.
When calling such scripts, always use '/' as the separator for
directories, e.g. <tt class="docutils literal"><span class="pre">devel/lua-example</span></tt>.</p>
<p>Scripts are re-read from disk every time they are used
(this may be changed later to check the file change time); however
the global variable values persist in memory between calls.
Every script gets its own separate environment for global
variables.</p>
<p>Arguments are passed in to the scripts via the <strong>...</strong> built-in
quasi-variable; when the script is called by the DFHack core,
they are all guaranteed to be non-nil strings.</p>
<p>DFHack core invokes the scripts in the <em>core context</em> (see above);
however it is possible to call them from any lua code (including
from other scripts) in any context, via the same function the core uses:</p>
<ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.run_script(name[,args...])</span></tt></p>
<p>Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
The <tt class="docutils literal">name</tt> argument should be the name stem, as would be used on the command line.</p>
</li>
</ul>
<p>Note that this function lets errors propagate to the caller.</p>
</div>
</div> </div>
</body> </body>
</html> </html>

@ -68,6 +68,8 @@ function dfhack.with_temp_object(obj,fn,...)
return dfhack.call_with_finalizer(1,true,call_delete,obj,fn,obj,...) return dfhack.call_with_finalizer(1,true,call_delete,obj,fn,obj,...)
end end
dfhack.exception.__index = dfhack.exception
-- Module loading -- Module loading
function mkmodule(module,env) function mkmodule(module,env)