Add Lua API for access to some contextual and low-level info.

develop
Alexander Gavrilov 2012-06-13 21:12:36 +04:00
parent 24e2c15113
commit 8d7cf092fd
4 changed files with 199 additions and 13 deletions

@ -607,6 +607,22 @@ One notable difference is that these explicit wrappers allow argument count
adjustment according to the usual lua rules, so trailing false/nil arguments adjustment according to the usual lua rules, so trailing false/nil arguments
can be omitted. can be omitted.
* ``dfhack.getOSType()``
Returns the OS type string from ``symbols.xml``.
* ``dfhack.getDFVersion()``
Returns the DF version string from ``symbols.xml``.
* ``dfhack.getDFPath()``
Returns the DF directory path.
* ``dfhack.getHackPath()``
Returns the dfhack directory path, i.e. ``".../df/hack/"``.
* ``dfhack.isWorldLoaded()`` * ``dfhack.isWorldLoaded()``
Checks if the world is loaded. Checks if the world is loaded.
@ -1102,6 +1118,29 @@ Constructions module
Returns *true, was_only_planned* if removed; or *false* if none found. Returns *true, was_only_planned* if removed; or *false* if none found.
Internal API
------------
These functions are intended for the use by dfhack developers,
and are only documented here for completeness:
* ``dfhack.internal.getAddress(name)``
Returns the global address ``name``, or *nil*.
* ``dfhack.internal.setAddress(name, value)``
Sets the global address ``name``. Returns the value of ``getAddress`` before the change.
* ``dfhack.internal.getBase()``
Returns the base address of the process.
* ``dfhack.internal.getMemRanges()``
Returns a sequence of tables describing virtual memory ranges of the process.
Core interpreter context Core interpreter context
======================== ========================

