diff --git a/COMPILE.rst b/COMPILE.rst index beb738363..8fca0e1f5 100644 --- a/COMPILE.rst +++ b/COMPILE.rst @@ -152,10 +152,13 @@ Valid and useful build types include 'Release', 'Debug' and ================================ Using the library as a developer ================================ -Currently, the only way to use the library is to write a plugin that can be loaded by it. + +Currently, the most direct way to use the library is to write a plugin that can be loaded by it. All the plugins can be found in the 'plugins' folder. There's no in-depth documentation on how to write one yet, but it should be easy enough to copy one and just follow the pattern. +Other than through plugins, it is possible to use DFHack via remote access interface, or by writing Lua scripts. + The most important parts of DFHack are the Core, Console, Modules and Plugins. * Core acts as the centerpiece of DFHack - it acts as a filter between DF and SDL and synchronizes the various plugins with DF. @@ -171,6 +174,24 @@ The main license is zlib/libpng, some bits are MIT licensed, and some are BSD li Feel free to add your own extensions and plugins. Contributing back to the dfhack repository is welcome and the right thing to do :) +DF data structure definitions +============================= + +DFHack uses information about the game data structures, represented via xml files in the library/xml/ submodule. + +Data structure layouts are described in files following the df.*.xml name pattern. This information is transformed by a perl script into C++ headers describing the structures, and associated metadata for the Lua wrapper. These headers and data are then compiled into the DFHack libraries, thus necessitating a compatibility break every time layouts change; in return it significantly boosts the efficiency and capabilities of DFHack code. + +Global object addresses are stored in symbols.xml, which is copied to the dfhack release package and loaded as data at runtime. + +Remote access interface +======================= + +DFHack supports remote access by exchanging Google protobuf messages via a TCP socket. Both the core and plugins can define remotely accessible methods. The ``dfhack-run`` command uses this interface to invoke ordinary console commands. + +Currently the supported set of requests is limited, because the developers don't know what exactly is most useful. + +Protocol client implementations exist for Java and C#. + Contributing to DFHack ====================== diff --git a/Compile.html b/Compile.html index b0f9e9c6e..e17e57e22 100644 --- a/Compile.html +++ b/Compile.html @@ -334,10 +334,12 @@ ul.auto-toc {
Currently, the only way to use the library is to write a plugin that can be loaded by it. +
Currently, the most direct way to use the library is to write a plugin that can be loaded by it. All the plugins can be found in the 'plugins' folder. There's no in-depth documentation on how to write one yet, but it should be easy enough to copy one and just follow the pattern.
+Other than through plugins, it is possible to use DFHack via remote access interface, or by writing Lua scripts.
The most important parts of DFHack are the Core, Console, Modules and Plugins.
Feel free to add your own extensions and plugins. Contributing back to the dfhack repository is welcome and the right thing to do :)
+DFHack uses information about the game data structures, represented via xml files in the library/xml/ submodule.
+Data structure layouts are described in files following the df.*.xml name pattern. This information is transformed by a perl script into C++ headers describing the structures, and associated metadata for the Lua wrapper. These headers and data are then compiled into the DFHack libraries, thus necessitating a compatibility break every time layouts change; in return it significantly boosts the efficiency and capabilities of DFHack code.
+Global object addresses are stored in symbols.xml, which is copied to the dfhack release package and loaded as data at runtime.
+DFHack supports remote access by exchanging Google protobuf messages via a TCP socket. Both the core and plugins can define remotely accessible methods. The dfhack-run command uses this interface to invoke ordinary console commands.
+Currently the supported set of requests is limited, because the developers don't know what exactly is most useful.
+Protocol client implementations exist for Java and C#.
+Several things should be kept in mind when contributing to DFHack.
DFhack uses ANSI formatting and four spaces as indentation. Line endings are UNIX. The files use UTF-8 encoding. Code not following this won't make me happy, because I'll have to fix it. There's a good chance I'll make you fix it ;)
You can send patches or make a clone of the github repo and ask me on the IRC channel to pull your code in. I'll review it and see if there are any problems. I'll fix them if they are minor.
@@ -506,7 +521,7 @@ this is also a good place to dump new ideas and/or bugs that need fixing.If you want to do memory research, you'll need some tools and some knowledge. In general, you'll need a good memory viewer and optionally something to look at machine code without getting crazy :)
diff --git a/LUA_API.rst b/LUA_API.rst index 2859f8678..252be3374 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -4,9 +4,26 @@ DFHack Lua API .. contents:: -==================== -DF structure wrapper -==================== +The current version of DFHack has extensive support for +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. +It does not describe all of the 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 to lua code as a tree of objects and functions under the ``df`` global, @@ -426,13 +443,17 @@ not destroy any objects allocated in this way, so the user should be prepared to catch the error and do the necessary cleanup. -================ -DFHack utilities -================ +========== +DFHack API +========== DFHack utility functions are placed in the ``dfhack`` global tree. -Currently it defines the following features: +Native utilities +================ + +Input & Output +-------------- * ``dfhack.print(args...)`` @@ -451,6 +472,7 @@ Currently it defines the following features: * ``dfhack.color([color])`` Sets the current output color. If color is *nil* or *-1*, resets to default. + Returns the previous color value. * ``dfhack.is_interactive()`` @@ -473,15 +495,27 @@ Currently it defines the following features: If the interactive console is not accessible, returns *nil, error*. + +Exception handling +------------------ + +* ``dfhack.error(msg[,level[,verbose]])`` + + Throws a dfhack exception object with location and stack trace. + The verbose parameter controls whether the trace is printed by default. + +* ``qerror(msg[,level])`` + + Calls ``dfhack.error()`` with ``verbose`` being *false*. Intended to + be used for user-caused errors in scripts, where stack traces are not + desirable. + * ``dfhack.pcall(f[,args...])`` Invokes f via xpcall, using an error function that attaches a stack trace to the error. The same function is used by SafeCall in C++, and dfhack.safecall. - The returned error is a table with separate ``message`` and - ``stacktrace`` string fields; it implements ``__tostring``. - * ``safecall(f[,args...])``, ``dfhack.safecall(f[,args...])`` Just like pcall, but also prints the error using printerr before @@ -491,12 +525,33 @@ Currently it defines the following features: Compares to coroutine.resume like dfhack.safecall vs pcall. -* ``dfhack.run_script(name[,args...])`` +* ``dfhack.exception`` - 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. + Metatable of error objects used by dfhack. The objects have the + following properties: + + ``err.where`` + The location prefix string, or *nil*. + ``err.message`` + The base message string. + ``err.stacktrace`` + The stack trace string, or *nil*. + ``err.cause`` + A different exception object, or *nil*. + ``err.thread`` + The coroutine that has thrown the exception. + ``err.verbose`` + Boolean, or *nil*; specifies if where and stacktrace should be printed. + ``tostring(err)``, or ``err:tostring([verbose])`` + Converts the exception to string. + +* ``dfhack.exception.verbose`` + + The default value of the ``verbose`` argument of ``err:tostring()``. + + +Locking and finalization +------------------------ * ``dfhack.with_suspend(f[,args...])`` @@ -536,7 +591,7 @@ Currently it defines the following features: Persistent configuration storage -================================ +-------------------------------- This api is intended for storing configuration options in the world itself. It probably should be restricted to data that is world-dependent. @@ -578,7 +633,7 @@ functions can just copy values in memory without doing any actual I/O. However, currently every entry has a 180+-byte dead-weight overhead. Material info lookup -==================== +-------------------- A material info record has fields: @@ -1168,14 +1223,38 @@ and are only documented here for completeness: Sets the global address ``name``. Returns the value of ``getAddress`` before the change. -* ``dfhack.internal.getBase()`` +* ``dfhack.internal.getVTable(name)`` + + Returns the pre-extracted vtable address ``name``, or *nil*. - Returns the base address of the process. +* ``dfhack.internal.getRebaseDelta()`` + + Returns the ASLR rebase offset of the DF executable. * ``dfhack.internal.getMemRanges()`` Returns a sequence of tables describing virtual memory ranges of the process. +* ``dfhack.internal.memmove(dest,src,count)`` + + Wraps the standard memmove function. Accepts both numbers and refs as pointers. + +* ``dfhack.internal.memcmp(ptr1,ptr2,count)`` + + Wraps the standard memcmp function. + +* ``dfhack.internal.memscan(haystack,count,step,needle,nsize)`` + + Searches for ``needle`` of ``nsize`` bytes in ``haystack``, + using ``count`` steps of ``step`` bytes. + Returns: *step_idx, sum_idx, found_ptr*, or *nil* if not found. + +* ``dfhack.internal.diffscan(old_data, new_data, start_idx, end_idx, eltsize[, oldval, newval, delta])`` + + Searches for differences between buffers at ptr1 and ptr2, as integers of size eltsize. + The oldval, newval or delta arguments may be used to specify additional constraints. + Returns: *found_index*, or *nil* if end reached. + Core interpreter context ======================== @@ -1243,6 +1322,218 @@ Features: Invokes all listeners contained in the event in an arbitrary order using ``dfhack.safecall``. + +=========== +Lua 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 module management 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. + +Global environment +================== + +A number of variables and functions are provided in the base global +environment by the mandatory init file dfhack.lua: + +* Color constants + + These are applicable both for ``dfhack.color()`` and color fields + in DF functions or structures: + + COLOR_RESET, COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, + COLOR_RED, COLOR_MAGENTA, COLOR_BROWN, COLOR_GREY, COLOR_DARKGREY, + COLOR_LIGHTBLUE, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN, COLOR_LIGHTRED, + COLOR_LIGHTMAGENTA, COLOR_YELLOW, COLOR_WHITE + +* ``dfhack.onStateChange`` event codes + + Available only in the core context, as is the event itself: + + SC_WORLD_LOADED, SC_WORLD_UNLOADED, SC_MAP_LOADED, + SC_MAP_UNLOADED, SC_VIEWSCREEN_CHANGED, SC_CORE_INITIALIZED + +* Functions already described above + + safecall, qerror, mkmodule, reload + +* ``printall(obj)`` + + If the argument is a lua table or DF object reference, prints all fields. + +* ``copyall(obj)`` + + Returns a shallow copy of the table or reference as a lua table. + +* ``pos2xyz(obj)`` + + The object must have fields x, y and z. Returns them as 3 values. + If obj is *nil*, or x is -30000 (the usual marker for undefined + coordinates), returns *nil*. + +* ``xyz2pos(x,y,z)`` + + Returns a table with x, y and z as fields. + +* ``safe_index(obj,index...)`` + + Walks a sequence of dereferences, which may be represented by numbers or strings. + Returns *nil* if any of obj or indices is *nil*, or a numeric index is out of array bounds. + +utils +===== + +* ``utils.compare(a,b)`` + + Comparator function; returns *-1* if ab, *0* otherwise. + +* ``utils.compare_name(a,b)`` + + Comparator for names; compares empty string last. + +* ``utils.is_container(obj)`` + + Checks if obj is a container ref. + +* ``utils.make_index_sequence(start,end)`` + + Returns a lua sequence of numbers in start..end. + +* ``utils.make_sort_order(data, ordering)`` + + Computes an ordering of objects in data, as a table of integer + indices into the data sequence. Uses ``data.n`` as input length + if present. + + The ordering argument is a sequence of ordering specs, represented + as lua tables with following possible fields: + + ord.key = *function(value)* + Computes comparison key from a data value. Not called on nil. + If omitted, the comparison key is the value itself. + ord.key_table = *function(data)* + Computes a key table from the data table in one go. + ord.compare = *function(a,b)* + Comparison function. Defaults to ``utils.compare`` above. + Called on non-nil keys; nil sorts last. + ord.nil_first = *true/false* + If true, nil keys are sorted first instead of last. + ord.reverse = *true/false* + If true, sort non-nil keys in descending order. + + This function is used by the sort plugin. + +* ``utils.assign(tgt, src)`` + + Does a recursive assignment of src into tgt. + Uses ``df.assign`` if tgt is a native object ref; otherwise + recurses into lua tables. + +* ``utils.clone(obj, deep)`` + + Performs a shallow, or semi-deep copy of the object as a lua table tree. + The deep mode recurses into lua tables and subobjects, except pointers + to other heap objects. + Null pointers are represented as df.NULL. Zero-based native containers + are converted to 1-based lua sequences. + +* ``utils.clone_with_default(obj, default, force)`` + + Copies the object, using the ``default`` lua table tree + as a guide to which values should be skipped as uninteresting. + The ``force`` argument makes it always return a non-*nil* value. + +* ``utils.sort_vector(vector,field,cmpfun)`` + + Sorts a native vector or lua sequence using the comparator function. + If ``field`` is not *nil*, applies the comparator to the field instead + of the whole object. + +* ``utils.binsearch(vector,key,field,cmpfun,min,max)`` + + Does a binary search in a native vector or lua sequence for + ``key``, using ``cmpfun`` and ``field`` like sort_vector. + If ``min`` and ``max`` are specified, they are used as the + search subrange bounds. + + If found, returns *item, true, idx*. Otherwise returns + *nil, false, insert_idx*, where *insert_idx* is the correct + insertion point. + +* ``utils.insert_sorted(vector,item,field,cmpfun)`` + + Does a binary search, and inserts item if not found. + Returns *did_insert, vector[idx], idx*. + +* ``utils.insert_or_update(vector,item,field,cmpfun)`` + + Like ``insert_sorted``, but also assigns the item into + the vector cell if insertion didn't happen. + + As an example, you can use this to set skill values:: + + utils.insert_or_update(soul.skills, {new=true, id=..., rating=...}, 'id') + + (For an explanation of ``new=true``, see table assignment in the wrapper section) + +* ``utils.prompt_yes_no(prompt, default)`` + + Presents a yes/no prompt to the user. If ``default`` is not *nil*, + allows just pressing Enter to submit the default choice. + If the user enters ``'abort'``, throws an error. + +* ``utils.prompt_input(prompt, checkfun, quit_str)`` + + Presents a prompt to input data, until a valid string is entered. + Once ``checkfun(input)`` returns *true, ...*, passes the values + through. If the user enters the quit_str (defaults to ``'~~~'``), + throws an error. + +* ``utils.check_number(text)`` + + A ``prompt_input`` ``checkfun`` that verifies a number input. + +dumper +====== + +A third-party lua table dumper module from +http://lua-users.org/wiki/DataDumper. Defines one +function: + +* ``dumper.DataDumper(value, varname, fastmode, ident, indent_step)`` + + Returns ``value`` converted to a string. The ``indent_step`` + argument specifies the indentation step size in spaces. For + the other arguments see the original documentation link above. + + ======= Plugins ======= @@ -1304,3 +1595,43 @@ sort Does not export any native functions as of now. Instead, it 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. + +If the first line of the script is a one-line comment, it is +used by the built-in ``ls`` and ``help`` commands. + +**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. diff --git a/Lua API.html b/Lua API.html index 047457985..0496d7e50 100644 --- a/Lua API.html +++ b/Lua API.html @@ -320,7 +320,7 @@ ul.auto-toc {Contents
The current version of DFHack has extensive support for +the Lua scripting language, providing access to:
+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. +It does not describe all of the utility functions +implemented by Lua files located in hack/lua/...
+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, which broadly maps to the df namespace in C++.
@@ -717,10 +744,13 @@ should be prepared to catch the error and do the necessary cleanup.DFHack utility functions are placed in the dfhack global tree.
-Currently it defines the following features:
+dfhack.print(args...)
Output tab-separated args as standard lua print would do, @@ -734,7 +764,8 @@ works with DFHack output infrastructure.
Same as println; intended for errors. Uses red color and logs to stderr.log.
dfhack.color([color])
-Sets the current output color. If color is nil or -1, resets to default.
+Sets the current output color. If color is nil or -1, resets to default. +Returns the previous color value.
dfhack.is_interactive()
Checks if the thread can access the interactive console and returns true or false.
@@ -752,12 +783,24 @@ this, forcing the function to block on input with lock held. string, global environment and command-line history file.If the interactive console is not accessible, returns nil, error.
dfhack.error(msg[,level[,verbose]])
+Throws a dfhack exception object with location and stack trace. +The verbose parameter controls whether the trace is printed by default.
+qerror(msg[,level])
+Calls dfhack.error() with verbose being false. Intended to +be used for user-caused errors in scripts, where stack traces are not +desirable.
+dfhack.pcall(f[,args...])
Invokes f via xpcall, using an error function that attaches a stack trace to the error. The same function is used by SafeCall in C++, and dfhack.safecall.
-The returned error is a table with separate message and -stacktrace string fields; it implements __tostring.
safecall(f[,args...]), dfhack.safecall(f[,args...])
Just like pcall, but also prints the error using printerr before @@ -766,12 +809,41 @@ returning. Intended as a convenience function.
dfhack.saferesume(coroutine[,args...])
Compares to coroutine.resume like dfhack.safecall vs pcall.
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.exception
+Metatable of error objects used by dfhack. The objects have the +following properties:
+The location prefix string, or nil.
+The base message string.
+The stack trace string, or nil.
+A different exception object, or nil.
+The coroutine that has thrown the exception.
+Boolean, or nil; specifies if where and stacktrace should be printed.
+Converts the exception to string.
+dfhack.exception.verbose
+The default value of the verbose argument of err:tostring().
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.
@@ -801,8 +873,9 @@ Implemented using call_with_finalCalls fn(obj,args...), then finalizes with obj:delete().
This api is intended for storing configuration options in the world itself. It probably should be restricted to data that is world-dependent.
Entries are identified by a string key, but it is also possible to manage @@ -837,7 +910,7 @@ functions can just copy values in memory without doing any actual I/O. However, currently every entry has a 180+-byte dead-weight overhead.
A material info record has fields:
type, index, material
@@ -880,8 +953,9 @@ Accept dfhack_material_category auto-assign table.Thin wrappers around C++ functions, similar to the ones for virtual methods. One notable difference is that these explicit wrappers allow argument count adjustment according to the usual lua rules, so trailing false/nil arguments @@ -910,7 +984,7 @@ can be omitted.
dfhack.gui.getCurViewscreen()
Returns the viewscreen that is current in the core.
@@ -946,7 +1020,7 @@ The is_bright boolean actually seems to invert the brightness.dfhack.job.cloneJobStruct(job)
Creates a deep copy of the given job.
@@ -983,7 +1057,7 @@ a lua list containing them.dfhack.units.getPosition(unit)
Returns true x,y,z of the unit, or nil if invalid; may be not equal to unit.pos if caged.
@@ -1037,7 +1111,7 @@ or raws. The ignore_noble boolean disables thedfhack.items.getPosition(item)
Returns true x,y,z of the item, or nil if invalid; may be not equal to item.pos if in inventory.
@@ -1080,7 +1154,7 @@ Returns false in case of error.dfhack.maps.getSize()
Returns map size in blocks: x, y, z
@@ -1121,7 +1195,7 @@ burrows, or the presence of invaders.dfhack.burrows.findByName(name)
Returns the burrow pointer or nil.
@@ -1156,7 +1230,7 @@ burrows, or the presence of invaders.dfhack.buildings.getSize(building)
Returns width, height, centerx, centery.
@@ -1296,7 +1370,7 @@ can be determined this way, constructBuildingdfhack.constructions.designateNew(pos,type,item_type,mat_index)
Designates a new construction at given position. If there already is @@ -1312,7 +1386,7 @@ Returns true, was_only_planned if removed; or false if none fo
These functions are intended for the use by dfhack developers, and are only documented here for completeness:
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.getVTable(name)
+Returns the pre-extracted vtable address name, or nil.
+dfhack.internal.getRebaseDelta()
+Returns the ASLR rebase offset of the DF executable.
dfhack.internal.getMemRanges()
Returns a sequence of tables describing virtual memory ranges of the process.
dfhack.internal.memmove(dest,src,count)
+Wraps the standard memmove function. Accepts both numbers and refs as pointers.
+dfhack.internal.memcmp(ptr1,ptr2,count)
+Wraps the standard memcmp function.
+dfhack.internal.memscan(haystack,count,step,needle,nsize)
+Searches for needle of nsize bytes in haystack, +using count steps of step bytes. +Returns: step_idx, sum_idx, found_ptr, or nil if not found.
+dfhack.internal.diffscan(old_data, new_data, start_idx, end_idx, eltsize[, oldval, newval, delta])
+Searches for differences between buffers at ptr1 and ptr2, as integers of size eltsize. +The oldval, newval or delta arguments may be used to specify additional constraints. +Returns: found_index, or nil if end reached.
+While plugins can create any number of interpreter instances, there is one special context managed by dfhack core. It is the only context that can receive events from DF and plugins.
@@ -1367,7 +1460,7 @@ Using timeout_active(id,nil) cancels the timerAn event is just a lua table with a predefined metatable that contains a __call metamethod. When it is invoked, it loops through the table with next and calls all contained values. @@ -1392,15 +1485,201 @@ order using dfhack.safecall.
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 module management 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.
+A number of variables and functions are provided in the base global +environment by the mandatory init file dfhack.lua:
+Color constants
+These are applicable both for dfhack.color() and color fields +in DF functions or structures:
+COLOR_RESET, COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, +COLOR_RED, COLOR_MAGENTA, COLOR_BROWN, COLOR_GREY, COLOR_DARKGREY, +COLOR_LIGHTBLUE, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN, COLOR_LIGHTRED, +COLOR_LIGHTMAGENTA, COLOR_YELLOW, COLOR_WHITE
+dfhack.onStateChange event codes
+Available only in the core context, as is the event itself:
+SC_WORLD_LOADED, SC_WORLD_UNLOADED, SC_MAP_LOADED, +SC_MAP_UNLOADED, SC_VIEWSCREEN_CHANGED, SC_CORE_INITIALIZED
+Functions already described above
+safecall, qerror, mkmodule, reload
+printall(obj)
+If the argument is a lua table or DF object reference, prints all fields.
+copyall(obj)
+Returns a shallow copy of the table or reference as a lua table.
+pos2xyz(obj)
+The object must have fields x, y and z. Returns them as 3 values. +If obj is nil, or x is -30000 (the usual marker for undefined +coordinates), returns nil.
+xyz2pos(x,y,z)
+Returns a table with x, y and z as fields.
+safe_index(obj,index...)
+Walks a sequence of dereferences, which may be represented by numbers or strings. +Returns nil if any of obj or indices is nil, or a numeric index is out of array bounds.
+utils.compare(a,b)
+Comparator function; returns -1 if a<b, 1 if a>b, 0 otherwise.
+utils.compare_name(a,b)
+Comparator for names; compares empty string last.
+utils.is_container(obj)
+Checks if obj is a container ref.
+utils.make_index_sequence(start,end)
+Returns a lua sequence of numbers in start..end.
+utils.make_sort_order(data, ordering)
+Computes an ordering of objects in data, as a table of integer +indices into the data sequence. Uses data.n as input length +if present.
+The ordering argument is a sequence of ordering specs, represented +as lua tables with following possible fields:
+Computes comparison key from a data value. Not called on nil. +If omitted, the comparison key is the value itself.
+Computes a key table from the data table in one go.
+Comparison function. Defaults to utils.compare above. +Called on non-nil keys; nil sorts last.
+If true, nil keys are sorted first instead of last.
+If true, sort non-nil keys in descending order.
+This function is used by the sort plugin.
+utils.assign(tgt, src)
+Does a recursive assignment of src into tgt. +Uses df.assign if tgt is a native object ref; otherwise +recurses into lua tables.
+utils.clone(obj, deep)
+Performs a shallow, or semi-deep copy of the object as a lua table tree. +The deep mode recurses into lua tables and subobjects, except pointers +to other heap objects. +Null pointers are represented as df.NULL. Zero-based native containers +are converted to 1-based lua sequences.
+utils.clone_with_default(obj, default, force)
+Copies the object, using the default lua table tree +as a guide to which values should be skipped as uninteresting. +The force argument makes it always return a non-nil value.
+utils.sort_vector(vector,field,cmpfun)
+Sorts a native vector or lua sequence using the comparator function. +If field is not nil, applies the comparator to the field instead +of the whole object.
+utils.binsearch(vector,key,field,cmpfun,min,max)
+Does a binary search in a native vector or lua sequence for +key, using cmpfun and field like sort_vector. +If min and max are specified, they are used as the +search subrange bounds.
+If found, returns item, true, idx. Otherwise returns +nil, false, insert_idx, where insert_idx is the correct +insertion point.
+utils.insert_sorted(vector,item,field,cmpfun)
+Does a binary search, and inserts item if not found. +Returns did_insert, vector[idx], idx.
+utils.insert_or_update(vector,item,field,cmpfun)
+Like insert_sorted, but also assigns the item into +the vector cell if insertion didn't happen.
+As an example, you can use this to set skill values:
++utils.insert_or_update(soul.skills, {new=true, id=..., rating=...}, 'id') ++
(For an explanation of new=true, see table assignment in the wrapper section)
+utils.prompt_yes_no(prompt, default)
+Presents a yes/no prompt to the user. If default is not nil, +allows just pressing Enter to submit the default choice. +If the user enters 'abort', throws an error.
+utils.prompt_input(prompt, checkfun, quit_str)
+Presents a prompt to input data, until a valid string is entered. +Once checkfun(input) returns true, ..., passes the values +through. If the user enters the quit_str (defaults to '~~~'), +throws an error.
+utils.check_number(text)
+A prompt_input checkfun that verifies a number input.
+A third-party lua table dumper module from +http://lua-users.org/wiki/DataDumper. Defines one +function:
+dumper.DataDumper(value, varname, fastmode, ident, indent_step)
+Returns value converted to a string. The indent_step +argument specifies the indentation step size in spaces. For +the other arguments see the original documentation link above.
+DFHack plugins may export native functions and events to lua contexts. They are automatically imported by mkmodule('plugins.<name>'); this means that a lua module file is still necessary for require to read.
The following plugins have lua support.
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.
+