@ -345,17 +345,18 @@ ul.auto-toc {
<li><a class="reference internal" href="#burrows-module" id="id19">Burrows module</a></li> <li><a class="reference internal" href="#burrows-module" id="id19">Burrows module</a></li>
<li><a class="reference internal" href="#buildings-module" id="id20">Buildings module</a></li> <li><a class="reference internal" href="#buildings-module" id="id20">Buildings module</a></li>
<li><a class="reference internal" href="#constructions-module" id="id21">Constructions module</a></li> <li><a class="reference internal" href="#constructions-module" id="id21">Constructions module</a></li>
<li><a class="reference internal" href="#internal-api" id="id22">Internal API</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#core-interpreter-context" id="id22">Core interpreter context</a><ul> <li><a class="reference internal" href="#core-interpreter-context" id="id23">Core interpreter context</a><ul>
<li><a class="reference internal" href="#event-type" id="id23">Event type</a></li> <li><a class="reference internal" href="#event-type" id="id24">Event type</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#plugins" id="id24">Plugins</a><ul> <li><a class="reference internal" href="#plugins" id="id25">Plugins</a><ul>
<li><a class="reference internal" href="#burrows" id="id25">burrows</a></li> <li><a class="reference internal" href="#burrows" id="id26">burrows</a></li>
<li><a class="reference internal" href="#sort" id="id26">sort</a></li> <li><a class="reference internal" href="#sort" id="id27">sort</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -862,6 +863,18 @@ One notable difference is that these explicit wrappers allow argument count
adjustment according to the usual lua rules, so trailing false/nil arguments adjustment according to the usual lua rules, so trailing false/nil arguments
can be omitted.</p> can be omitted.</p>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.getOSType()</tt></p>
<p>Returns the OS type string from <tt class="docutils literal">symbols.xml</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.getDFVersion()</tt></p>
<p>Returns the DF version string from <tt class="docutils literal">symbols.xml</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.getDFPath()</tt></p>
<p>Returns the DF directory path.</p>
</li>
<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.isWorldLoaded()</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.isWorldLoaded()</tt></p>
<p>Checks if the world is loaded.</p> <p>Checks if the world is loaded.</p>
</li> </li>
@ -1274,9 +1287,28 @@ Returns <em>true, was_only_planned</em> if removed; or <em>false</em> if none fo
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="internal-api">
<h3><a class="toc-backref" href="#id22">Internal API</a></h3>
<p>These functions are intended for the use by dfhack developers,
and are only documented here for completeness:</p>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.internal.getAddress(name)</tt></p>
<p>Returns the global address <tt class="docutils literal">name</tt>, or <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.internal.setAddress(name, value)</tt></p>
<p>Sets the global address <tt class="docutils literal">name</tt>. Returns the value of <tt class="docutils literal">getAddress</tt> before the change.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.internal.getBase()</tt></p>
<p>Returns the base address of the process.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.internal.getMemRanges()</tt></p>
<p>Returns a sequence of tables describing virtual memory ranges of the process.</p>
</li>
</ul>
</div>
</div> </div>
<div class="section" id="core-interpreter-context"> <div class="section" id="core-interpreter-context">
<h2><a class="toc-backref" href="#id22">Core interpreter context</a></h2> <h2><a class="toc-backref" href="#id23">Core interpreter context</a></h2>
<p>While plugins can create any number of interpreter instances, <p>While plugins can create any number of interpreter instances,
there is one special context managed by dfhack core. It is the there is one special context managed by dfhack core. It is the
only context that can receive events from DF and plugins.</p> only context that can receive events from DF and plugins.</p>
@ -1307,7 +1339,7 @@ Using <tt class="docutils literal">timeout_active(id,nil)</tt> cancels the timer
</li> </li>
</ul> </ul>
<div class="section" id="event-type"> <div class="section" id="event-type">
<h3><a class="toc-backref" href="#id23">Event type</a></h3> <h3><a class="toc-backref" href="#id24">Event type</a></h3>
<p>An event is just a lua table with a predefined metatable that <p>An event is just a lua table with a predefined metatable that
contains a __call metamethod. When it is invoked, it loops contains a __call metamethod. When it is invoked, it loops
through the table with next and calls all contained values. through the table with next and calls all contained values.
@ -1333,14 +1365,14 @@ order using <tt class="docutils literal">dfhack.safecall</tt>.</p>
</div> </div>
</div> </div>
<div class="section" id="plugins"> <div class="section" id="plugins">
<h1><a class="toc-backref" href="#id24">Plugins</a></h1> <h1><a class="toc-backref" href="#id25">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="#id25">burrows</a></h2> <h2><a class="toc-backref" href="#id26">burrows</a></h2>
<p>Implements extended burrow manipulations.</p> <p>Implements extended burrow manipulations.</p>
<p>Events:</p> <p>Events:</p>
<ul> <ul>
@ -1378,7 +1410,7 @@ 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="#id26">sort</a></h2> <h2><a class="toc-backref" href="#id27">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>

@ -84,6 +84,8 @@ distribution.
using namespace DFHack; using namespace DFHack;
using namespace DFHack::LuaWrapper; using namespace DFHack::LuaWrapper;
void dfhack_printerr(lua_State *S, const std::string &str);
void Lua::Push(lua_State *state, const Units::NoblePosition &pos) void Lua::Push(lua_State *state, const Units::NoblePosition &pos)
{ {
lua_createtable(state, 0, 3); lua_createtable(state, 0, 3);
@ -640,10 +642,37 @@ static void OpenModule(lua_State *state, const char *mname,
/***** DFHack module *****/ /***** DFHack module *****/
static std::string getOSType()
{
switch (Core::getInstance().vinfo->getOS())
{
case OS_WINDOWS:
return "windows";
case OS_LINUX:
return "linux";
case OS_APPLE:
return "darwin";
default:
return "unknown";
}
}
static std::string getDFVersion() { return Core::getInstance().vinfo->getVersion(); }
static std::string getDFPath() { return Core::getInstance().p->getPath(); }
static std::string getHackPath() { return Core::getInstance().getHackPath(); }
static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); } static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); }
static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); } static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); }
static const LuaWrapper::FunctionReg dfhack_module[] = { static const LuaWrapper::FunctionReg dfhack_module[] = {
WRAP(getOSType),
WRAP(getDFVersion),
WRAP(getDFPath),
WRAP(getHackPath),
WRAP(isWorldLoaded), WRAP(isWorldLoaded),
WRAP(isMapLoaded), WRAP(isMapLoaded),
WRAPM(Translation, TranslateName), WRAPM(Translation, TranslateName),
@ -990,6 +1019,91 @@ static const luaL_Reg dfhack_constructions_funcs[] = {
{ NULL, NULL } { NULL, NULL }
}; };
/***** Internal module *****/
static uint32_t getBase() { return Core::getInstance().p->getBase(); }
static const LuaWrapper::FunctionReg dfhack_internal_module[] = {
WRAP(getBase),
{ NULL, NULL }
};
static int internal_getAddress(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
uint32_t addr = Core::getInstance().vinfo->getAddress(name);
if (addr)
lua_pushnumber(L, addr);
else
lua_pushnil(L);
return 1;
}
static int internal_setAddress(lua_State *L)
{
std::string name = luaL_checkstring(L, 1);
uint32_t addr = luaL_checkint(L, 2);
internal_getAddress(L);
// Set the address
Core::getInstance().vinfo->setAddress(name, addr);
auto fields = df::global::_identity.getFields();
for (int i = 0; fields && fields[i].mode != struct_field_info::END; ++i)
{
if (fields[i].name != name)
continue;
*(void**)fields[i].offset = (void*)addr;
}
// Print via printerr, so that it is definitely logged to stderr.log.
std::string msg = stl_sprintf("<global-address name='%s' value='0x%x'/>", name.c_str(), addr);
dfhack_printerr(L, msg);
return 1;
}
static int internal_getMemRanges(lua_State *L)
{
std::vector<DFHack::t_memrange> ranges;
Core::getInstance().p->getMemRanges(ranges);
lua_newtable(L);
for(size_t i = 0; i < ranges.size(); i++)
{
lua_newtable(L);
lua_pushnumber(L, (uint32_t)ranges[i].start);
lua_setfield(L, -2, "start");
lua_pushnumber(L, (uint32_t)ranges[i].end);
lua_setfield(L, -2, "end");
lua_pushstring(L, ranges[i].name);
lua_setfield(L, -2, "name");
lua_pushboolean(L, ranges[i].read);
lua_setfield(L, -2, "read");
lua_pushboolean(L, ranges[i].write);
lua_setfield(L, -2, "write");
lua_pushboolean(L, ranges[i].execute);
lua_setfield(L, -2, "execute");
lua_pushboolean(L, ranges[i].shared);
lua_setfield(L, -2, "shared");
lua_pushboolean(L, ranges[i].valid);
lua_setfield(L, -2, "valid");
lua_rawseti(L, -2, i+1);
}
return 1;
}
static const luaL_Reg dfhack_internal_funcs[] = {
{ "getAddress", internal_getAddress },
{ "setAddress", internal_setAddress },
{ "getMemRanges", internal_getMemRanges },
{ NULL, NULL }
};
/************************ /************************
* Main Open function * * Main Open function *
@ -1009,4 +1123,5 @@ void OpenDFHackApi(lua_State *state)
OpenModule(state, "burrows", dfhack_burrows_module, dfhack_burrows_funcs); OpenModule(state, "burrows", dfhack_burrows_module, dfhack_burrows_funcs);
OpenModule(state, "buildings", dfhack_buildings_module, dfhack_buildings_funcs); OpenModule(state, "buildings", dfhack_buildings_module, dfhack_buildings_funcs);
OpenModule(state, "constructions", dfhack_constructions_module); OpenModule(state, "constructions", dfhack_constructions_module);
OpenModule(state, "internal", dfhack_internal_module, dfhack_internal_funcs);
} }

@ -66,6 +66,8 @@ using namespace DFHack::LuaWrapper;
lua_State *DFHack::Lua::Core::State = NULL; lua_State *DFHack::Lua::Core::State = NULL;
void dfhack_printerr(lua_State *S, const std::string &str);
inline void AssertCoreSuspend(lua_State *state) inline void AssertCoreSuspend(lua_State *state)
{ {
assert(!Lua::IsCoreContext(state) || DFHack::Core::getInstance().isSuspended()); assert(!Lua::IsCoreContext(state) || DFHack::Core::getInstance().isSuspended());
@ -96,8 +98,6 @@ static void check_valid_ptr_index(lua_State *state, int val_index)
} }
} }
static void dfhack_printerr(lua_State *S, const std::string &str);
static void signal_typeid_error(color_ostream *out, lua_State *state, static void signal_typeid_error(color_ostream *out, lua_State *state,
type_identity *type, const char *msg, type_identity *type, const char *msg,
int val_index, bool perr, bool signal) int val_index, bool perr, bool signal)
@ -233,7 +233,7 @@ static int lua_dfhack_println(lua_State *S)
return 0; return 0;
} }
static void dfhack_printerr(lua_State *S, const std::string &str) void dfhack_printerr(lua_State *S, const std::string &str)
{ {
if (color_ostream *out = Lua::GetOutput(S)) if (color_ostream *out = Lua::GetOutput(S))
out->printerr("%s\n", str.c_str()); out->printerr("%s\n", str.c_str());