Merge branch 'master' of git://github.com/peterix/dfhack

develop
RossM 2012-03-30 10:06:43 -07:00
commit 703aca81d8
99 changed files with 2545 additions and 2568 deletions

@ -47,13 +47,18 @@ if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR "In-source builds are not allowed.") message(FATAL_ERROR "In-source builds are not allowed.")
endif() endif()
# make sure all the necessary submodules have been set up
if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/clsocket/CMakeLists.txt)
message(FATAL_ERROR "Required submodules could not be found! First run 'git submodule init' and 'git submodule update' from the root DFHack directory. (See the section 'Getting the Code' in Compile.html)")
endif()
# set up versioning. # set up versioning.
set(DF_VERSION_MAJOR "0") set(DF_VERSION_MAJOR "0")
set(DF_VERSION_MINOR "34") set(DF_VERSION_MINOR "34")
set(DF_VERSION_PATCH "05") set(DF_VERSION_PATCH "06")
set(DF_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}") set(DF_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}")
set(DFHACK_RELEASE "1f") set(DFHACK_RELEASE "3")
set(DFHACK_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}-r${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}-r${DFHACK_RELEASE}")
add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}") add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}")

@ -103,10 +103,93 @@ Usage
----- -----
:list-equipped [all]: List armor and weapons equipped by your companions. If all is specified, also lists non-metal clothing. :list-equipped [all]: List armor and weapons equipped by your companions. If all is specified, also lists non-metal clothing.
changelayer
===========
Changes material of the geology layer under cursor to the specified inorganic RAW material. Can have impact on all surrounding regions, not only your embark! By default changing stone to soil and vice versa is not allowed. By default changes only the layer at the cursor position. Note that one layer can stretch across lots of z levels. By default changes only the geology which is linked to the biome under the cursor. That geology might be linked to other biomes as well, though. Mineral veins and gem clusters will stay on the map. Use 'changevein' for them.
tl;dr: You will end up with changing quite big areas in one go, especially if you use it in lower z levels. Use with care.
Options
-------
:all_biomes: Change selected layer for all biomes on your map.
Result may be undesirable since the same layer can AND WILL be on different z-levels for different biomes. Use the tool 'probe' to get an idea how layers and biomes are distributed on your map.
:all_layers: Change all layers on your map (only for the selected biome unless 'all_biomes' is added).
Candy mountain, anyone? Will make your map quite boring, but tidy.
:force: Allow changing stone to soil and vice versa. !!THIS CAN HAVE WEIRD EFFECTS, USE WITH CARE!!
Note that soil will not be magically replaced with stone. You will, however, get a stone floor after digging so it will allow the floor to be engraved.
Note that stone will not be magically replaced with soil. You will, however, get a soil floor after digging so it could be helpful for creating farm plots on maps with no soil.
:verbose: Give some details about what is being changed.
:trouble: Give some advice about known problems.
Examples:
---------
``changelayer GRANITE``
Convert layer at cursor position into granite.
``changelayer SILTY_CLAY force``
Convert layer at cursor position into clay even if it's stone.
``changelayer MARBLE all_biomes all_layers``
Convert all layers of all biomes which are not soil into marble.
.. note::
* If you use changelayer and nothing happens, try to pause/unpause the game for a while and try to move the cursor to another tile. Then try again. If that doesn't help try temporarily changing some other layer, undo your changes and try again for the layer you want to change. Saving and reloading your map might also help.
* You should be fine if you only change single layers without the use of 'force'. Still it's advisable to save your game before messing with the map.
* When you force changelayer to convert soil to stone you might experience weird stuff (flashing tiles, tiles changed all over place etc). Try reverting the changes manually or even better use an older savegame. You did save your game, right?
changevein changevein
========== ==========
Changes material of the vein under cursor to the specified inorganic RAW material. Changes material of the vein under cursor to the specified inorganic RAW material.
Example:
--------
``changevein NATIVE_PLATINUM``
Convert vein at cursor position into platinum ore.
changeitem
==========
Allows changing item material and base quality. By default the item currently selected in the UI will be changed (you can select items in the 'k' list or inside containers/inventory). By default change is only allowed if materials is of the same subtype (for example wood<->wood, stone<->stone etc). But since some transformations work pretty well and may be desired you can override this with 'force'. Note that some attributes will not be touched, possibly resulting in weirdness. To get an idea how the RAW id should look like, check some items with 'info'. Using 'force' might create items which are not touched by crafters/haulers.
Options
-------
:info: Don't change anything, print some info instead.
:here: Change all items at the cursor position. Requires in-game curser.
:material, m: Change material. Must be followed by valid material RAW id.
:quality, q: Change base quality. Must be followed by number (0-5).
:force: Ignore subtypes, force change to new material.
Examples:
---------
``changeitem m INORGANIC:GRANITE here``
Change material of all items under the cursor to granite.
``changeitem q 5``
Change currently selected item to masterpiece quality.
cursecheck
==========
Checks a single map tile or the whole map/world for cursed creatures (ghosts, vampires, necromancers, werebeasts, zombies).
With an active in-game cursor only the selected tile will be observed. Without a cursor the whole map will be checked.
By default cursed creatures will be only counted in case you just want to find out if you have any of them running around in your fort.
By default dead and passive creatures (ghosts who were put to rest, killed vampires, ...) are ignored.
Undead skeletons, corpses, bodyparts and the like are all thrown into the curse category "zombie".
Anonymous zombies and resurrected body parts will show as "unnamed creature".
Options
-------
:detail: Print full name, date of birth, date of curse and some status info (some vampires might use fake identities in-game, though).
:nick: Set the type of curse as nickname (does not always show up in-game, some vamps don't like nicknames).
:all: Include dead and passive cursed creatures (can result in a quite long list after having FUN with necromancers).
:verbose: Print all curse tags (if you really want to know it all).
Examples:
---------
``cursecheck detail all``
Give detailed info about all cursed creatures including deceased ones (no in-game cursor).
``cursecheck nick``
Give a nickname all living/active cursed creatures on the map(no in-game cursor).
.. note::
* If you do a full search (with the option "all") former ghosts will show up with the cursetype "unknown" because their ghostly flag is not set anymore. But if you happen to find a living/active creature with cursetype "unknown" please report that in the dfhack thread on the modding forum or per irc. This is likely to happen with mods which introduce new types of curses, for example.
follow follow
====== ======
Makes the game view follow the currently highlighted unit after you exit from current menu/cursor mode. Handy for watching dwarves running around. Deactivated by moving the view manually. Makes the game view follow the currently highlighted unit after you exit from current menu/cursor mode. Handy for watching dwarves running around. Deactivated by moving the view manually.
@ -371,7 +454,7 @@ When multiple commands are bound to the same key combination, DFHack selects the
liquids liquids
======= =======
Allows adding magma, water and obsidian to the game. It replaces the normal dfhack command line and can't be used from a hotkey. Allows adding magma, water and obsidian to the game. It replaces the normal dfhack command line and can't be used from a hotkey. Settings will be remembered as long as dfhack runs. Intended for use in combination with the command liquids-here (which can be bound to a hotkey).
For more information, refer to the command's internal help. For more information, refer to the command's internal help.
.. note:: .. note::
@ -379,14 +462,9 @@ For more information, refer to the command's internal help.
Spawning and deleting liquids can F up pathing data and Spawning and deleting liquids can F up pathing data and
temperatures (creating heat traps). You've been warned. temperatures (creating heat traps). You've been warned.
liquidsgo liquids-here
========= ============
Allows adding magma, water and obsidian to the game. It replaces the normal dfhack command line and can't be used from a hotkey. Settings will be remembered as long as dfhack runs. Intended for use in combination with the command liquidsgo-here (which can be bound to a hotkey). Run the liquid spawner with the current/last settings made in liquids (if no settings in liquids were made it paints a point of 7/7 magma by default).
For more information, refer to the command's internal help.
liquidsgo-here
==============
Run the liquid spawner with the current/last settings made in liquidsgo (if no settings in liquidsgo were made it paints a point of 7/7 magma by default).
Intended to be used as keybinding. Requires an active in-game cursor. Intended to be used as keybinding. Requires an active in-game cursor.
mode mode
@ -542,37 +620,6 @@ tubefill
======== ========
Fills all the adamantine veins again. Veins that were empty will be filled in too, but might still trigger a demon invasion (this is a known bug). Fills all the adamantine veins again. Veins that were empty will be filled in too, but might still trigger a demon invasion (this is a known bug).
cursecheck
==========
Checks a single map tile or the whole map/world for cursed creatures (ghosts, vampires, necromancers, werebeasts, zombies).
With an active in-game cursor only the selected tile will be observed. Without a cursor the whole map will be checked.
By default cursed creatures will be only counted in case you just want to find out if you have any of them running around in your fort.
By default dead and passive creatures (ghosts who were put to rest, killed vampires, ...) are ignored.
Undead skeletons, corpses, bodyparts and the like are all thrown into the curse category "zombie".
Anonymous zombies and resurrected body parts will show as "unnamed creature".
Options
-------
:detail: Print full name, date of birth, date of curse and some status info (some vampires might use fake identities in-game, though).
:nick: Set the type of curse as nickname (does not always show up in-game, some vamps don't like nicknames).
:all: Include dead and passive cursed creatures (can result in a quite long list after having FUN with necromancers).
:verbose: Print all curse tags (if you really want to know it all).
Examples:
---------
Check one single map tile if one of the creatures on it is cursed (in-game cursor required):
* cursecheck
Count all active cursed creatures who roam around on your map (no in-game cursor) without giving more details:
* cursecheck
Give detailed info about all cursed creatures including deceased ones (no in-game cursor):
* cursecheck detail all
Give a nickname all living/active cursed creatures on the map(no in-game cursor):
* cursecheck nick
.. note::
* If you do a full search (with the option "all") former ghosts will show up with the cursetype "unknown" because their ghostly flag is not set anymore. But if you happen to find a living/active creature with cursetype "unknown" please report that in the dfhack thread on the modding forum or per irc. This is likely to happen with mods which introduce new types of curses, for example.
vdig vdig
==== ====
Designates a whole vein for digging. Requires an active in-game cursor placed over a vein tile. With the 'x' option, it will traverse z-levels (putting stairs between the same-material tiles). Designates a whole vein for digging. Requires an active in-game cursor placed over a vein tile. With the 'x' option, it will traverse z-levels (putting stairs between the same-material tiles).

File diff suppressed because it is too large Load Diff

@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2010 mkdir VC2010
cd VC2010 cd VC2010
echo generating a build folder echo generating a build folder
cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX=%_DF_PATH% -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1

@ -3,5 +3,5 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2010 mkdir VC2010
cd VC2010 cd VC2010
echo Pre-generating a build folder echo Pre-generating a build folder
cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX=%_DF_PATH% cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%"
cmake-gui . cmake-gui .

@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2010 mkdir VC2010
cd VC2010 cd VC2010
echo generating a build folder echo generating a build folder
cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX=%_DF_PATH% -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0

@ -76,6 +76,7 @@ src/ltm.c
src/lundump.c src/lundump.c
src/lvm.c src/lvm.c
src/lzio.c src/lzio.c
src/bit.c
) )
# compile with C++ compiler # compile with C++ compiler
set_source_files_properties(${SRC_LIBLUA} PROPERTIES LANGUAGE CXX) set_source_files_properties(${SRC_LIBLUA} PROPERTIES LANGUAGE CXX)

@ -152,7 +152,7 @@
** LUA_BUILD_AS_DLL to get it). ** LUA_BUILD_AS_DLL to get it).
*/ */
#ifdef __cplusplus #ifdef __cplusplus
#define LUA_API_EXTERN extern "C" #define LUA_API_EXTERN extern
#else #else
#define LUA_API_EXTERN extern #define LUA_API_EXTERN extern
#endif #endif

@ -236,10 +236,17 @@ static int luaB_next (lua_State *L) {
static int luaB_pairs (lua_State *L) { static int luaB_pairs (lua_State *L) {
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__pairs")) {
lua_pushvalue(L, 1);
lua_call(L, 1, 3);
}
else {
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
lua_pushvalue(L, 1); /* state, */ lua_pushvalue(L, 1); /* state, */
lua_pushnil(L); /* and initial value */ lua_pushnil(L); /* and initial value */
}
return 3; return 3;
} }
@ -255,10 +262,17 @@ static int ipairsaux (lua_State *L) {
static int luaB_ipairs (lua_State *L) { static int luaB_ipairs (lua_State *L) {
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__ipairs")) {
lua_pushvalue(L, 1);
lua_call(L, 1, 3);
}
else {
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
lua_pushvalue(L, 1); /* state, */ lua_pushvalue(L, 1); /* state, */
lua_pushinteger(L, 0); /* and initial value */ lua_pushinteger(L, 0); /* and initial value */
}
return 3; return 3;
} }

@ -12,7 +12,7 @@
#include "lualib.h" #include "lualib.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "bit.h"
static const luaL_Reg lualibs[] = { static const luaL_Reg lualibs[] = {
{"", luaopen_base}, {"", luaopen_base},
@ -23,6 +23,7 @@ static const luaL_Reg lualibs[] = {
{LUA_STRLIBNAME, luaopen_string}, {LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math}, {LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug}, {LUA_DBLIBNAME, luaopen_debug},
{"bit",luaopen_bit},
{NULL, NULL} {NULL, NULL}
}; };

@ -189,14 +189,14 @@ FILE(GLOB GENERATE_INPUT_SCRIPTS ${dfapi_SOURCE_DIR}/xml/*.pm ${dfapi_SOURCE_DIR
FILE(GLOB GENERATE_INPUT_XMLS ${dfapi_SOURCE_DIR}/xml/*.xml) FILE(GLOB GENERATE_INPUT_XMLS ${dfapi_SOURCE_DIR}/xml/*.xml)
ADD_CUSTOM_COMMAND( ADD_CUSTOM_COMMAND(
OUTPUT ${dfapi_SOURCE_DIR}/include/df/static.inc OUTPUT ${dfapi_SOURCE_DIR}/include/df/codegen.out.xml
COMMAND ${PERL_EXECUTABLE} xml/codegen.pl xml include/df COMMAND ${PERL_EXECUTABLE} xml/codegen.pl xml include/df
WORKING_DIRECTORY ${dfapi_SOURCE_DIR} WORKING_DIRECTORY ${dfapi_SOURCE_DIR}
MAIN_DEPENDENCY ${dfapi_SOURCE_DIR}/xml/codegen.pl MAIN_DEPENDENCY ${dfapi_SOURCE_DIR}/xml/codegen.pl
DEPENDS ${GENERATE_INPUT_XMLS} ${GENERATE_INPUT_SCRIPTS} DEPENDS ${GENERATE_INPUT_XMLS} ${GENERATE_INPUT_SCRIPTS}
) )
ADD_CUSTOM_TARGET(generate_headers DEPENDS ${dfapi_SOURCE_DIR}/include/df/static.inc) ADD_CUSTOM_TARGET(generate_headers DEPENDS ${dfapi_SOURCE_DIR}/include/df/codegen.out.xml)
IF(UNIX) IF(UNIX)
# Don't produce debug info for generated stubs # Don't produce debug info for generated stubs

@ -179,7 +179,7 @@ namespace DFHack
void color(int index) void color(int index)
{ {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, index); SetConsoleTextAttribute(hConsole, index == color_ostream::COLOR_RESET ? default_attributes : index);
} }
void reset_color( void ) void reset_color( void )

@ -70,7 +70,7 @@ using df::global::init;
// FIXME: A lot of code in one file, all doing different things... there's something fishy about it. // FIXME: A lot of code in one file, all doing different things... there's something fishy about it.
static void loadScriptFile(Core *core, PluginManager *plug_mgr, string fname); static void loadScriptFile(Core *core, PluginManager *plug_mgr, string fname, bool silent);
static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clueless_counter, const string &command); static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clueless_counter, const string &command);
static bool parseKeySpec(std::string keyspec, int *psym, int *pmod); static bool parseKeySpec(std::string keyspec, int *psym, int *pmod);
@ -492,7 +492,7 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
{ {
if(parts.size() == 1) if(parts.size() == 1)
{ {
loadScriptFile(core, plug_mgr, parts[0]); loadScriptFile(core, plug_mgr, parts[0], false);
} }
else else
{ {
@ -512,8 +512,9 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
} }
} }
static void loadScriptFile(Core *core, PluginManager *plug_mgr, string fname) static void loadScriptFile(Core *core, PluginManager *plug_mgr, string fname, bool silent)
{ {
if(!silent)
core->getConsole() << "Loading script at " << fname << std::endl; core->getConsole() << "Loading script at " << fname << std::endl;
ifstream script(fname); ifstream script(fname);
if (script.good()) if (script.good())
@ -528,6 +529,7 @@ static void loadScriptFile(Core *core, PluginManager *plug_mgr, string fname)
} }
else else
{ {
if(!silent)
core->getConsole().printerr("Error loading script\n"); core->getConsole().printerr("Error loading script\n");
} }
@ -551,7 +553,7 @@ void fIOthread(void * iodata)
return; return;
} }
loadScriptFile(core, plug_mgr, "dfhack.init"); loadScriptFile(core, plug_mgr, "dfhack.init", true);
con.print("DFHack is ready. Have a nice day!\n" con.print("DFHack is ready. Have a nice day!\n"
"Type in '?' or 'help' for general help, 'ls' to see all commands.\n"); "Type in '?' or 'help' for general help, 'ls' to see all commands.\n");
@ -972,6 +974,7 @@ int Core::UnicodeAwareSym(const SDL::KeyboardEvent& ke)
{ {
// Assume keyboard layouts don't change the order of numbers: // Assume keyboard layouts don't change the order of numbers:
if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym; if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym;
if(SDL::K_F1 <= ke.ksym.sym && ke.ksym.sym <= SDL::K_F12) return ke.ksym.sym;
int unicode = ke.ksym.unicode; int unicode = ke.ksym.unicode;

@ -51,6 +51,11 @@ void type_identity::do_copy_pod(void *tgt, const void *src) {
memmove(tgt, src, size); memmove(tgt, src, size);
}; };
bool type_identity::do_destroy_pod(void *obj) {
free(obj);
return true;
}
void *type_identity::allocate() { void *type_identity::allocate() {
if (can_allocate()) if (can_allocate())
return do_allocate(); return do_allocate();
@ -60,7 +65,17 @@ void *type_identity::allocate() {
bool type_identity::copy(void *tgt, const void *src) { bool type_identity::copy(void *tgt, const void *src) {
if (can_allocate() && tgt && src) if (can_allocate() && tgt && src)
{
do_copy(tgt, src); do_copy(tgt, src);
return true;
}
else
return false;
}
bool type_identity::destroy(void *obj) {
if (can_allocate() && obj)
return do_destroy(obj);
else else
return false; return false;
} }
@ -137,10 +152,11 @@ enum_identity::enum_identity(size_t size,
compound_identity *scope_parent, const char *dfhack_name, compound_identity *scope_parent, const char *dfhack_name,
type_identity *base_type, type_identity *base_type,
int64_t first_item_value, int64_t last_item_value, int64_t first_item_value, int64_t last_item_value,
const char *const *keys) const char *const *keys,
const void *attrs, struct_identity *attr_type)
: compound_identity(size, NULL, scope_parent, dfhack_name), : compound_identity(size, NULL, scope_parent, dfhack_name),
first_item_value(first_item_value), last_item_value(last_item_value), first_item_value(first_item_value), last_item_value(last_item_value),
keys(keys), base_type(base_type) keys(keys), base_type(base_type), attrs(attrs), attr_type(attr_type)
{ {
} }

@ -8,6 +8,7 @@
#include "df/ui.h" #include "df/ui.h"
#include "DataIdentity.h" #include "DataIdentity.h"
#include "DataFuncs.h"
#include <stddef.h> #include <stddef.h>
@ -30,9 +31,12 @@ namespace df {
bool_identity identity_traits<bool>::identity; bool_identity identity_traits<bool>::identity;
stl_string_identity identity_traits<std::string>::identity; stl_string_identity identity_traits<std::string>::identity;
ptr_string_identity identity_traits<char*>::identity;
ptr_string_identity identity_traits<const char*>::identity;
pointer_identity identity_traits<void*>::identity; pointer_identity identity_traits<void*>::identity;
stl_ptr_vector_identity identity_traits<std::vector<void*> >::identity; stl_ptr_vector_identity identity_traits<std::vector<void*> >::identity;
stl_bit_vector_identity identity_traits<std::vector<bool> >::identity; stl_bit_vector_identity identity_traits<std::vector<bool> >::identity;
bit_array_identity identity_traits<BitArray<int> >::identity;
buffer_container_identity buffer_container_identity::base_instance; buffer_container_identity buffer_container_identity::base_instance;
@ -43,6 +47,7 @@ namespace df {
#define FLD(mode, name) struct_field_info::mode, #name, offsetof(CUR_STRUCT, name) #define FLD(mode, name) struct_field_info::mode, #name, offsetof(CUR_STRUCT, name)
#define GFLD(mode, name) struct_field_info::mode, #name, (size_t)&df::global::name #define GFLD(mode, name) struct_field_info::mode, #name, (size_t)&df::global::name
#define METHOD(mode, name) struct_field_info::mode, #name, 0, wrap_function(&CUR_STRUCT::name)
#define FLD_END struct_field_info::END #define FLD_END struct_field_info::END
// Field definitions // Field definitions

@ -1,4 +1,4 @@
/* /*
https://github.com/peterix/dfhack https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
@ -36,6 +36,7 @@ distribution.
#include "DataDefs.h" #include "DataDefs.h"
#include "DataIdentity.h" #include "DataIdentity.h"
#include "LuaWrapper.h" #include "LuaWrapper.h"
#include "DataFuncs.h"
#include "MiscUtils.h" #include "MiscUtils.h"
@ -49,13 +50,36 @@ using namespace DFHack::LuaWrapper;
* Identity object read/write methods * * Identity object read/write methods *
**************************************/ **************************************/
void function_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr)
{
field_error(state, fname_idx, "executable code", "read");
}
void function_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
field_error(state, fname_idx, "executable code", "write");
}
void constructed_identity::lua_read(lua_State *state, int fname_idx, void *ptr) void constructed_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
{ {
push_object_internal(state, this, ptr); push_object_internal(state, this, ptr);
} }
static void invoke_assign(lua_State *state, type_identity *id, void *ptr, int val_index)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
push_object_internal(state, id, ptr);
lua_pushvalue(state, val_index);
lua_call(state, 2, 0);
}
void constructed_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) void constructed_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{ {
if (lua_istable(state, val_index))
{
invoke_assign(state, this, ptr, val_index);
}
else
field_error(state, fname_idx, "complex object", "write"); field_error(state, fname_idx, "complex object", "write");
} }
@ -99,6 +123,20 @@ void df::bool_identity::lua_write(lua_State *state, int fname_idx, void *ptr, in
field_error(state, fname_idx, "boolean or number expected", "write"); field_error(state, fname_idx, "boolean or number expected", "write");
} }
void df::ptr_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
{
auto pstr = (char**)ptr;
if (*pstr)
lua_pushstring(state, *pstr);
else
lua_pushnil(state);
}
void df::ptr_string_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
field_error(state, fname_idx, "raw pointer string", "write");
}
void df::stl_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr) void df::stl_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
{ {
auto pstr = (std::string*)ptr; auto pstr = (std::string*)ptr;
@ -125,13 +163,79 @@ void df::pointer_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
lua_read(state, fname_idx, ptr, target); lua_read(state, fname_idx, ptr, target);
} }
static void autovivify_ptr(lua_State *state, int fname_idx, void **pptr,
type_identity *target, int val_index)
{
lua_getfield(state, val_index, "new");
// false or nil => bail out
if (!lua_toboolean(state, -1))
field_error(state, fname_idx, "null and autovivify not requested", "write");
// not 'true' => call df.new()
if (!lua_isboolean(state, -1))
{
int top = lua_gettop(state);
// Verify new points to a reasonable type of object
type_identity *suggested = get_object_identity(state, top, "autovivify", true, true);
if (!is_type_compatible(state, target, 0, suggested, top+1, false))
field_error(state, fname_idx, "incompatible suggested autovivify type", "write");
lua_pop(state, 1);
// Invoke df.new()
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME);
lua_swap(state);
lua_call(state, 1, 1);
// Retrieve the pointer
void *nval = get_object_internal(state, target, top, false);
// shouldn't happen: this means suggested type is compatible,
// but its new() result isn't for some reason.
if (!nval)
field_error(state, fname_idx, "inconsistent autovivify type", "write");
*pptr = nval;
}
// otherwise use the target type
else
{
if (!target)
field_error(state, fname_idx, "trying to autovivify void*", "write");
*pptr = target->allocate();
if (!*pptr)
field_error(state, fname_idx, "could not allocate in autovivify", "write");
}
lua_pop(state, 1);
}
static bool is_null(lua_State *state, int val_index)
{
return lua_isnil(state, val_index) ||
(lua_islightuserdata(state, val_index) &&
!lua_touserdata(state, val_index));
}
void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr, void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr,
type_identity *target, int val_index) type_identity *target, int val_index)
{ {
auto pptr = (void**)ptr; auto pptr = (void**)ptr;
if (lua_isnil(state, val_index)) if (is_null(state, val_index))
*pptr = NULL; *pptr = NULL;
else if (lua_istable(state, val_index))
{
if (!*pptr)
autovivify_ptr(state, fname_idx, pptr, target, val_index);
invoke_assign(state, target, *pptr, val_index);
}
else else
{ {
void *nval = get_object_internal(state, target, val_index, false); void *nval = get_object_internal(state, target, val_index, false);
@ -264,15 +368,71 @@ static void lookup_field(lua_State *state, int index, const char *mode)
field_error(state, index, "not found", mode); field_error(state, index, "not found", mode);
} }
// Resolve the field in the metatable and return
static int get_metafield(lua_State *state)
{
lua_rawget(state, UPVAL_METATABLE);
return 1;
}
static void *find_field(lua_State *state, int index, const char *mode) static void *find_field(lua_State *state, int index, const char *mode)
{ {
lookup_field(state, index, mode); lookup_field(state, index, mode);
// Methods
if (lua_isfunction(state, -1))
return NULL;
// Otherwise must be a pointer
if (!lua_isuserdata(state, -1))
field_error(state, index, "corrupted field table", mode);
void *p = lua_touserdata(state, -1); void *p = lua_touserdata(state, -1);
lua_pop(state, 1); lua_pop(state, 1);
// NULL => metafield
if (!p)
get_metafield(state);
return p; return p;
} }
static int cur_iter_index(lua_State *state, int len, int fidx, int first_idx = -1)
{
int rv;
if (lua_isnil(state, fidx))
rv = first_idx;
else
{
if (lua_isnumber(state, fidx))
rv = lua_tointeger(state, fidx);
else
{
lua_pushvalue(state, fidx);
lua_rawget(state, UPVAL_FIELDTABLE);
if (!lua_isnumber(state, -1))
field_error(state, fidx, "index not found", "iterate");
rv = lua_tointeger(state, -1);
lua_pop(state, 1);
}
if (rv < 0 || rv >= len)
field_error(state, fidx, "index out of bounds", "iterate");
}
return rv;
}
static void iter_idx_to_name(lua_State *state, int idx)
{
lua_pushvalue(state, idx);
lua_rawget(state, UPVAL_FIELDTABLE);
if (lua_isnil(state, -1))
lua_pop(state, 1);
else
lua_replace(state, idx);
}
static uint8_t *check_method_call(lua_State *state, int min_args, int max_args) static uint8_t *check_method_call(lua_State *state, int min_args, int max_args)
{ {
int argc = lua_gettop(state)-1; int argc = lua_gettop(state)-1;
@ -295,6 +455,10 @@ static void read_field(lua_State *state, const struct_field_info *field, void *p
return; return;
} }
case struct_field_info::OBJ_METHOD:
case struct_field_info::CLASS_METHOD:
// error
case struct_field_info::PRIMITIVE: case struct_field_info::PRIMITIVE:
case struct_field_info::SUBSTRUCT: case struct_field_info::SUBSTRUCT:
field->type->lua_read(state, 2, ptr); field->type->lua_read(state, 2, ptr);
@ -339,6 +503,10 @@ static void field_reference(lua_State *state, const struct_field_info *field, vo
push_adhoc_pointer(state, ptr, field->type); push_adhoc_pointer(state, ptr, field->type);
return; return;
case struct_field_info::OBJ_METHOD:
case struct_field_info::CLASS_METHOD:
// error
case struct_field_info::CONTAINER: case struct_field_info::CONTAINER:
read_field(state, field, ptr); read_field(state, field, ptr);
return; return;
@ -371,6 +539,10 @@ static void write_field(lua_State *state, const struct_field_info *field, void *
return; return;
} }
case struct_field_info::OBJ_METHOD:
case struct_field_info::CLASS_METHOD:
// error
case struct_field_info::PRIMITIVE: case struct_field_info::PRIMITIVE:
case struct_field_info::SUBSTRUCT: case struct_field_info::SUBSTRUCT:
case struct_field_info::CONTAINER: case struct_field_info::CONTAINER:
@ -379,10 +551,15 @@ static void write_field(lua_State *state, const struct_field_info *field, void *
case struct_field_info::POINTER: case struct_field_info::POINTER:
df::pointer_identity::lua_write(state, 2, ptr, field->type, value_idx); df::pointer_identity::lua_write(state, 2, ptr, field->type, value_idx);
return;
case struct_field_info::STATIC_ARRAY: case struct_field_info::STATIC_ARRAY:
case struct_field_info::STL_VECTOR_PTR: case struct_field_info::STL_VECTOR_PTR:
field_error(state, 2, "complex object", "write"); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
read_field(state, field, ptr);
lua_pushvalue(state, value_idx);
lua_call(state, 2, 0);
return;
case struct_field_info::END: case struct_field_info::END:
return; return;
@ -418,13 +595,6 @@ static int meta_ptr_tostring(lua_State *state)
return 1; return 1;
} }
// Resolve the field in the metatable and return
static int get_metafield(lua_State *state)
{
lua_rawget(state, UPVAL_METATABLE);
return 1;
}
/** /**
* Metamethod: __index for structures. * Metamethod: __index for structures.
*/ */
@ -433,7 +603,7 @@ static int meta_struct_index(lua_State *state)
uint8_t *ptr = get_object_addr(state, 1, 2, "read"); uint8_t *ptr = get_object_addr(state, 1, 2, "read");
auto field = (struct_field_info*)find_field(state, 2, "read"); auto field = (struct_field_info*)find_field(state, 2, "read");
if (!field) if (!field)
return get_metafield(state); return 1;
read_field(state, field, ptr + field->offset); read_field(state, field, ptr + field->offset);
return 1; return 1;
} }
@ -448,7 +618,7 @@ static int meta_struct_field_reference(lua_State *state)
uint8_t *ptr = get_object_addr(state, 1, 2, "reference"); uint8_t *ptr = get_object_addr(state, 1, 2, "reference");
auto field = (struct_field_info*)find_field(state, 2, "reference"); auto field = (struct_field_info*)find_field(state, 2, "reference");
if (!field) if (!field)
field_error(state, 2, "builtin property", "reference"); field_error(state, 2, "builtin property or method", "reference");
field_reference(state, field, ptr + field->offset); field_reference(state, field, ptr + field->offset);
return 1; return 1;
} }
@ -461,11 +631,29 @@ static int meta_struct_newindex(lua_State *state)
uint8_t *ptr = get_object_addr(state, 1, 2, "write"); uint8_t *ptr = get_object_addr(state, 1, 2, "write");
auto field = (struct_field_info*)find_field(state, 2, "write"); auto field = (struct_field_info*)find_field(state, 2, "write");
if (!field) if (!field)
field_error(state, 2, "builtin property", "write"); field_error(state, 2, "builtin property or method", "write");
write_field(state, field, ptr + field->offset, 3); write_field(state, field, ptr + field->offset, 3);
return 0; return 0;
} }
/**
* Metamethod: iterator for structures.
*/
static int meta_struct_next(lua_State *state)
{
if (lua_gettop(state) < 2) lua_pushnil(state);
int len = lua_objlen(state, UPVAL_FIELDTABLE);
int idx = cur_iter_index(state, len+1, 2, 0);
if (idx == len)
return 0;
lua_rawgeti(state, UPVAL_FIELDTABLE, idx+1);
lua_dup(state);
lua_gettable(state, 1);
return 2;
}
/** /**
* Metamethod: __index for primitives, i.e. simple object references. * Metamethod: __index for primitives, i.e. simple object references.
* Fields point to identity, or NULL for metafields. * Fields point to identity, or NULL for metafields.
@ -475,7 +663,7 @@ static int meta_primitive_index(lua_State *state)
uint8_t *ptr = get_object_addr(state, 1, 2, "read"); uint8_t *ptr = get_object_addr(state, 1, 2, "read");
auto type = (type_identity*)find_field(state, 2, "read"); auto type = (type_identity*)find_field(state, 2, "read");
if (!type) if (!type)
return get_metafield(state); return 1;
type->lua_read(state, 2, ptr); type->lua_read(state, 2, ptr);
return 1; return 1;
} }
@ -488,7 +676,7 @@ static int meta_primitive_newindex(lua_State *state)
uint8_t *ptr = get_object_addr(state, 1, 2, "write"); uint8_t *ptr = get_object_addr(state, 1, 2, "write");
auto type = (type_identity*)find_field(state, 2, "write"); auto type = (type_identity*)find_field(state, 2, "write");
if (!type) if (!type)
field_error(state, 2, "builtin property", "write"); field_error(state, 2, "builtin property or method", "write");
type->lua_write(state, 2, ptr, 3); type->lua_write(state, 2, ptr, 3);
return 0; return 0;
} }
@ -521,7 +709,7 @@ static int lookup_container_field(lua_State *state, int field, const char *mode
if (lua_isuserdata(state, -1) && !lua_touserdata(state, -1)) if (lua_isuserdata(state, -1) && !lua_touserdata(state, -1))
{ {
if (mode) if (mode)
field_error(state, field, "builtin property", mode); field_error(state, field, "builtin property or method", mode);
lua_pop(state, 1); lua_pop(state, 1);
get_metafield(state); get_metafield(state);
@ -596,6 +784,39 @@ static int meta_container_newindex(lua_State *state)
return 0; return 0;
} }
/**
* Metamethod: integer iterator for containers.
*/
static int meta_container_nexti(lua_State *state)
{
if (lua_gettop(state) < 2) lua_pushnil(state);
uint8_t *ptr = get_object_addr(state, 1, 2, "iterate");
auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
int len = id->lua_item_count(state, ptr, container_identity::COUNT_LEN);
int idx = cur_iter_index(state, len, 2);
if (++idx >= len)
return 0;
lua_pushinteger(state, idx);
id->lua_item_read(state, 2, ptr, idx);
return 2;
}
/**
* Metamethod: name iterator for containers.
*/
static int meta_container_next(lua_State *state)
{
if (!meta_container_nexti(state))
return 0;
iter_idx_to_name(state, lua_gettop(state)-1);
return 2;
}
/** /**
* Method: resize container * Method: resize container
*/ */
@ -655,6 +876,17 @@ static int meta_bitfield_len(lua_State *state)
return 1; return 1;
} }
static void read_bitfield(lua_State *state, uint8_t *ptr, bitfield_identity *id, int idx)
{
int size = id->getBits()[idx].size;
int value = getBitfieldField(ptr, idx, size);
if (size <= 1)
lua_pushboolean(state, value != 0);
else
lua_pushinteger(state, value);
}
/** /**
* Metamethod: __index for bitfields. * Metamethod: __index for bitfields.
*/ */
@ -677,13 +909,7 @@ static int meta_bitfield_index(lua_State *state)
} }
int idx = check_container_index(state, id->getNumBits(), 2, iidx, "read"); int idx = check_container_index(state, id->getNumBits(), 2, iidx, "read");
int size = id->getBits()[idx].size; read_bitfield(state, ptr, id, idx);
int value = getBitfieldField(ptr, idx, size);
if (size <= 1)
lua_pushboolean(state, value != 0);
else
lua_pushinteger(state, value);
return 1; return 1;
} }
@ -720,6 +946,44 @@ static int meta_bitfield_newindex(lua_State *state)
return 0; return 0;
} }
/**
* Metamethod: integer iterator for bitfields.
*/
static int meta_bitfield_nexti(lua_State *state)
{
if (lua_gettop(state) < 2) lua_pushnil(state);
uint8_t *ptr = get_object_addr(state, 1, 2, "iterate");
auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
int len = id->getNumBits();
int idx = cur_iter_index(state, len, 2);
if (idx < 0)
idx = 0;
else
idx += std::max(1, (int)id->getBits()[idx].size);
if (idx >= len)
return 0;
lua_pushinteger(state, idx);
read_bitfield(state, ptr, id, idx);
return 2;
}
/**
* Metamethod: name iterator for bitfields.
*/
static int meta_bitfield_next(lua_State *state)
{
if (!meta_bitfield_nexti(state))
return 0;
iter_idx_to_name(state, lua_gettop(state)-1);
return 2;
}
/** /**
* Metamethod: __index for df.global * Metamethod: __index for df.global
*/ */
@ -727,7 +991,7 @@ static int meta_global_index(lua_State *state)
{ {
auto field = (struct_field_info*)find_field(state, 2, "read"); auto field = (struct_field_info*)find_field(state, 2, "read");
if (!field) if (!field)
return get_metafield(state); return 1;
void *ptr = *(void**)field->offset; void *ptr = *(void**)field->offset;
if (!ptr) if (!ptr)
field_error(state, 2, "global address not known", "read"); field_error(state, 2, "global address not known", "read");
@ -742,7 +1006,7 @@ static int meta_global_newindex(lua_State *state)
{ {
auto field = (struct_field_info*)find_field(state, 2, "write"); auto field = (struct_field_info*)find_field(state, 2, "write");
if (!field) if (!field)
field_error(state, 2, "builtin property", "write"); field_error(state, 2, "builtin property or method", "write");
void *ptr = *(void**)field->offset; void *ptr = *(void**)field->offset;
if (!ptr) if (!ptr)
field_error(state, 2, "global address not known", "write"); field_error(state, 2, "global address not known", "write");
@ -750,27 +1014,99 @@ static int meta_global_newindex(lua_State *state)
return 0; return 0;
} }
/**
* Wrapper for c++ methods and functions.
*/
static int meta_call_function(lua_State *state)
{
auto id = (function_identity_base*)lua_touserdata(state, UPVAL_CONTAINER_ID);
if (lua_gettop(state) != id->getNumArgs())
field_error(state, UPVAL_METHOD_NAME, "invalid argument count", "invoke");
id->invoke(state, 1);
return 1;
}
/**
* Create a closure invoking the given function, and add it to the field table.
*/
static void AddMethodWrapper(lua_State *state, int meta_idx, int field_idx,
const char *name, function_identity_base *fun)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
lua_pushvalue(state, meta_idx);
lua_pushfstring(state, "%s()", name);
lua_pushlightuserdata(state, fun);
lua_pushcclosure(state, meta_call_function, 4);
lua_setfield(state, field_idx, name);
}
/** /**
* Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack. * Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack.
*/ */
static void IndexFields(lua_State *state, struct_identity *pstruct) static void IndexFields(lua_State *state, int base, struct_identity *pstruct)
{ {
// stack: fieldtable if (pstruct->getParent())
IndexFields(state, base, pstruct->getParent());
int base = lua_gettop(state); auto fields = pstruct->getFields();
if (!fields)
return;
int cnt = lua_objlen(state, base+3); // field iter table
for (int i = 0; fields[i].mode != struct_field_info::END; ++i)
{
// Qualify conflicting field names with the type
std::string name = fields[i].name;
lua_getfield(state, base+2, name.c_str());
if (!lua_isnil(state, -1))
name = pstruct->getName() + ("." + name);
lua_pop(state, 1);
// Handle the field
switch (fields[i].mode)
{
case struct_field_info::OBJ_METHOD:
AddMethodWrapper(state, base+1, base+2, name.c_str(),
(function_identity_base*)fields[i].type);
break;
case struct_field_info::CLASS_METHOD:
break;
default:
AssociateId(state, base+3, ++cnt, name.c_str());
lua_pushlightuserdata(state, (void*)&fields[i]);
lua_setfield(state, base+2, name.c_str());
break;
}
}
}
void LuaWrapper::IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct)
{
// stack: metatable fieldtable
for (struct_identity *p = pstruct; p; p = p->getParent()) for (struct_identity *p = pstruct; p; p = p->getParent())
{ {
auto fields = p->getFields(); auto fields = p->getFields();
if (!fields)
continue;
for (; fields; ++fields) for (int i = 0; fields[i].mode != struct_field_info::END; ++i)
{ {
if (fields->mode == struct_field_info::END) switch (fields[i].mode)
{
case struct_field_info::CLASS_METHOD:
AddMethodWrapper(state, meta_idx, ftable_idx, fields[i].name,
(function_identity_base*)fields[i].type);
break; break;
lua_pushstring(state,fields->name); default:
lua_pushlightuserdata(state,(void*)fields); break;
lua_rawset(state,base); }
} }
} }
} }
@ -785,8 +1121,20 @@ static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
MakeMetatable(state, pstruct, "struct"); // meta, fields MakeMetatable(state, pstruct, "struct"); // meta, fields
IndexFields(state, pstruct); // Index the fields
lua_newtable(state);
IndexFields(state, base, pstruct);
// Add the iteration metamethods
PushStructMethod(state, base+1, base+3, meta_struct_next);
SetPairsMethod(state, base+1, "__pairs");
lua_pushnil(state);
SetPairsMethod(state, base+1, "__ipairs");
lua_setfield(state, base+1, "_index_table");
// Add the indexing metamethods
SetStructMethod(state, base+1, base+2, reader, "__index"); SetStructMethod(state, base+1, base+2, reader, "__index");
SetStructMethod(state, base+1, base+2, writer, "__newindex"); SetStructMethod(state, base+1, base+2, writer, "__newindex");
@ -804,8 +1152,21 @@ static void MakePrimitiveMetatable(lua_State *state, type_identity *type)
SetPtrMethods(state, base+1, base+2); SetPtrMethods(state, base+1, base+2);
// Index the fields
lua_newtable(state);
EnableMetaField(state, base+2, "value", type); EnableMetaField(state, base+2, "value", type);
AssociateId(state, base+3, 1, "value");
// Add the iteration metamethods
PushStructMethod(state, base+1, base+3, meta_struct_next);
SetPairsMethod(state, base+1, "__pairs");
lua_pushnil(state);
SetPairsMethod(state, base+1, "__ipairs");
lua_setfield(state, base+1, "_index_table");
// Add the indexing metamethods
SetStructMethod(state, base+1, base+2, meta_primitive_index, "__index"); SetStructMethod(state, base+1, base+2, meta_primitive_index, "__index");
SetStructMethod(state, base+1, base+2, meta_primitive_newindex, "__newindex"); SetStructMethod(state, base+1, base+2, meta_primitive_newindex, "__newindex");
} }
@ -857,7 +1218,15 @@ static void MakeContainerMetatable(lua_State *state, container_identity *type,
AddContainerMethodFun(state, base+1, base+2, method_container_erase, "erase", type, item, count); AddContainerMethodFun(state, base+1, base+2, method_container_erase, "erase", type, item, count);
AddContainerMethodFun(state, base+1, base+2, method_container_insert, "insert", type, item, count); AddContainerMethodFun(state, base+1, base+2, method_container_insert, "insert", type, item, count);
// push the index table
AttachEnumKeys(state, base+1, base+2, ienum); AttachEnumKeys(state, base+1, base+2, ienum);
PushContainerMethod(state, base+1, base+3, meta_container_next, type, item, count);
SetPairsMethod(state, base+1, "__pairs");
PushContainerMethod(state, base+1, base+3, meta_container_nexti, type, item, count);
SetPairsMethod(state, base+1, "__ipairs");
lua_pop(state, 1);
} }
/* /*
@ -887,6 +1256,13 @@ void bitfield_identity::build_metatable(lua_State *state)
AttachEnumKeys(state, base+1, base+2, this); AttachEnumKeys(state, base+1, base+2, this);
PushContainerMethod(state, base+1, base+3, meta_bitfield_next, this, NULL, -1);
SetPairsMethod(state, base+1, "__pairs");
PushContainerMethod(state, base+1, base+3, meta_bitfield_nexti, this, NULL, -1);
SetPairsMethod(state, base+1, "__ipairs");
lua_pop(state, 1);
EnableMetaField(state, base+2, "whole", this); EnableMetaField(state, base+2, "whole", this);
} }

@ -1,4 +1,4 @@
/* /*
https://github.com/peterix/dfhack https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
@ -255,7 +255,7 @@ static void fetch_container_details(lua_State *state, int meta, type_identity **
/** /**
* Check if type1 and type2 are compatible, possibly using additional metatable data. * Check if type1 and type2 are compatible, possibly using additional metatable data.
*/ */
static bool is_type_compatible(lua_State *state, type_identity *type1, int meta1, bool LuaWrapper::is_type_compatible(lua_State *state, type_identity *type1, int meta1,
type_identity *type2, int meta2, bool exact_equal) type_identity *type2, int meta2, bool exact_equal)
{ {
if (type1 == type2) if (type1 == type2)
@ -417,9 +417,9 @@ static bool is_valid_metatable(lua_State *state, int objidx, int metaidx)
/** /**
* Given a DF object reference or type, safely retrieve its identity pointer. * Given a DF object reference or type, safely retrieve its identity pointer.
*/ */
static type_identity *get_object_identity(lua_State *state, int objidx, type_identity *LuaWrapper::get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type = false, const char *ctx, bool allow_type,
bool keep_metatable = false) bool keep_metatable)
{ {
if (!lua_getmetatable(state, objidx)) if (!lua_getmetatable(state, objidx))
luaL_error(state, "Invalid object in %s", ctx); luaL_error(state, "Invalid object in %s", ctx);
@ -496,14 +496,7 @@ static int meta_sizeof(lua_State *state)
luaL_error(state, "Usage: object:sizeof() or df.sizeof(object)"); luaL_error(state, "Usage: object:sizeof() or df.sizeof(object)");
// Two special cases: nil and lightuserdata for NULL and void* // Two special cases: nil and lightuserdata for NULL and void*
if (lua_isnil(state, 1)) if (lua_isnil(state, 1) || lua_islightuserdata(state, 1))
{
lua_pushnil(state);
lua_pushinteger(state, 0);
return 2;
}
if (lua_islightuserdata(state, 1))
{ {
lua_pushnil(state); lua_pushnil(state);
lua_pushnumber(state, (size_t)lua_touserdata(state, 1)); lua_pushnumber(state, (size_t)lua_touserdata(state, 1));
@ -593,10 +586,7 @@ static int meta_new(lua_State *state)
void *ptr = id->allocate(); void *ptr = id->allocate();
if (!ptr) if (!ptr)
{ luaL_error(state, "Cannot allocate %s", id->getFullName().c_str());
lua_pushnil(state);
return 1;
}
if (lua_isuserdata(state, 1)) if (lua_isuserdata(state, 1))
{ {
@ -611,6 +601,43 @@ static int meta_new(lua_State *state)
return 1; return 1;
} }
static void invoke_resize(lua_State *state, int table, lua_Integer size)
{
lua_getfield(state, table, "resize");
lua_pushvalue(state, table);
lua_pushinteger(state, size);
lua_call(state, 2, 0);
}
static void copy_table(lua_State *state, int dest, int src, int skipbase)
{
// stack: (skipbase) skipkey skipkey |
int top = lua_gettop(state);
lua_pushnil(state);
while (lua_next(state, src))
{
for (int i = skipbase+1; i <= top; i++)
{
if (lua_rawequal(state, -2, i))
{
lua_pop(state, 1);
goto next_outer;
}
}
{
lua_pushvalue(state, -2);
lua_swap(state);
lua_settable(state, dest);
}
next_outer:;
}
}
/** /**
* Method: assign data between objects. * Method: assign data between objects.
*/ */
@ -621,15 +648,133 @@ static int meta_assign(lua_State *state)
if (argc != 2) if (argc != 2)
luaL_error(state, "Usage: target:assign(src) or df.assign(target,src)"); luaL_error(state, "Usage: target:assign(src) or df.assign(target,src)");
if (!lua_istable(state, 2))
{
type_identity *id1, *id2; type_identity *id1, *id2;
check_type_compatible(state, 1, 2, &id1, &id2, "df.assign()", false, false); check_type_compatible(state, 1, 2, &id1, &id2, "df.assign()", false, false);
if (!id1->copy(get_object_ref(state, 1), get_object_ref(state, 2))) if (!id1->copy(get_object_ref(state, 1), get_object_ref(state, 2)))
luaL_error(state, "No copy support for %s", id1->getFullName().c_str()); luaL_error(state, "No copy support for %s", id1->getFullName().c_str());
}
else
{
type_identity *id = get_object_identity(state, 1, "df.assign()", false);
int base = lua_gettop(state);
// x:assign{ assign = foo } => x:assign(foo)
bool has_assign = false;
lua_pushstring(state, "assign");
lua_dup(state);
lua_rawget(state, 2);
if (!lua_isnil(state,-1))
{
has_assign = true;
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
lua_pushvalue(state, 1);
lua_pushvalue(state, base+2);
lua_call(state, 2, 0);
}
lua_pop(state, 1);
// new is used by autovivification and should be skipped
lua_pushstring(state, "new");
if (id->isContainer())
{
// check resize field
lua_pushstring(state, "resize");
lua_dup(state);
lua_rawget(state, 2);
if (lua_isnil(state,-1) && !has_assign)
{
/*
* no assign && nil or missing resize field => 1-based lua array
*/
int size = lua_objlen(state, 2);
lua_pop(state, 1);
invoke_resize(state, 1, size);
for (int i = 1; i <= size; i++)
{
lua_pushinteger(state, i-1);
lua_rawgeti(state, 2, i);
lua_settable(state, 1);
}
}
else
{
if (lua_isboolean(state, -1) || lua_isnil(state, -1))
{
// resize=false => just assign
// resize=true => find the largest index
if (lua_toboolean(state, -1))
{
lua_Integer size = 0;
lua_pushnil(state);
while (lua_next(state, 2))
{
lua_pop(state, 1);
if (lua_isnumber(state,-1))
size = std::max(size, lua_tointeger(state,-1)+1);
}
invoke_resize(state, 1, size);
}
}
else
{
// otherwise, must be an explicit number
if (!lua_isnumber(state,-1))
luaL_error(state, "Invalid container.resize value in df.assign()");
invoke_resize(state, 1, lua_tointeger(state, -1));
}
lua_pop(state, 1);
copy_table(state, 1, 2, base);
}
}
else
{
copy_table(state, 1, 2, base);
}
}
return 0; return 0;
} }
/**
* Method: deallocation for DF object references.
*/
static int meta_delete(lua_State *state)
{
int argc = lua_gettop(state);
if (argc != 1)
luaL_error(state, "Usage: object:delete() or df.delete(object)");
if (lua_isnil(state, 1))
{
lua_pushboolean(state, true);
return 1;
}
type_identity *id = get_object_identity(state, 1, "df.delete()", false);
bool ok = id->destroy(get_object_ref(state, 1));
lua_pushboolean(state, ok);
return 1;
}
/** /**
* Verify that the object is a DF ref with UPVAL_METATABLE. * Verify that the object is a DF ref with UPVAL_METATABLE.
* If everything ok, extract the address. * If everything ok, extract the address.
@ -677,6 +822,47 @@ static int meta_ptr_tostring(lua_State *state)
return 1; return 1;
} }
/**
* Metamethod: __index for enum.attrs
*/
static int meta_enum_attr_index(lua_State *state)
{
if (!lua_isnumber(state, 2))
lua_rawget(state, UPVAL_FIELDTABLE);
if (!lua_isnumber(state, 2))
luaL_error(state, "Invalid index in enum.attrs[]");
auto id = (enum_identity*)lua_touserdata(state, lua_upvalueindex(2));
int64_t idx = lua_tonumber(state, 2);
if (idx < id->getFirstItem() || idx > id->getLastItem())
idx = id->getLastItem()+1;
idx -= id->getFirstItem();
uint8_t *ptr = (uint8_t*)id->getAttrs();
auto atype = id->getAttrType();
push_object_internal(state, atype, ptr + unsigned(atype->byte_size()*idx));
return 1;
}
static int meta_nodata(lua_State *state)
{
return 0;
}
/**
* Metamethod: __pairs, returning 1st upvalue as iterator
*/
static int meta_pairs(lua_State *state)
{
luaL_checkany(state, 1);
lua_pushvalue(state, lua_upvalueindex(1));
lua_pushvalue(state, 1);
lua_pushnil(state);
return 3;
}
/** /**
* Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE. * Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE.
*/ */
@ -703,7 +889,8 @@ void LuaWrapper::MakeMetatable(lua_State *state, type_identity *type, const char
lua_pushstring(state, kind); lua_pushstring(state, kind);
lua_setfield(state, base+1, "_kind"); lua_setfield(state, base+1, "_kind");
lua_newtable(state); // fieldtable // Create the field table
lua_newtable(state);
} }
/** /**
@ -741,6 +928,10 @@ void LuaWrapper::SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
lua_setfield(state, meta_idx, "new"); lua_setfield(state, meta_idx, "new");
EnableMetaField(state, read_idx, "new"); EnableMetaField(state, read_idx, "new");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DELETE_NAME);
lua_setfield(state, meta_idx, "delete");
EnableMetaField(state, read_idx, "delete");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
lua_setfield(state, meta_idx, "assign"); lua_setfield(state, meta_idx, "assign");
EnableMetaField(state, read_idx, "assign"); EnableMetaField(state, read_idx, "assign");
@ -750,24 +941,48 @@ void LuaWrapper::SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
EnableMetaField(state, read_idx, "_displace"); EnableMetaField(state, read_idx, "_displace");
} }
/**
* Add a __pairs/__ipairs metamethod using iterator on the top of stack.
*/
void LuaWrapper::SetPairsMethod(lua_State *state, int meta_idx, const char *name)
{
if (lua_isnil(state, -1))
{
lua_pop(state, 1);
lua_pushcfunction(state, meta_nodata);
}
lua_pushcclosure(state, meta_pairs, 1);
lua_setfield(state, meta_idx, name);
}
/** /**
* Add a struct-style (3 upvalues) metamethod to the metatable. * Add a struct-style (3 upvalues) metamethod to the metatable.
*/ */
void LuaWrapper::SetStructMethod(lua_State *state, int meta_idx, int ftable_idx, void LuaWrapper::PushStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function, const char *name) lua_CFunction function)
{ {
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
lua_pushvalue(state, meta_idx); lua_pushvalue(state, meta_idx);
lua_pushvalue(state, ftable_idx); lua_pushvalue(state, ftable_idx);
lua_pushcclosure(state, function, 3); lua_pushcclosure(state, function, 3);
}
/**
* Add a struct-style (3 upvalues) metamethod to the metatable.
*/
void LuaWrapper::SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function, const char *name)
{
PushStructMethod(state, meta_idx, ftable_idx, function);
lua_setfield(state, meta_idx, name); lua_setfield(state, meta_idx, name);
} }
/** /**
* Add a 6 upvalue metamethod to the metatable. * Add a 6 upvalue metamethod to the metatable.
*/ */
void LuaWrapper::SetContainerMethod(lua_State *state, int meta_idx, int ftable_idx, void LuaWrapper::PushContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function, const char *name, lua_CFunction function,
type_identity *container, type_identity *item, int count) type_identity *container, type_identity *item, int count)
{ {
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
@ -782,31 +997,48 @@ void LuaWrapper::SetContainerMethod(lua_State *state, int meta_idx, int ftable_i
lua_pushinteger(state, count); lua_pushinteger(state, count);
lua_pushcclosure(state, function, 6); lua_pushcclosure(state, function, 6);
}
/**
* Add a 6 upvalue metamethod to the metatable.
*/
void LuaWrapper::SetContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function, const char *name,
type_identity *container, type_identity *item, int count)
{
PushContainerMethod(state, meta_idx, ftable_idx, function, container, item, count);
lua_setfield(state, meta_idx, name); lua_setfield(state, meta_idx, name);
} }
/** /**
* If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE, * If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE,
* and the enum itself to the _enum metafield. * and the enum itself to the _enum metafield. Pushes the key table on the stack
*/ */
void LuaWrapper::AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum) void LuaWrapper::AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum)
{ {
EnableMetaField(state, ftable_idx, "_enum");
LookupInTable(state, ienum, DFHACK_TYPEID_TABLE_NAME);
lua_setfield(state, meta_idx, "_enum");
LookupInTable(state, ienum, DFHACK_ENUM_TABLE_NAME); LookupInTable(state, ienum, DFHACK_ENUM_TABLE_NAME);
if (!lua_isnil(state, -1)) if (!lua_isnil(state, -1))
{ {
lua_dup(state);
lua_newtable(state); lua_newtable(state);
lua_swap(state); lua_swap(state);
lua_setfield(state, -2, "__index"); lua_setfield(state, -2, "__index");
lua_setmetatable(state, ftable_idx); lua_setmetatable(state, ftable_idx);
} }
else else
{
lua_pop(state, 1); lua_pop(state, 1);
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_EMPTY_TABLE_NAME);
}
LookupInTable(state, ienum, DFHACK_TYPEID_TABLE_NAME); lua_dup(state);
lua_setfield(state, meta_idx, "_enum"); lua_setfield(state, meta_idx, "_index_table");
EnableMetaField(state, ftable_idx, "_enum");
} }
static void BuildTypeMetatable(lua_State *state, type_identity *type) static void BuildTypeMetatable(lua_State *state, type_identity *type)
@ -824,7 +1056,7 @@ static void BuildTypeMetatable(lua_State *state, type_identity *type)
static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children); static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children);
static void AssociateId(lua_State *state, int table, int val, const char *name) void LuaWrapper::AssociateId(lua_State *state, int table, int val, const char *name)
{ {
lua_pushinteger(state, val); lua_pushinteger(state, val);
lua_pushstring(state, name); lua_pushstring(state, name);
@ -835,127 +1067,168 @@ static void AssociateId(lua_State *state, int table, int val, const char *name)
lua_rawset(state, table); lua_rawset(state, table);
} }
static void RenderType(lua_State *state, compound_identity *node) static void FillEnumKeys(lua_State *state, int ftable, enum_identity *eid)
{ {
assert(node->getName()); const char *const *keys = eid->getKeys();
std::string name = node->getFullName();
// Create a new table attached to ftable as __index
lua_newtable(state); lua_newtable(state);
if (!lua_checkstack(state, 20))
return;
int base = lua_gettop(state);
switch (node->type()) lua_dup(state);
{ lua_setmetatable(state, ftable);
case IDTYPE_STRUCT:
lua_pushstring(state, "struct-type");
lua_setfield(state, base, "_kind");
break;
case IDTYPE_CLASS:
lua_pushstring(state, "class-type");
lua_setfield(state, base, "_kind");
break;
case IDTYPE_ENUM: int base = lua_gettop(state);
{
lua_pushstring(state, "enum-type");
lua_setfield(state, base, "_kind");
enum_identity *eid = (enum_identity*)node; lua_newtable(state);
const char *const *keys = eid->getKeys();
// For enums, set mapping between keys and values // For enums, set mapping between keys and values
for (int64_t i = eid->getFirstItem(), j = 0; i <= eid->getLastItem(); i++, j++) for (int64_t i = eid->getFirstItem(), j = 0; i <= eid->getLastItem(); i++, j++)
{ {
if (keys[j]) if (keys[j])
AssociateId(state, base, i, keys[j]); AssociateId(state, base+1, i, keys[j]);
} }
if (eid->getFirstItem() <= eid->getLastItem()) if (eid->getFirstItem() <= eid->getLastItem())
{ {
lua_pushinteger(state, eid->getFirstItem()); lua_pushinteger(state, eid->getFirstItem());
lua_setfield(state, base, "_first_item"); lua_setfield(state, base+1, "_first_item");
lua_pushinteger(state, eid->getLastItem()); lua_pushinteger(state, eid->getLastItem());
lua_setfield(state, base, "_last_item"); lua_setfield(state, base+1, "_last_item");
} }
SaveInTable(state, node, DFHACK_ENUM_TABLE_NAME); SaveInTable(state, eid, DFHACK_ENUM_TABLE_NAME);
}
break;
case IDTYPE_BITFIELD: // Add an attribute table if any
if (eid->getAttrs())
{ {
lua_pushstring(state, "bitfield-type"); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
lua_setfield(state, base, "_kind"); lua_pushlightuserdata(state, eid);
lua_pushvalue(state, base+1);
lua_pushcclosure(state, meta_enum_attr_index, 3);
freeze_table(state, false, (eid->getFullName()+".attrs").c_str());
lua_setfield(state, ftable, "attrs");
}
lua_setfield(state, base, "__index");
lua_pop(state, 1);
}
bitfield_identity *eid = (bitfield_identity*)node; static void FillBitfieldKeys(lua_State *state, int ftable, bitfield_identity *eid)
{
auto bits = eid->getBits(); auto bits = eid->getBits();
for (int i = 0; i < eid->getNumBits(); i++) for (int i = 0; i < eid->getNumBits(); i++)
{ {
if (bits[i].name) if (bits[i].name)
AssociateId(state, base, i, bits[i].name); AssociateId(state, ftable, i, bits[i].name);
if (bits[i].size > 1) if (bits[i].size > 1)
i += bits[i].size-1; i += bits[i].size-1;
} }
lua_pushinteger(state, 0); lua_pushinteger(state, 0);
lua_setfield(state, base, "_first_item"); lua_setfield(state, ftable, "_first_item");
lua_pushinteger(state, eid->getNumBits()-1); lua_pushinteger(state, eid->getNumBits()-1);
lua_setfield(state, base, "_last_item"); lua_setfield(state, ftable, "_last_item");
SaveInTable(state, node, DFHACK_ENUM_TABLE_NAME); SaveInTable(state, eid, DFHACK_ENUM_TABLE_NAME);
} }
break;
default: static void RenderType(lua_State *state, compound_identity *node)
{
assert(node->getName());
std::string name = node->getFullName();
int base = lua_gettop(state);
lua_newtable(state);
if (!lua_checkstack(state, 20))
return;
SaveInTable(state, node, DFHACK_TYPEID_TABLE_NAME);
// metatable
lua_newtable(state);
lua_dup(state);
lua_setmetatable(state, base+1);
lua_pushstring(state, name.c_str());
lua_setfield(state, base+2, "__metatable");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPE_TOSTRING_NAME);
lua_setfield(state, base+2, "__tostring");
lua_pushlightuserdata(state, node);
lua_setfield(state, base+2, "_identity");
// inner table
lua_newtable(state);
lua_dup(state);
lua_setfield(state, base+2, "__index");
int ftable = base+3;
switch (node->type())
{
case IDTYPE_STRUCT:
lua_pushstring(state, "struct-type");
lua_setfield(state, ftable, "_kind");
IndexStatics(state, base+2, base+3, (struct_identity*)node);
break; break;
}
RenderTypeChildren(state, node->getScopeChildren()); case IDTYPE_CLASS:
lua_pushstring(state, "class-type");
lua_setfield(state, ftable, "_kind");
IndexStatics(state, base+2, base+3, (struct_identity*)node);
break;
assert(base == lua_gettop(state)); case IDTYPE_ENUM:
lua_pushstring(state, "enum-type");
lua_setfield(state, ftable, "_kind");
FillEnumKeys(state, ftable, (enum_identity*)node);
break;
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME); case IDTYPE_BITFIELD:
lua_setfield(state, base, "sizeof"); lua_pushstring(state, "bitfield-type");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME); lua_setfield(state, ftable, "_kind");
lua_setfield(state, base, "new"); FillBitfieldKeys(state, ftable, (bitfield_identity*)node);
break;
if (node->type() == IDTYPE_GLOBAL) case IDTYPE_GLOBAL:
{ {
RenderTypeChildren(state, node->getScopeChildren());
BuildTypeMetatable(state, node); BuildTypeMetatable(state, node);
// Set metatable for the inner table
lua_dup(state); lua_dup(state);
lua_setmetatable(state, base); lua_setmetatable(state, base+3);
lua_swap(state); // -> meta curtable
freeze_table(state, true, "global");
// Copy __newindex to the outer metatable lua_getfield(state, -1, "__newindex");
lua_getfield(state, base, "__newindex"); lua_setfield(state, base+2, "__newindex");
lua_setfield(state, -2, "__newindex"); lua_getfield(state, -1, "__pairs");
lua_setfield(state, base+2, "__pairs");
lua_remove(state, base); lua_pop(state, 3);
return;
} }
else
{ default:
freeze_table(state, true, name.c_str()); break;
} }
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPE_TOSTRING_NAME); RenderTypeChildren(state, node->getScopeChildren());
lua_setfield(state, -2, "__tostring");
lua_pushlightuserdata(state, node); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
lua_setfield(state, -2, "_identity"); lua_setfield(state, ftable, "sizeof");
lua_pop(state, 1); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME);
lua_setfield(state, ftable, "new");
SaveInTable(state, node, DFHACK_TYPEID_TABLE_NAME); lua_pop(state, 2);
} }
static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children) static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children)
@ -982,6 +1255,9 @@ static void DoAttach(lua_State *state)
lua_newtable(state); lua_newtable(state);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ENUM_TABLE_NAME); lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ENUM_TABLE_NAME);
lua_newtable(state);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_EMPTY_TABLE_NAME);
lua_pushcfunction(state, change_error); lua_pushcfunction(state, change_error);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_CHANGEERROR_NAME); lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_CHANGEERROR_NAME);
@ -1007,6 +1283,10 @@ static void DoAttach(lua_State *state)
lua_pushcclosure(state, meta_assign, 1); lua_pushcclosure(state, meta_assign, 1);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
lua_pushcclosure(state, meta_delete, 1);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_DELETE_NAME);
luaL_register(state, "df", no_functions); luaL_register(state, "df", no_functions);
{ {
@ -1020,11 +1300,18 @@ static void DoAttach(lua_State *state)
lua_setfield(state, -2, "sizeof"); lua_setfield(state, -2, "sizeof");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME);
lua_setfield(state, -2, "new"); lua_setfield(state, -2, "new");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DELETE_NAME);
lua_setfield(state, -2, "delete");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME);
lua_setfield(state, -2, "_displace"); lua_setfield(state, -2, "_displace");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
lua_setfield(state, -2, "assign"); lua_setfield(state, -2, "assign");
lua_pushlightuserdata(state, NULL);
lua_setfield(state, -2, "NULL");
lua_pushlightuserdata(state, NULL);
lua_setglobal(state, "NULL");
freeze_table(state, true, "df"); freeze_table(state, true, "df");
lua_remove(state, -2); lua_remove(state, -2);
lua_setmetatable(state, -2); lua_setmetatable(state, -2);

@ -212,6 +212,7 @@ bool Plugin::load(color_ostream &con)
plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect"); plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect");
this->name = *plug_name; this->name = *plug_name;
plugin_lib = plug; plugin_lib = plug;
commands.clear();
if(plugin_init(con,commands) == CR_OK) if(plugin_init(con,commands) == CR_OK)
{ {
state = PS_LOADED; state = PS_LOADED;
@ -242,6 +243,7 @@ bool Plugin::unload(color_ostream &con)
access->wait(); access->wait();
// cleanup... // cleanup...
parent->unregisterCommands(this); parent->unregisterCommands(this);
commands.clear();
if(cr == CR_OK) if(cr == CR_OK)
{ {
ClosePlugin(plugin_lib); ClosePlugin(plugin_lib);

@ -25,6 +25,7 @@ distribution.
#include "Internal.h" #include "Internal.h"
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <string> #include <string>
@ -131,12 +132,12 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
{ {
t_memrange temp; t_memrange temp;
temp.name[0] = 0; temp.name[0] = 0;
sscanf(buffer, "%zx-%zx %s %zx %2zu:%2zu %zu %[^\n]s", sscanf(buffer, "%zx-%zx %s %zx %2zx:%2zx %zu %[^\n]",
&start, &start,
&end, &end,
(char*)&permissions, (char*)&permissions,
&offset, &device1, &device2, &node, &offset, &device1, &device2, &node,
(char*)&temp.name); (char*)temp.name);
temp.start = (void *) start; temp.start = (void *) start;
temp.end = (void *) end; temp.end = (void *) end;
temp.read = permissions[0] == 'r'; temp.read = permissions[0] == 'r';

@ -49,6 +49,7 @@ namespace DFHack
enum identity_type { enum identity_type {
IDTYPE_GLOBAL, IDTYPE_GLOBAL,
IDTYPE_FUNCTION,
IDTYPE_PRIMITIVE, IDTYPE_PRIMITIVE,
IDTYPE_POINTER, IDTYPE_POINTER,
IDTYPE_CONTAINER, IDTYPE_CONTAINER,
@ -72,10 +73,12 @@ namespace DFHack
void *do_allocate_pod(); void *do_allocate_pod();
void do_copy_pod(void *tgt, const void *src); void do_copy_pod(void *tgt, const void *src);
bool do_destroy_pod(void *obj);
virtual bool can_allocate() { return true; } virtual bool can_allocate() { return true; }
virtual void *do_allocate() { return do_allocate_pod(); } virtual void *do_allocate() { return do_allocate_pod(); }
virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); } virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); }
virtual bool do_destroy(void *obj) { return do_destroy_pod(obj); }
public: public:
virtual ~type_identity() {} virtual ~type_identity() {}
@ -100,6 +103,7 @@ namespace DFHack
void *allocate(); void *allocate();
bool copy(void *tgt, const void *src); bool copy(void *tgt, const void *src);
bool destroy(void *obj);
}; };
class DFHACK_EXPORT constructed_identity : public type_identity { class DFHACK_EXPORT constructed_identity : public type_identity {
@ -109,12 +113,13 @@ namespace DFHack
constructed_identity(size_t size, TAllocateFn alloc) constructed_identity(size_t size, TAllocateFn alloc)
: type_identity(size), allocator(alloc) {}; : type_identity(size), allocator(alloc) {};
virtual bool isPrimitive() { return false; }
virtual bool isConstructed() { return true; }
virtual bool can_allocate() { return (allocator != NULL); } virtual bool can_allocate() { return (allocator != NULL); }
virtual void *do_allocate() { return allocator(NULL,NULL); } virtual void *do_allocate() { return allocator(NULL,NULL); }
virtual void do_copy(void *tgt, const void *src) { allocator(tgt,src); } virtual void do_copy(void *tgt, const void *src) { allocator(tgt,src); }
virtual bool do_destroy(void *obj) { return allocator(NULL,obj) == obj; }
public:
virtual bool isPrimitive() { return false; }
virtual bool isConstructed() { return true; }
virtual void lua_read(lua_State *state, int fname_idx, void *ptr); virtual void lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
@ -161,6 +166,7 @@ namespace DFHack
virtual bool can_allocate() { return true; } virtual bool can_allocate() { return true; }
virtual void *do_allocate() { return do_allocate_pod(); } virtual void *do_allocate() { return do_allocate_pod(); }
virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); } virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); }
virtual bool do_destroy(void *obj) { return do_destroy_pod(obj); }
public: public:
bitfield_identity(size_t size, bitfield_identity(size_t size,
@ -177,6 +183,8 @@ namespace DFHack
virtual void build_metatable(lua_State *state); virtual void build_metatable(lua_State *state);
}; };
class struct_identity;
class DFHACK_EXPORT enum_identity : public compound_identity { class DFHACK_EXPORT enum_identity : public compound_identity {
const char *const *keys; const char *const *keys;
int64_t first_item_value; int64_t first_item_value;
@ -184,17 +192,22 @@ namespace DFHack
type_identity *base_type; type_identity *base_type;
const void *attrs;
struct_identity *attr_type;
protected: protected:
virtual bool can_allocate() { return true; } virtual bool can_allocate() { return true; }
virtual void *do_allocate(); virtual void *do_allocate();
virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); } virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); }
virtual bool do_destroy(void *obj) { return do_destroy_pod(obj); }
public: public:
enum_identity(size_t size, enum_identity(size_t size,
compound_identity *scope_parent, const char *dfhack_name, compound_identity *scope_parent, const char *dfhack_name,
type_identity *base_type, type_identity *base_type,
int64_t first_item_value, int64_t last_item_value, int64_t first_item_value, int64_t last_item_value,
const char *const *keys); const char *const *keys,
const void *attrs, struct_identity *attr_type);
virtual identity_type type() { return IDTYPE_ENUM; } virtual identity_type type() { return IDTYPE_ENUM; }
@ -204,6 +217,8 @@ namespace DFHack
const char *const *getKeys() { return keys; } const char *const *getKeys() { return keys; }
type_identity *getBaseType() { return base_type; } type_identity *getBaseType() { return base_type; }
const void *getAttrs() { return attrs; }
struct_identity *getAttrType() { return attr_type; }
virtual bool isPrimitive() { return true; } virtual bool isPrimitive() { return true; }
virtual bool isConstructed() { return false; } virtual bool isConstructed() { return false; }
@ -221,7 +236,9 @@ namespace DFHack
STATIC_ARRAY, STATIC_ARRAY,
SUBSTRUCT, SUBSTRUCT,
CONTAINER, CONTAINER,
STL_VECTOR_PTR STL_VECTOR_PTR,
OBJ_METHOD,
CLASS_METHOD
}; };
Mode mode; Mode mode;
const char *name; const char *name;
@ -409,6 +426,14 @@ namespace df
template<class T> template<class T>
void *allocator_fn(void *out, const void *in) { void *allocator_fn(void *out, const void *in) {
if (out) { *(T*)out = *(const T*)in; return out; } if (out) { *(T*)out = *(const T*)in; return out; }
else if (in) { delete (T*)in; return (T*)in; }
else return new T();
}
template<class T>
void *allocator_nodel_fn(void *out, const void *in) {
if (out) { *(T*)out = *(const T*)in; return out; }
else if (in) { return NULL; }
else return new T(); else return new T();
} }

@ -0,0 +1,142 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include "DataIdentity.h"
#include "LuaWrapper.h"
namespace df {
// A very simple and stupid implementation of some stuff from boost
template<class U, class V> struct is_same_type { static const bool value = false; };
template<class T> struct is_same_type<T,T> { static const bool value = true; };
template<class T> struct return_type {};
/*
* Workaround for a msvc bug suggested by:
*
* http://stackoverflow.com/questions/5110529/class-template-partial-specialization-parametrized-on-member-function-return-typ
*/
template<class T, bool isvoid = is_same_type<typename return_type<T>::type,void>::value>
struct function_wrapper {};
/*
* Since templates can't match variable arg count,
* a separate specialization is needed for every
* supported count value...
*
* The FW_TARGS ugliness is needed because of
* commas not wrapped in ()
*/
#define INVOKE_VOID(call) \
call; lua_pushnil(state);
#define INVOKE_RV(call) \
RT rv = call; df::identity_traits<RT>::get()->lua_read(state, UPVAL_METHOD_NAME, &rv);
#define LOAD_CLASS() \
CT *self = (CT*)DFHack::LuaWrapper::get_object_addr(state, base++, UPVAL_METHOD_NAME, "invoke");
#define LOAD_ARG(type) \
type v##type; df::identity_traits<type>::get()->lua_write(state, UPVAL_METHOD_NAME, &v##type, base++);
#define INSTANTIATE_WRAPPERS(Count, FArgs, Args, Loads) \
template<FW_TARGSC class RT> struct return_type<RT (*) FArgs> { typedef RT type; }; \
template<FW_TARGSC class RT, class CT> struct return_type<RT (CT::*) FArgs> { typedef RT type; }; \
template<FW_TARGS> struct function_wrapper<void (*) FArgs, true> { \
static const bool is_method = false; \
static const int num_args = Count; \
static void execute(lua_State *state, int base, void (*cb) FArgs) { Loads; INVOKE_VOID(cb Args); } \
}; \
template<FW_TARGSC class RT> struct function_wrapper<RT (*) FArgs, false> { \
static const bool is_method = false; \
static const int num_args = Count; \
static void execute(lua_State *state, int base, RT (*cb) FArgs) { Loads; INVOKE_RV(cb Args); } \
}; \
template<FW_TARGSC class CT> struct function_wrapper<void (CT::*) FArgs, true> { \
static const bool is_method = true; \
static const int num_args = Count+1; \
static void execute(lua_State *state, int base, void (CT::*cb) FArgs) { \
LOAD_CLASS() Loads; INVOKE_VOID((self->*cb) Args); } \
}; \
template<FW_TARGSC class RT, class CT> struct function_wrapper<RT (CT::*) FArgs, false> { \
static const bool is_method = true; \
static const int num_args = Count+1; \
static void execute(lua_State *state, int base, RT (CT::*cb) FArgs) { \
LOAD_CLASS(); Loads; INVOKE_RV((self->*cb) Args); } \
};
#define FW_TARGSC
#define FW_TARGS
INSTANTIATE_WRAPPERS(0, (), (), ;)
#undef FW_TARGS
#undef FW_TARGSC
#define FW_TARGSC FW_TARGS,
#define FW_TARGS class A1
INSTANTIATE_WRAPPERS(1, (A1), (vA1), LOAD_ARG(A1);)
#undef FW_TARGS
#define FW_TARGS class A1, class A2
INSTANTIATE_WRAPPERS(2, (A1,A2), (vA1,vA2), LOAD_ARG(A1); LOAD_ARG(A2);)
#undef FW_TARGS
#define FW_TARGS class A1, class A2, class A3
INSTANTIATE_WRAPPERS(3, (A1,A2,A3), (vA1,vA2,vA3), LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3);)
#undef FW_TARGS
#define FW_TARGS class A1, class A2, class A3, class A4
INSTANTIATE_WRAPPERS(4, (A1,A2,A3,A4), (vA1,vA2,vA3,vA4),
LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4);)
#undef FW_TARGS
#undef FW_TARGSC
#undef INSTANTIATE_WRAPPERS
#undef INVOKE_VOID
#undef INVOKE_RV
#undef LOAD_CLASS
#undef LOAD_ARG
template<class T>
class function_identity : public function_identity_base {
T ptr;
public:
typedef function_wrapper<T> wrapper;
function_identity(T ptr)
: function_identity_base(wrapper::num_args), ptr(ptr) {};
virtual void invoke(lua_State *state, int base) { wrapper::execute(state, base, ptr); }
};
template<class T>
inline function_identity_base *wrap_function(T ptr) {
// bah, but didn't have any idea how to allocate statically
return new function_identity<T>(ptr);
}
}

@ -37,6 +37,23 @@ distribution.
namespace DFHack namespace DFHack
{ {
class DFHACK_EXPORT function_identity_base : public type_identity {
int num_args;
public:
function_identity_base(int num_args) : type_identity(0), num_args(num_args) {};
virtual identity_type type() { return IDTYPE_FUNCTION; }
int getNumArgs() { return num_args; }
std::string getFullName() { return "function"; }
virtual void invoke(lua_State *state, int base) = 0;
virtual void lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
class DFHACK_EXPORT primitive_identity : public type_identity { class DFHACK_EXPORT primitive_identity : public type_identity {
public: public:
primitive_identity(size_t size) : type_identity(size) {}; primitive_identity(size_t size) : type_identity(size) {};
@ -145,6 +162,7 @@ namespace DFHack
namespace df namespace df
{ {
using DFHack::function_identity_base;
using DFHack::primitive_identity; using DFHack::primitive_identity;
using DFHack::pointer_identity; using DFHack::pointer_identity;
using DFHack::container_identity; using DFHack::container_identity;
@ -187,6 +205,16 @@ namespace df
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
}; };
class ptr_string_identity : public primitive_identity {
public:
ptr_string_identity() : primitive_identity(sizeof(char*)) {};
std::string getFullName() { return "char*"; }
virtual void lua_read(lua_State *state, int fname_idx, void *ptr);
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
class stl_string_identity : public DFHack::constructed_identity { class stl_string_identity : public DFHack::constructed_identity {
public: public:
stl_string_identity() stl_string_identity()
@ -370,6 +398,28 @@ namespace df
} }
}; };
template<class T>
class enum_list_attr_identity : public container_identity {
public:
typedef enum_list_attr<T> container;
enum_list_attr_identity(type_identity *item)
: container_identity(sizeof(container), NULL, item, NULL)
{}
std::string getFullName(type_identity *item) {
return "enum_list_attr" + container_identity::getFullName(item);
}
protected:
virtual int item_count(void *ptr, CountMode cm) {
return cm == COUNT_WRITE ? 0 : ((container*)ptr)->size;
}
virtual void *item_pointer(type_identity *item, void *ptr, int idx) {
return (void*)&((container*)ptr)->items[idx];
}
};
#define NUMBER_IDENTITY_TRAITS(type) \ #define NUMBER_IDENTITY_TRAITS(type) \
template<> struct identity_traits<type> { \ template<> struct identity_traits<type> { \
static number_identity<type> identity; \ static number_identity<type> identity; \
@ -397,6 +447,16 @@ namespace df
static stl_string_identity *get() { return &identity; } static stl_string_identity *get() { return &identity; }
}; };
template<> struct identity_traits<char*> {
static ptr_string_identity identity;
static ptr_string_identity *get() { return &identity; }
};
template<> struct identity_traits<const char*> {
static ptr_string_identity identity;
static ptr_string_identity *get() { return &identity; }
};
template<> struct identity_traits<void*> { template<> struct identity_traits<void*> {
static pointer_identity identity; static pointer_identity identity;
static pointer_identity *get() { return &identity; } static pointer_identity *get() { return &identity; }
@ -440,6 +500,11 @@ namespace df
static container_identity *get(); static container_identity *get();
}; };
template<> struct identity_traits<BitArray<int> > {
static bit_array_identity identity;
static bit_container_identity *get() { return &identity; }
};
template<class T> struct identity_traits<BitArray<T> > { template<class T> struct identity_traits<BitArray<T> > {
static bit_container_identity *get(); static bit_container_identity *get();
}; };
@ -448,58 +513,66 @@ namespace df
static container_identity *get(); static container_identity *get();
}; };
template<class T> struct identity_traits<enum_list_attr<T> > {
static container_identity *get();
};
// Container definitions // Container definitions
template<class Enum, class FT> template<class Enum, class FT>
primitive_identity *identity_traits<enum_field<Enum,FT> >::get() { inline primitive_identity *identity_traits<enum_field<Enum,FT> >::get() {
return identity_traits<FT>::get(); return identity_traits<FT>::get();
} }
template<class T> template<class T>
pointer_identity *identity_traits<T *>::get() { inline pointer_identity *identity_traits<T *>::get() {
static pointer_identity identity(identity_traits<T>::get()); static pointer_identity identity(identity_traits<T>::get());
return &identity; return &identity;
} }
template<class T, int sz> template<class T, int sz>
container_identity *identity_traits<T [sz]>::get() { inline container_identity *identity_traits<T [sz]>::get() {
static buffer_container_identity identity(sz, identity_traits<T>::get()); static buffer_container_identity identity(sz, identity_traits<T>::get());
return &identity; return &identity;
} }
template<class T> template<class T>
container_identity *identity_traits<std::vector<T> >::get() { inline container_identity *identity_traits<std::vector<T> >::get() {
typedef std::vector<T> container; typedef std::vector<T> container;
static stl_container_identity<container> identity("vector", identity_traits<T>::get()); static stl_container_identity<container> identity("vector", identity_traits<T>::get());
return &identity; return &identity;
} }
template<class T> template<class T>
stl_ptr_vector_identity *identity_traits<std::vector<T*> >::get() { inline stl_ptr_vector_identity *identity_traits<std::vector<T*> >::get() {
static stl_ptr_vector_identity identity(identity_traits<T>::get()); static stl_ptr_vector_identity identity(identity_traits<T>::get());
return &identity; return &identity;
} }
template<class T> template<class T>
container_identity *identity_traits<std::deque<T> >::get() { inline container_identity *identity_traits<std::deque<T> >::get() {
typedef std::deque<T> container; typedef std::deque<T> container;
static stl_container_identity<container> identity("deque", identity_traits<T>::get()); static stl_container_identity<container> identity("deque", identity_traits<T>::get());
return &identity; return &identity;
} }
template<class T> template<class T>
bit_container_identity *identity_traits<BitArray<T> >::get() { inline bit_container_identity *identity_traits<BitArray<T> >::get() {
static type_identity *eid = identity_traits<T>::get(); static bit_array_identity identity(identity_traits<T>::get());
static enum_identity *reid = eid->type() == DFHack::IDTYPE_ENUM ? (enum_identity*)eid : NULL;
static bit_array_identity identity(reid);
return &identity; return &identity;
} }
template<class T> template<class T>
container_identity *identity_traits<DfArray<T> >::get() { inline container_identity *identity_traits<DfArray<T> >::get() {
typedef DfArray<T> container; typedef DfArray<T> container;
static stl_container_identity<container> identity("DfArray", identity_traits<T>::get()); static stl_container_identity<container> identity("DfArray", identity_traits<T>::get());
return &identity; return &identity;
} }
template<class T>
inline container_identity *identity_traits<enum_list_attr<T> >::get() {
static enum_list_attr_identity<T> identity(identity_traits<T>::get());
return &identity;
}
} }

@ -68,6 +68,8 @@ namespace DFHack { namespace LuaWrapper {
#define DFHACK_DISPLACE_NAME "DFHack::Displace" #define DFHACK_DISPLACE_NAME "DFHack::Displace"
#define DFHACK_NEW_NAME "DFHack::New" #define DFHACK_NEW_NAME "DFHack::New"
#define DFHACK_ASSIGN_NAME "DFHack::Assign" #define DFHACK_ASSIGN_NAME "DFHack::Assign"
#define DFHACK_DELETE_NAME "DFHack::Delete"
#define DFHACK_EMPTY_TABLE_NAME "DFHack::EmptyTable"
/* /*
* Upvalue: contents of DFHACK_TYPETABLE_NAME * Upvalue: contents of DFHACK_TYPETABLE_NAME
@ -148,10 +150,19 @@ namespace DFHack { namespace LuaWrapper {
*/ */
uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode); uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode);
bool is_type_compatible(lua_State *state, type_identity *type1, int meta1,
type_identity *type2, int meta2, bool exact_equal);
type_identity *get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type = false,
bool keep_metatable = false);
void LookupInTable(lua_State *state, void *id, const char *tname); void LookupInTable(lua_State *state, void *id, const char *tname);
void SaveInTable(lua_State *state, void *node, const char *tname); void SaveInTable(lua_State *state, void *node, const char *tname);
void SaveTypeInfo(lua_State *state, void *node); void SaveTypeInfo(lua_State *state, void *node);
void AssociateId(lua_State *state, int table, int val, const char *name);
/** /**
* Look up the key on the stack in DFHACK_TYPETABLE; * Look up the key on the stack in DFHACK_TYPETABLE;
* if found, put result on the stack and return true. * if found, put result on the stack and return true.
@ -170,11 +181,26 @@ namespace DFHack { namespace LuaWrapper {
* Set metatable properties common to all actual DF object references. * Set metatable properties common to all actual DF object references.
*/ */
void SetPtrMethods(lua_State *state, int meta_idx, int read_idx); void SetPtrMethods(lua_State *state, int meta_idx, int read_idx);
/**
* Add a __pairs/__ipairs metamethod using iterator on the top of stack.
*/
void SetPairsMethod(lua_State *state, int meta_idx, const char *name);
/**
* Add a struct-style (3 upvalues) metamethod to the stack.
*/
void PushStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function);
/** /**
* Add a struct-style (3 upvalues) metamethod to the metatable. * Add a struct-style (3 upvalues) metamethod to the metatable.
*/ */
void SetStructMethod(lua_State *state, int meta_idx, int ftable_idx, void SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function, const char *name); lua_CFunction function, const char *name);
/**
* Add a 6 upvalue metamethod to the stack.
*/
void PushContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function,
type_identity *container, type_identity *item, int count);
/** /**
* Add a 6 upvalue metamethod to the metatable. * Add a 6 upvalue metamethod to the metatable.
*/ */
@ -183,8 +209,10 @@ namespace DFHack { namespace LuaWrapper {
type_identity *container, type_identity *item, int count); type_identity *container, type_identity *item, int count);
/** /**
* If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE, * If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE,
* and the enum itself to the _enum metafield. * and the enum itself to the _enum metafield. Pushes the key table on the stack.
*/ */
void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum); void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum);
void IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct);
}} }}

@ -54,6 +54,8 @@ distribution.
// just shut up already. // just shut up already.
#pragma warning( disable: 4244) #pragma warning( disable: 4244)
#pragma warning( disable: 4018) #pragma warning( disable: 4018)
// nonstandard extension used: enum 'df::whatever::etc' used in qualified name
#pragma warning( disable: 4482)
#endif #endif
#endif #endif

@ -40,7 +40,7 @@ namespace df
namespace DFHack namespace DFHack
{ {
class MaterialInfo; struct MaterialInfo;
using google::protobuf::RepeatedField; using google::protobuf::RepeatedField;
using google::protobuf::RepeatedPtrField; using google::protobuf::RepeatedPtrField;

@ -1 +1 @@
Subproject commit 8f2fdb4e0258db7a139e26f1084f05f9a45824c3 Subproject commit 3e1c728640d8f5a9501908064a2d5385a156058c

@ -10,11 +10,6 @@ if(BUILD_DFUSION)
add_subdirectory (Dfusion) add_subdirectory (Dfusion)
endif() endif()
OPTION(BUILD_QTPLUG "Build the experimental Qt plugin." OFF)
if(BUILD_QTPLUG)
add_subdirectory (qtplug)
endif()
OPTION(BUILD_STONESENSE "Build stonesense (needs a checkout first)." OFF) OPTION(BUILD_STONESENSE "Build stonesense (needs a checkout first)." OFF)
if(BUILD_STONESENSE) if(BUILD_STONESENSE)
add_subdirectory (stonesense) add_subdirectory (stonesense)
@ -25,11 +20,6 @@ if(BUILD_DEV_PLUGINS)
add_subdirectory (devel) add_subdirectory (devel)
endif() endif()
OPTION(BUILD_SERVER "Build server." OFF)
if(BUILD_SERVER)
add_subdirectory (server)
endif()
OPTION(BUILD_DF2MC "Build DF2MC (needs a checkout first)." OFF) OPTION(BUILD_DF2MC "Build DF2MC (needs a checkout first)." OFF)
if(BUILD_DF2MC) if(BUILD_DF2MC)
add_subdirectory (df2mc) add_subdirectory (df2mc)
@ -100,6 +90,8 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(fixpositions fixpositions.cpp) DFHACK_PLUGIN(fixpositions fixpositions.cpp)
DFHACK_PLUGIN(follow follow.cpp) DFHACK_PLUGIN(follow follow.cpp)
DFHACK_PLUGIN(changevein changevein.cpp) DFHACK_PLUGIN(changevein changevein.cpp)
DFHACK_PLUGIN(changelayer changelayer.cpp)
DFHACK_PLUGIN(changeitem changeitem.cpp)
DFHACK_PLUGIN(advtools advtools.cpp) DFHACK_PLUGIN(advtools advtools.cpp)
DFHACK_PLUGIN(tweak tweak.cpp) DFHACK_PLUGIN(tweak tweak.cpp)
DFHACK_PLUGIN(feature feature.cpp) DFHACK_PLUGIN(feature feature.cpp)
@ -114,4 +106,3 @@ OPTION(BUILD_SKELETON "Build the skeleton plugin." OFF)
if(BUILD_SKELETON) if(BUILD_SKELETON)
add_subdirectory(skeleton) add_subdirectory(skeleton)
endif() endif()

@ -12,4 +12,3 @@ DFHACK_PLUGIN(dfusion ${DFUSION_CPPS_ALL} ${DFUSION_HS} LINK_LIBRARIES lua dfha
# installs into DF root # installs into DF root
install(DIRECTORY luafiles/ DESTINATION dfusion) install(DIRECTORY luafiles/ DESTINATION dfusion)
install(FILES ../../library/include/df/codegen.out.xml DESTINATION dfusion/patterns/)

@ -1,17 +0,0 @@
#ifndef BIT_H
#define BIT_H
#define LUA_BITOP_VERSION "1.0.1"
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#ifdef __cplusplus
extern "C" {
#endif
LUALIB_API int luaopen_bit(lua_State *L);
#ifdef __cplusplus
}
#endif
#endif // BIT_H

@ -7,7 +7,6 @@
#include <MemAccess.h> #include <MemAccess.h>
#include "luamain.h" #include "luamain.h"
#include "OutFile.h" #include "OutFile.h"
#include "bit.h"
#include "functioncall.h" #include "functioncall.h"
namespace lua namespace lua

@ -5,11 +5,11 @@ using std::string;
extern "C" {
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
}
#include "lune.h" #include "lune.h"
#include "luaxx.hpp" #include "luaxx.hpp"

@ -28,11 +28,12 @@
#define lua_Integer_long 1 #define lua_Integer_long 1
#define lua_Integer_int 1 #define lua_Integer_int 1
extern "C" {
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
}
#include <string> #include <string>
#include <vector> #include <vector>
#include <new> #include <new>

@ -1,11 +1,11 @@
#ifndef LUNE_H #ifndef LUNE_H
#define LUNE_H #define LUNE_H
extern "C" {
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
}
#include "luaxx.hpp" #include "luaxx.hpp"
#include <string> #include <string>

@ -366,8 +366,8 @@ function findVectors()
end end
function GetRaceToken(p) --actually gets token... function GetRaceToken(p) --actually gets token...
local vec=df.world.raws.creatures.all local vec=df.global.world.raws.creatures.all
return vec[p]:deref().creature_id return vec[p].creature_id
end end
function BuildNameTable() function BuildNameTable()
local rtbl={} local rtbl={}

@ -2,8 +2,8 @@ if not(FILE) then
--sanity test --sanity test
--print("race num:"..engine.peekw(offsets.getEx("CurrentRace"))) --print("race num:"..engine.peekw(offsets.getEx("CurrentRace")))
--print(string.format("%x vs %x",offsets.getEx("CurrentRace"),VersionInfo.getGroup("Creatures"):getAddress("current_race"))) --print(string.format("%x vs %x",offsets.getEx("CurrentRace"),VersionInfo.getGroup("Creatures"):getAddress("current_race")))
print("Race num:"..df.ui.race_id) print("Race num:"..df.global.ui.race_id)
print("Your current race is:"..GetRaceToken(df.ui.race_id)) print("Your current race is:"..GetRaceToken(df.global.ui.race_id))
print("If this is wrong please type 'q'") print("If this is wrong please type 'q'")
if(getline()=='q') then if(getline()=='q') then
return return

@ -47,7 +47,7 @@ function mainmenu(t1)
end end
function RunSaved() function RunSaved()
print("Locating saves...") print("Locating saves...")
local str=df.world.cur_savegame.save_dir local str=df.global.world.cur_savegame.save_dir
print("Current region:"..str) print("Current region:"..str)
str="data/save/"..str.."/dfusion/init.lua" str="data/save/"..str.."/dfusion/init.lua"
print("Trying to run:"..str) print("Trying to run:"..str)
@ -73,8 +73,8 @@ table.insert(plugins,{"adv_tools","some tools for (mainly) advneturer hacking"})
table.insert(plugins,{"triggers","a function calling plug (discontinued...)"}) table.insert(plugins,{"triggers","a function calling plug (discontinued...)"})
table.insert(plugins,{"migrants","multi race imigrations"}) table.insert(plugins,{"migrants","multi race imigrations"})
--]=] --]=]
table.insert(plugins,{"onfunction","run lua on some df function"}) --table.insert(plugins,{"onfunction","run lua on some df function"})
table.insert(plugins,{"editor","edit internals of df",EditDF}) --table.insert(plugins,{"editor","edit internals of df",EditDF})
table.insert(plugins,{"saves","run current worlds's init.lua",RunSaved}) table.insert(plugins,{"saves","run current worlds's init.lua",RunSaved})
loadall(plugins) loadall(plugins)
dofile_silent("dfusion/initcustom.lua") dofile_silent("dfusion/initcustom.lua")

@ -13,4 +13,4 @@ WorldData : 0x1306148
Xpointer : 0x7347f0 Xpointer : 0x7347f0
vtableLegends : 0x6e7594 vtableLegends : 0x6e7594
Buildings : 0x12C4DA8 Buildings : 0x12C4DA8
StartDwarfs : 0x5A5170 StartDwarfs : 0x5DA790

@ -260,6 +260,20 @@ function tools.changesite(names)
print(string.format("%x->%d",off,n2)) print(string.format("%x->%d",off,n2))
engine.poke(off,ptr_site.type,n2) engine.poke(off,ptr_site.type,n2)
end end
function tools.project(unit)
if unit==nil then
unit=getSelectedUnit()
end
if unit==nil then
unit=getCreatureAtPos(getxyz())
end
if unit==nil then
error("Failed to project unit. Unit not selected/valid")
end
-- todo: add projectile to world, point to unit, add flag to unit, add gen-ref to projectile.
end
function tools.empregnate(unit) function tools.empregnate(unit)
if unit==nil then if unit==nil then
unit=getSelectedUnit() unit=getSelectedUnit()
@ -270,25 +284,45 @@ function tools.empregnate(unit)
end end
if unit==nil then if unit==nil then
error("Failed to empregnate. Unit not selected/valide") error("Failed to empregnate. Unit not selected/valid")
end
if unit.curse then
unit.curse.add_tags2.STERILE=false
end end
local arr1=unit.appearance.unk_51c local arr1=unit.appearance.unk_51c
local arr2=unit.appearance.unk_51c local arr2=unit.appearance.unk_51c
local created=false local created=false
if unit.relations.pregnancy_ptr:tonumber()==0 then if unit.relations.pregnancy_ptr == nil then
print("creating preg ptr.") print("creating preg ptr.")
unit.relations.pregnancy_ptr:newref() if false then
created=true print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_ptr"))))
return
end end
local tarr1=unit.relations.pregnancy_ptr:deref().anon_1 local size,offset=df.sizeof(unit.relations:_field("pregnancy_ptr"))
local tarr2=unit.relations.pregnancy_ptr:deref().anon_2 local s1=df.sizeof(arr1)
if created or tarr1.size~= arr1.size then local s2=df.sizeof(arr2)
print("Setting up arr1") engine.poked(offset,engine.alloc(s1+s2))
initType(tarr1,arr1.size) created=true
end end
if created or tarr2.size~= arr2.size then local tarr1=unit.relations.pregnancy_ptr.anon_1
local tarr2=unit.relations.pregnancy_ptr.anon_2
if created or #tarr1~= #arr1 then
print(string.format("Before: %d vs %d",#tarr1,#arr1))
print("Setting up arr1") print("Setting up arr1")
initType(tarr2,arr2.size) print(string.format("%x %x",df.sizeof(tarr1)))
--tarr1=arr1:new()
local size,offset=df.sizeof(tarr1)
engine.poked(offset,engine.alloc(#arr1))
engine.poked(offset+4,#arr1)
print(string.format("after: %d vs %d",#tarr1,#arr1))
end
if created or #tarr2~= #arr2 then
print("Setting up arr2")
--tarr2=arr2:new()
local size,offset=df.sizeof(tarr2)
engine.poked(offset,engine.alloc(#arr2*2))
engine.poked(offset+4,#arr2)
end end
print("Setting preg timer.") print("Setting preg timer.")
unit.relations.pregnancy_timer=10 unit.relations.pregnancy_timer=10

@ -1,181 +0,0 @@
/*
** Lua BitOp -- a bit operations library for Lua 5.1.
** http://bitop.luajit.org/
**
** Copyright (C) 2008-2009 Mike Pall. All rights reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
** "Software"), to deal in the Software without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Software, and to
** permit persons to whom the Software is furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
*/
#include "bit.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
typedef int32_t SBits;
typedef uint32_t UBits;
typedef union {
lua_Number n;
#ifdef LUA_NUMBER_DOUBLE
uint64_t b;
#else
UBits b;
#endif
} BitNum;
/* Convert argument to bit type. */
static UBits barg(lua_State *L, int idx)
{
BitNum bn;
UBits b;
bn.n = lua_tonumber(L, idx);
#if defined(LUA_NUMBER_DOUBLE)
bn.n += 6755399441055744.0; /* 2^52+2^51 */
#ifdef SWAPPED_DOUBLE
b = (UBits)(bn.b >> 32);
#else
b = (UBits)bn.b;
#endif
#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \
defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \
defined(LUA_NUMBER_LLONG)
if (sizeof(UBits) == sizeof(lua_Number))
b = bn.b;
else
b = (UBits)(SBits)bn.n;
#elif defined(LUA_NUMBER_FLOAT)
#error "A 'float' lua_Number type is incompatible with this library"
#else
#error "Unknown number type, check LUA_NUMBER_* in luaconf.h"
#endif
if (b == 0 && !lua_isnumber(L, idx))
luaL_typerror(L, idx, "number");
return b;
}
/* Return bit type. */
#define BRET(b) lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1;
static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
#define BIT_OP(func, opr) \
static int func(lua_State *L) { int i; UBits b = barg(L, 1); \
for (i = lua_gettop(L); i > 1; i--) b opr barg(L, i); BRET(b) }
BIT_OP(bit_band, &=)
BIT_OP(bit_bor, |=)
BIT_OP(bit_bxor, ^=)
#define bshl(b, n) (b << n)
#define bshr(b, n) (b >> n)
#define bsar(b, n) ((SBits)b >> n)
#define brol(b, n) ((b << n) | (b >> (32-n)))
#define bror(b, n) ((b << (32-n)) | (b >> n))
#define BIT_SH(func, fn) \
static int func(lua_State *L) { \
UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) }
BIT_SH(bit_lshift, bshl)
BIT_SH(bit_rshift, bshr)
BIT_SH(bit_arshift, bsar)
BIT_SH(bit_rol, brol)
BIT_SH(bit_ror, bror)
static int bit_bswap(lua_State *L)
{
UBits b = barg(L, 1);
b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
BRET(b)
}
static int bit_tohex(lua_State *L)
{
UBits b = barg(L, 1);
SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
const char *hexdigits = "0123456789abcdef";
char buf[8];
int i;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;
for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
lua_pushlstring(L, buf, (size_t)n);
return 1;
}
static const struct luaL_Reg bit_funcs[] = {
{ "tobit", bit_tobit },
{ "bnot", bit_bnot },
{ "band", bit_band },
{ "bor", bit_bor },
{ "bxor", bit_bxor },
{ "lshift", bit_lshift },
{ "rshift", bit_rshift },
{ "arshift", bit_arshift },
{ "rol", bit_rol },
{ "ror", bit_ror },
{ "bswap", bit_bswap },
{ "tohex", bit_tohex },
{ NULL, NULL }
};
/* Signed right-shifts are implementation-defined per C89/C99.
** But the de facto standard are arithmetic right-shifts on two's
** complement CPUs. This behaviour is required here, so test for it.
*/
#define BAD_SAR (bsar(-8, 2) != (SBits)-2)
LUALIB_API int luaopen_bit(lua_State *L)
{
UBits b;
lua_pushnumber(L, (lua_Number)1437217655L);
b = barg(L, -1);
if (b != (UBits)1437217655L || BAD_SAR) { /* Perform a simple self-test. */
const char *msg = "compiled with incompatible luaconf.h";
#ifdef LUA_NUMBER_DOUBLE
#ifdef _WIN32
if (b == (UBits)1610612736L)
msg = "use D3DCREATE_FPU_PRESERVE with DirectX";
#endif
if (b == (UBits)1127743488L)
msg = "not compiled with SWAPPED_DOUBLE";
#endif
if (BAD_SAR)
msg = "arithmetic right-shift broken";
luaL_error(L, "bit library self-test failed (%s)", msg);
}
luaL_register(L, "bit", bit_funcs);
return 1;
}
#ifdef __cplusplus
}
#endif

@ -236,5 +236,4 @@ void lua::RegisterMisc(lua::state &st)
} }
lua::RegFunctionsLocal(st, lua_misc_func); lua::RegFunctionsLocal(st, lua_misc_func);
st.setglobal("engine"); st.setglobal("engine");
luaopen_bit(st);
} }

@ -96,7 +96,8 @@ const luaL_Reg lua_vinfo_func[]=
VI_FUNC(setAddress), VI_FUNC(setAddress),
VI_FUNC(getAddress), VI_FUNC(getAddress),
VI_FUNC(setOS), VI_FUNC(setOS),
VI_FUNC(getOS) VI_FUNC(getOS),
{NULL,NULL}
}; };
#undef VI_FUNC #undef VI_FUNC
void lua::RegisterVersionInfo(lua::state &st) void lua::RegisterVersionInfo(lua::state &st)

@ -55,8 +55,6 @@ DFHACK_PLUGIN("advtools");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
if (!ui_advmode) if (!ui_advmode)
return CR_OK; return CR_OK;

@ -300,7 +300,9 @@ struct labor_info
int minimum_dwarfs; int minimum_dwarfs;
}; };
static const struct labor_info labor_infos[] = { static struct labor_info* labor_infos;
static const struct labor_info default_labor_infos[] = {
/* MINE */ {AUTOMATIC, true, 2}, /* MINE */ {AUTOMATIC, true, 2},
/* HAUL_STONE */ {HAULERS, false, 1}, /* HAUL_STONE */ {HAULERS, false, 1},
/* HAUL_WOOD */ {HAULERS, false, 1}, /* HAUL_WOOD */ {HAULERS, false, 1},
@ -382,7 +384,7 @@ static const df::job_skill noble_skills[] = {
df::enums::job_skill::RECORD_KEEPING, df::enums::job_skill::RECORD_KEEPING,
}; };
struct dwarf_info struct dwarf_info_t
{ {
int highest_skill; int highest_skill;
int total_skill; int total_skill;
@ -395,10 +397,14 @@ struct dwarf_info
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
assert(ARRAY_COUNT(labor_infos) > ENUM_LAST_ITEM(unit_labor)); // initialize labor infos table from default table
if(ARRAY_COUNT(default_labor_infos) != ENUM_LAST_ITEM(unit_labor) + 1)
return CR_FAILURE;
labor_infos = new struct labor_info[ARRAY_COUNT(default_labor_infos)];
for (int i = 0; i < ARRAY_COUNT(default_labor_infos); i++) {
labor_infos[i] = default_labor_infos[i];
}
// Fill the command list with your commands. // Fill the command list with your commands.
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"autolabor", "Automatically manage dwarf labors.", "autolabor", "Automatically manage dwarf labors.",
autolabor, false, /* true means that the command can't be used from non-interactive user interface */ autolabor, false, /* true means that the command can't be used from non-interactive user interface */
@ -406,6 +412,8 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
" autolabor enable\n" " autolabor enable\n"
" autolabor disable\n" " autolabor disable\n"
" Enables or disables the plugin.\n" " Enables or disables the plugin.\n"
" autolabor miners <n>\n"
" Set number of desired miners (defaults to 2)\n"
"Function:\n" "Function:\n"
" When enabled, autolabor periodically checks your dwarves and enables or\n" " When enabled, autolabor periodically checks your dwarves and enables or\n"
" disables labors. It tries to keep as many dwarves as possible busy but\n" " disables labors. It tries to keep as many dwarves as possible busy but\n"
@ -418,9 +426,44 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
DFhackCExport command_result plugin_shutdown ( color_ostream &out ) DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{ {
// release the labor info table;
delete [] labor_infos;
return CR_OK; return CR_OK;
} }
// sorting objects
struct dwarfinfo_sorter
{
dwarfinfo_sorter(std::vector <dwarf_info_t> & info):dwarf_info(info){};
bool operator() (int i,int j)
{
if (dwarf_info[i].state == IDLE && dwarf_info[j].state != IDLE)
return true;
if (dwarf_info[i].state != IDLE && dwarf_info[j].state == IDLE)
return false;
return dwarf_info[i].mastery_penalty > dwarf_info[j].mastery_penalty;
};
std::vector <dwarf_info_t> & dwarf_info;
};
struct laborinfo_sorter
{
bool operator() (int i,int j)
{
return labor_infos[i].mode < labor_infos[j].mode;
};
};
struct values_sorter
{
values_sorter(std::vector <int> & values):values(values){};
bool operator() (int i,int j)
{
return values[i] > values[j];
};
std::vector<int> & values;
};
DFhackCExport command_result plugin_onupdate ( color_ostream &out ) DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{ {
static int step_count = 0; static int step_count = 0;
@ -468,7 +511,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
if (n_dwarfs == 0) if (n_dwarfs == 0)
return CR_OK; return CR_OK;
std::vector<dwarf_info> dwarf_info(n_dwarfs); std::vector<dwarf_info_t> dwarf_info(n_dwarfs);
std::vector<int> best_noble(ARRAY_COUNT(noble_skills)); std::vector<int> best_noble(ARRAY_COUNT(noble_skills));
std::vector<int> highest_noble_skill(ARRAY_COUNT(noble_skills)); std::vector<int> highest_noble_skill(ARRAY_COUNT(noble_skills));
@ -548,8 +591,10 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
if (labor == df::enums::unit_labor::NONE) if (labor == df::enums::unit_labor::NONE)
continue; continue;
/*
assert(labor >= 0); assert(labor >= 0);
assert(labor < ARRAY_COUNT(labor_infos)); assert(labor < ARRAY_COUNT(labor_infos));
*/
if (labor_infos[labor].is_exclusive && dwarfs[dwarf]->status.labors[labor]) if (labor_infos[labor].is_exclusive && dwarfs[dwarf]->status.labors[labor])
dwarf_info[dwarf].mastery_penalty -= 100; dwarf_info[dwarf].mastery_penalty -= 100;
@ -594,8 +639,10 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{ {
int job = dwarfs[dwarf]->job.current_job->job_type; int job = dwarfs[dwarf]->job.current_job->job_type;
/*
assert(job >= 0); assert(job >= 0);
assert(job < ARRAY_COUNT(dwarf_states)); assert(job < ARRAY_COUNT(dwarf_states));
*/
dwarf_info[dwarf].state = dwarf_states[job]; dwarf_info[dwarf].state = dwarf_states[job];
} }
@ -614,8 +661,10 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
int labor = ENUM_ATTR(job_skill, labor, skill); int labor = ENUM_ATTR(job_skill, labor, skill);
if (labor != df::enums::unit_labor::NONE) if (labor != df::enums::unit_labor::NONE)
{ {
/*
assert(labor >= 0); assert(labor >= 0);
assert(labor < ARRAY_COUNT(labor_to_skill)); assert(labor < ARRAY_COUNT(labor_to_skill));
*/
labor_to_skill[labor] = skill; labor_to_skill[labor] = skill;
} }
@ -628,13 +677,15 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
if (labor == df::enums::unit_labor::NONE) if (labor == df::enums::unit_labor::NONE)
continue; continue;
/*
assert(labor >= 0); assert(labor >= 0);
assert(labor < ARRAY_COUNT(labor_infos)); assert(labor < ARRAY_COUNT(labor_infos));
*/
labors.push_back(labor); labors.push_back(labor);
} }
laborinfo_sorter lasorter;
std::sort(labors.begin(), labors.end(), [] (int i, int j) { return labor_infos[i].mode < labor_infos[j].mode; }); std::sort(labors.begin(), labors.end(), lasorter);
// Handle all skills except those marked HAULERS // Handle all skills except those marked HAULERS
@ -642,8 +693,10 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{ {
auto labor = *lp; auto labor = *lp;
/*
assert(labor >= 0); assert(labor >= 0);
assert(labor < ARRAY_COUNT(labor_infos)); assert(labor < ARRAY_COUNT(labor_infos));
*/
df::job_skill skill = labor_to_skill[labor]; df::job_skill skill = labor_to_skill[labor];
@ -670,7 +723,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
if (labor_infos[labor].is_exclusive && dwarf_info[dwarf].has_exclusive_labor) if (labor_infos[labor].is_exclusive && dwarf_info[dwarf].has_exclusive_labor)
continue; continue;
int value = dwarf_info[dwarf].mastery_penalty - dwarf_info[dwarf].assigned_jobs; int value = dwarf_info[dwarf].mastery_penalty - dwarf_info[dwarf].assigned_jobs * 50;
if (skill != df::enums::job_skill::NONE) if (skill != df::enums::job_skill::NONE)
{ {
@ -724,7 +777,10 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
} }
if (labor_infos[labor].mode != EVERYONE) if (labor_infos[labor].mode != EVERYONE)
std::sort(candidates.begin(), candidates.end(), [&values] (int i, int j) { return values[i] > values[j]; }); {
values_sorter ivs(values);
std::sort(candidates.begin(), candidates.end(), ivs);
}
for (int dwarf = 0; dwarf < n_dwarfs; dwarf++) for (int dwarf = 0; dwarf < n_dwarfs; dwarf++)
{ {
@ -784,7 +840,11 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
dwarfs[dwarf]->status.labors[labor] = true; dwarfs[dwarf]->status.labors[labor] = true;
if (labor_infos[labor].is_exclusive) if (labor_infos[labor].is_exclusive)
{
dwarf_info[dwarf].has_exclusive_labor = true; dwarf_info[dwarf].has_exclusive_labor = true;
// all the exclusive labors require equipment so this should force the dorf to reequip if needed
dwarfs[dwarf]->military.pickup_flags.bits.update = 1;
}
} }
} }
@ -801,25 +861,24 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
if (dwarf_info[dwarf].state == IDLE || dwarf_info[dwarf].state == BUSY) if (dwarf_info[dwarf].state == IDLE || dwarf_info[dwarf].state == BUSY)
hauler_ids.push_back(dwarf); hauler_ids.push_back(dwarf);
} }
dwarfinfo_sorter sorter(dwarf_info);
// Idle dwarves come first, then we sort from least-skilled to most-skilled. // Idle dwarves come first, then we sort from least-skilled to most-skilled.
std::sort(hauler_ids.begin(), hauler_ids.end(), sorter);
std::sort(hauler_ids.begin(), hauler_ids.end(), [&dwarf_info] (int i, int j) -> bool // don't set any haulers if everyone is off drinking or something
{ if (hauler_ids.size() == 0) {
if (dwarf_info[i].state == IDLE && dwarf_info[j].state != IDLE) num_haulers = 0;
return true; }
if (dwarf_info[i].state != IDLE && dwarf_info[j].state == IDLE)
return false;
return dwarf_info[i].mastery_penalty > dwarf_info[j].mastery_penalty;
});
FOR_ENUM_ITEMS(unit_labor, labor) FOR_ENUM_ITEMS(unit_labor, labor)
{ {
if (labor == df::enums::unit_labor::NONE) if (labor == df::enums::unit_labor::NONE)
continue; continue;
/*
assert(labor >= 0); assert(labor >= 0);
assert(labor < ARRAY_COUNT(labor_infos)); assert(labor < ARRAY_COUNT(labor_infos));
*/
if (labor_infos[labor].mode != HAULERS) if (labor_infos[labor].mode != HAULERS)
continue; continue;
@ -832,7 +891,6 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
assert(dwarf >= 0); assert(dwarf >= 0);
assert(dwarf < n_dwarfs); assert(dwarf < n_dwarfs);
dwarfs[dwarf]->status.labors[labor] = true; dwarfs[dwarf]->status.labors[labor] = true;
dwarf_info[dwarf].assigned_jobs++; dwarf_info[dwarf].assigned_jobs++;
} }
@ -849,22 +907,32 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
dwarfs[dwarf]->status.labors[labor] = false; dwarfs[dwarf]->status.labors[labor] = false;
} }
} }
return CR_OK; return CR_OK;
} }
// A command! It sits around and looks pretty. And it's nice and friendly. // A command! It sits around and looks pretty. And it's nice and friendly.
command_result autolabor (color_ostream &out, std::vector <std::string> & parameters) command_result autolabor (color_ostream &out, std::vector <std::string> & parameters)
{ {
if (parameters.size() == 1 && (parameters[0] == "0" || parameters[0] == "1")) if (parameters.size() == 1 &&
(parameters[0] == "0" || parameters[0] == "enable" ||
parameters[0] == "1" || parameters[0] == "disable"))
{ {
if (parameters[0] == "0") if (parameters[0] == "0" || parameters[0] == "disable")
enable_autolabor = 0; enable_autolabor = 0;
else else
enable_autolabor = 1; enable_autolabor = 1;
out.print("autolabor %sactivated.\n", (enable_autolabor ? "" : "de")); out.print("autolabor %sactivated.\n", (enable_autolabor ? "" : "de"));
} }
else else if (parameters.size() == 2 && parameters[0] == "miners") {
int nminers = atoi (parameters[1].c_str());
if (nminers >= 0) {
labor_infos[0].minimum_dwarfs = nminers;
out.print("miner count set to %d.\n", nminers);
} else {
out.print("Syntax: autolabor miners <n>, where n is 0 or more.\n"
"Current miner count: %d\n", labor_infos[0].minimum_dwarfs);
}
} else
{ {
out.print("Automatically assigns labors to dwarves.\n" out.print("Automatically assigns labors to dwarves.\n"
"Activate with 'autolabor 1', deactivate with 'autolabor 0'.\n" "Activate with 'autolabor 1', deactivate with 'autolabor 0'.\n"

@ -0,0 +1,321 @@
// changeitem plugin
// allows to change the material type and quality of selected items
#include <iostream>
#include <iomanip>
#include <sstream>
#include <climits>
#include <vector>
#include <string>
#include <algorithm>
#include <set>
using namespace std;
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Maps.h"
#include "modules/Gui.h"
#include "modules/Items.h"
#include "modules/Materials.h"
#include "modules/MapCache.h"
#include "DataDefs.h"
#include "df/item.h"
#include "df/world.h"
#include "df/general_ref.h"
using namespace DFHack;
using namespace df::enums;
using MapExtras::Block;
using MapExtras::MapCache;
using df::global::world;
DFHACK_PLUGIN("changeitem");
command_result df_changeitem(color_ostream &out, vector <string> & parameters);
const string changeitem_help =
"Changeitem allows to change some item attributes.\n"
"By default the item currently selected in the UI will be changed\n"
"(you can select items in the 'k' list or inside containers/inventory).\n"
"By default change is only allowed if materials is of the same subtype\n"
"(for example wood<->wood, stone<->stone etc). But since some transformations\n"
"work pretty well and may be desired you can override this with 'force'.\n"
"Note that some attributes will not be touched, possibly resulting in weirdness.\n"
"To get an idea how the RAW id should look like, check some items with 'info'.\n"
"Using 'force' might create items which are not touched by crafters/haulers.\n"
"Options:\n"
" info - don't change anything, print some item info instead\n"
" here - change all items at cursor position\n"
" material, m - change material. must be followed by material RAW id\n"
" quality, q - change base quality. must be followed by number (0-5)\n"
" force - ignore subtypes, force change to new material.\n"
"Example:\n"
" changeitem m INORGANIC:GRANITE here\n"
" change material of all items under the cursor to granite\n"
" changeitem q 5\n"
" change currently selected item to masterpiece quality\n";
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(
"changeitem", "Change item attributes (material, quality).",
df_changeitem, false,
changeitem_help.c_str()
));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}
// probably there is some method in the library which does the same
// todo: look for it :)
string describeQuality(int q)
{
switch(q)
{
case 0:
return "Basic";
case 1:
return "-Well-crafted-";
case 2:
return "+Finely-crafted+";
case 3:
return "*Superior quality*";
case 4:
return "#Exceptional#";
case 5:
return "$Masterful$";
default:
return "!INVALID!";
}
}
command_result changeitem_execute(
color_ostream &out, df::item * item,
bool info, bool force,
bool change_material, string new_material,
bool change_quality, int new_quality);
command_result df_changeitem(color_ostream &out, vector <string> & parameters)
{
CoreSuspender suspend;
bool here = false;
bool info = false;
bool force = false;
bool change_material = false;
string new_material = "none";
bool change_quality = false;
int new_quality = 0;
for (size_t i = 0; i < parameters.size(); i++)
{
string & p = parameters[i];
if (p == "help" || p == "?")
{
out << changeitem_help << endl;
return CR_OK;
}
else if (p == "here")
{
here = true;
}
else if (p == "info")
{
info = true;
}
else if (p == "force")
{
force = true;
}
else if (p == "material" || p == "m" )
{
// must be followed by material RAW id
// (string like 'INORGANIC:GRANITE', 'PLANT:MAPLE:WOOD', ...)
if(i == parameters.size()-1)
{
out.printerr("no material specified!\n");
}
change_material = true;
new_material = parameters[i+1];
i++;
}
else if (p == "quality" || p == "q")
{
// must be followed by numeric quality (allowed: 0-5)
if(i == parameters.size()-1)
{
out.printerr("no quality specified!\n");
}
string & q = parameters[i+1];
// meh. should use a stringstream instead. but it's only 6 numbers
if(q == "0")
new_quality = 0;
else if(q == "1")
new_quality = 1;
else if(q == "2")
new_quality = 2;
else if(q == "3")
new_quality = 3;
else if(q == "4")
new_quality = 4;
else if(q == "5")
new_quality = 5;
else
{
out << "Invalid quality specified!" << endl;
return CR_WRONG_USAGE;
}
out << "change to quality: " << describeQuality(new_quality) << endl;
change_quality = true;
i++;
}
else
{
out << p << ": Unknown command!" << endl;
return CR_WRONG_USAGE;
}
}
if (!Maps::IsValid())
{
out.printerr("Map is not available!\n");
return CR_FAILURE;
}
MaterialInfo mat_new;
if (change_material && !mat_new.find(new_material))
{
out.printerr("No such material!\n");
return CR_FAILURE;
}
if (here)
{
int processed_total = 0;
int cx, cy, cz;
DFCoord pos_cursor;
// needs a cursor
if (!Gui::getCursorCoords(cx,cy,cz))
{
out.printerr("Cursor position not found. Please enable the cursor.\n");
return CR_FAILURE;
}
pos_cursor = DFCoord(cx,cy,cz);
// uh. is this check necessary?
// changeitem doesn't do stuff with map blocks...
{
MapCache MC;
Block * b = MC.BlockAt(pos_cursor / 16);
if(!b)
{
out.printerr("Cursor is in an invalid/uninitialized area. Place it over a floor.\n");
return CR_FAILURE;
}
// when only changing material it doesn't matter if cursor is over a tile
//df::tiletype ttype = MC.tiletypeAt(pos_cursor);
//if(!DFHack::isFloorTerrain(ttype))
//{
// out.printerr("Cursor should be placed over a floor.\n");
// return CR_FAILURE;
//}
}
// iterate over all items, process those where pos = pos_cursor
size_t numItems = world->items.all.size();
for(size_t i=0; i< numItems; i++)
{
df::item * item = world->items.all[i];
DFCoord pos_item(item->pos.x, item->pos.y, item->pos.z);
if (pos_item != pos_cursor)
continue;
changeitem_execute(out, item, info, force, change_material, new_material, change_quality, new_quality);
processed_total++;
}
out.print("Done. %d items processed.\n", processed_total);
}
else
{
// needs a selected item
df::item *item = Gui::getSelectedItem(out);
if (!item)
{
out.printerr("No item selected.\n");
return CR_FAILURE;
}
changeitem_execute(out, item, info, force, change_material, new_material, change_quality, new_quality);
}
return CR_OK;
}
command_result changeitem_execute(
color_ostream &out, df::item * item,
bool info, bool force,
bool change_material, string new_material,
bool change_quality, int new_quality )
{
MaterialInfo mat_new;
MaterialInfo mat_old;
if(change_material)
mat_new.find(new_material);
if(change_material || info)
mat_old.decode(item);
// print some info, don't change stuff
if(info)
{
out << "Item info: " << endl;
out << " quality: " << describeQuality(item->getQuality()) << endl;
//if(item->isImproved())
// out << " imp.quality: " << describeQuality(item->getImprovementQuality()) << endl;
out << " material: " << mat_old.getToken() << endl;
return CR_OK;
}
if(change_quality)
{
item->setQuality(new_quality);
// it would be nice to be able to change the improved quality, too
// (only allowed if the item is already improved)
// but there is no method in item.h which supports that
// ok: hints from _Q/angavrilov: improvent is a vector, an item can have more than one improvement
// -> virtual_cast to item_constructedst
}
if(change_material)
{
// subtype and mode should match to avoid doing dumb stuff like changing boulders into meat whatever
// changing a stone cabinet to wood is fine, though. as well as lots of other combinations.
// still, it's better to make the user activate 'force' if he really wants to.
if(force||(mat_old.subtype == mat_new.subtype && mat_old.mode==mat_new.mode))
{
item->setMaterial(mat_new.type);
item->setMaterialIndex(mat_new.index);
}
else
{
out.printerr("change denied: subtype doesn't match. use 'force' to override.\n");
}
item->flags.bits.temps_computed = 0; // recalc temperatures next time touched
item->flags.bits.weight_computed = 0; // recalc weight next time touched
}
return CR_OK;
}

@ -0,0 +1,397 @@
// changelayer plugin
// allows changing the material type of geological layers
// some headers required for a plugin. Nothing special, just the basics.
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
// DF data structure definition headers
#include "DataDefs.h"
#include "modules/Maps.h"
#include "modules/Materials.h"
#include "modules/MapCache.h"
#include "modules/Gui.h"
#include "TileTypes.h"
#include "df/world_data.h"
#include "df/world_geo_biome.h"
#include "df/world_geo_layer.h"
using namespace DFHack;
using namespace df::enums;
using namespace std;
using std::vector;
using std::string;
using df::global::world;
using df::global::cursor;
const string changelayer_help =
" Allows to change the material of whole geology layers.\n"
" Can have impact on all surrounding regions, not only your embark!\n"
" By default changing stone to soil and vice versa is not allowed.\n"
" By default changes only the layer at the cursor position.\n"
" Note that one layer can stretch across lots of z levels.\n"
" By default changes only the geology which is linked to the biome under the\n"
" cursor. That geology might be linked to other biomes as well, though.\n"
" Mineral veins and gem clusters will stay on the map.\n"
" Use 'changevein' for them.\n\n"
" tl;dr: You will end up with changing quite big areas in one go.\n\n"
"Options (first parameter MUST be the material id):\n"
" all_biomes - Change layer for all biomes on your map.\n"
" Result may be undesirable since the same layer\n"
" can AND WILL be on different z-levels for different biomes.\n"
" Use the tool 'probe' to get an idea how layers and biomes\n"
" are distributed on your map.\n"
" all_layers - Change all layers on your map.\n"
" Candy mountain, anyone?\n"
" Will make your map quite boring, but tidy.\n"
" force - Allow changing stone to soil and vice versa.\n"
" !!THIS CAN HAVE WEIRD EFFECTS, USE WITH CARE!!\n"
" Note that soil will not be magically replaced with stone.\n"
" You will, however, get a stone floor after digging so it\n"
" will allow the floor to be engraved.\n"
" Note that stone will not be magically replaced with soil.\n"
" You will, however, get a soil floor after digging so it\n"
" could be helpful for creating farm plots on maps with no soil.\n"
" verbose - Give some more details about what is being changed.\n"
" trouble - Give some advice for known problems.\n"
"Example:\n"
" changelayer GRANITE\n"
" Convert layer at cursor position into granite.\n"
" changelayer SILTY_CLAY force\n"
" Convert layer at cursor position into clay even if it's stone.\n"
" changelayer MARBLE allbiomes alllayers\n"
" Convert all layers of all biomes into marble.\n";
const string changelayer_trouble =
"Known problems with changelayer:\n\n"
" Nothing happens, the material stays the old.\n"
" Pause/unpause the game and/or move the cursor a bit. Then retry.\n"
" Try changing another layer, undo the changes and try again.\n"
" Try saving and loading the game.\n\n"
" Weird stuff happening after using the 'force' option.\n"
" Change former stone layers back to stone, soil back to soil.\n"
" If in doubt, use the 'probe' tool to find tiles with soil walls\n"
" and stone layer type or the other way round.\n";
command_result changelayer (color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("changelayer");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(
"changelayer", "Change a whole geology layer.",
changelayer, false, /* true means that the command can't be used from non-interactive user interface */
// Extended help string. Used by CR_WRONG_USAGE and the help command:
changelayer_help.c_str()
));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}
bool conversionAllowed(color_ostream &out, MaterialInfo mi, MaterialInfo ml, bool force);
// no need to spam the "stone to soil" warning more than once
// in case multiple biomes and/or layers are going to be changed
static bool warned = false;
command_result changelayer (color_ostream &out, std::vector <std::string> & parameters)
{
CoreSuspender suspend;
string material;
bool force = false;
bool all_biomes = false;
bool all_layers = false;
bool verbose = false;
warned = false;
for(size_t i = 0; i < parameters.size();i++)
{
if(parameters[i] == "help" || parameters[i] == "?")
{
out.print(changelayer_help.c_str());
return CR_OK;
}
if(parameters[i] == "trouble")
{
out.print(changelayer_trouble.c_str());
return CR_OK;
}
if(parameters[i] == "force")
force = true;
if(parameters[i] == "all_biomes")
all_biomes = true;
if(parameters[i] == "all_layers")
all_layers = true;
if(parameters[i] == "verbose")
verbose = true;
}
if (!Maps::IsValid())
{
out.printerr("Map is not available!\n");
return CR_FAILURE;
}
if (parameters.empty())
{
out.printerr("You need to specify a material!\n");
return CR_WRONG_USAGE;
}
material = parameters[0];
MaterialInfo mat_new;
if (!mat_new.findInorganic(material))
{
out.printerr("No such material!\n");
return CR_FAILURE;
}
// check if specified material is stone or gem or soil
if (mat_new.inorganic->material.flags.is_set(material_flags::IS_METAL) ||
mat_new.inorganic->material.flags.is_set(material_flags::NO_STONE_STOCKPILE))
{
out.printerr("Invalid material - you must select a type of stone or gem or soil.\n");
return CR_FAILURE;
}
MapExtras::MapCache mc;
int32_t regionX, regionY, regionZ;
Maps::getPosition(regionX,regionY,regionZ);
int32_t cursorX, cursorY, cursorZ;
Gui::getCursorCoords(cursorX,cursorY,cursorZ);
if(cursorX == -30000)
{
out.printerr("No cursor; place cursor over tile.\n");
return CR_FAILURE;
}
DFCoord cursor (cursorX,cursorY,cursorZ);
uint32_t blockX = cursorX / 16;
uint32_t tileX = cursorX % 16;
uint32_t blockY = cursorY / 16;
uint32_t tileY = cursorY % 16;
MapExtras::Block * b = mc.BlockAt(cursor/16);
if(!b && !b->valid)
{
out.printerr("No data.\n");
return CR_OK;
}
mapblock40d & block = b->raw;
df::tile_designation &des = block.designation[tileX][tileY];
// get biome and geolayer at cursor position
uint32_t biome = des.bits.biome;
uint32_t layer = des.bits.geolayer_index;
if(verbose)
{
out << "biome: " << biome << endl
<< "geolayer: " << layer << endl;
}
// there is no Maps::WriteGeology or whatever, and I didn't want to mess with the library and add it
// so I copied the stuff which reads the geology information and modified it to be able to change it
//
// a more elegant solution would probably look like this:
// 1) modify Maps::ReadGeology to accept and fill one more optional vector
// where the geolayer ids of the 9 biomes are stored
// 2) call ReadGeology here, modify the data in the vectors without having to do all that map stuff
// 3) write Maps::WriteGeology, pass the vectors, let it do it's work
// Step 1) is optional, but it would make implementing 3) easier.
// Otherwise that "check which geo_index is used by biome X" loop would need to be done again.
// no need to touch the same geology more than once
// though it wouldn't matter much since there is not much data to be processed
vector<uint16_t> v_geoprocessed;
v_geoprocessed.clear();
// iterate over 8 surrounding regions + local region
for (int i = eNorthWest; i < eBiomeCount; i++)
{
if(verbose)
out << "---Biome: " << i;
if(!all_biomes && i!=biome)
{
if(verbose)
out << "-skipping" << endl;
continue;
}
else
{
if(verbose)
out << "-checking" << endl;
}
// check against worldmap boundaries, fix if needed
// regionX is in embark squares
// regionX/16 is in 16x16 embark square regions
// i provides -1 .. +1 offset from the current region
int bioRX = world->map.region_x / 16 + ((i % 3) - 1);
if (bioRX < 0) bioRX = 0;
if (bioRX >= world->world_data->world_width) bioRX = world->world_data->world_width - 1;
int bioRY = world->map.region_y / 16 + ((i / 3) - 1);
if (bioRY < 0) bioRY = 0;
if (bioRY >= world->world_data->world_height) bioRY = world->world_data->world_height - 1;
// get index into geoblock vector
uint16_t geoindex = world->world_data->region_map[bioRX][bioRY].geo_index;
if(verbose)
out << "geoindex: " << geoindex << endl;
bool skip = false;
for(int g=0; g<v_geoprocessed.size(); g++)
{
if(v_geoprocessed.at(g)==geoindex)
{
if(verbose)
out << "already processed" << endl;
skip = true;
break;
}
}
if(skip)
continue;
v_geoprocessed.push_back(geoindex);
/// geology blocks have a vector of layer descriptors
// get the vector with pointer to layers
df::world_geo_biome *geo_biome = df::world_geo_biome::find(geoindex);
if (!geo_biome)
{
if(verbose)
out << "no geology found here." << endl;
continue;
}
vector <df::world_geo_layer*> &geolayers = geo_biome->layers;
// complain if layer is out of range
// geology has up to 16 layers currently, but can have less!
if(layer >= geolayers.size() || layer < 0)
{
if(verbose)
out << "layer out of range!";
continue;
}
// now let's actually write the new mat id to the layer(s)
if(all_layers)
{
for (size_t j = 0; j < geolayers.size(); j++)
{
MaterialInfo mat_old;
mat_old.decode(0, geolayers[j]->mat_index);
if(conversionAllowed(out, mat_new, mat_old, force))
{
if(verbose)
out << "changing geolayer " << j
<< " from " << mat_old.getToken()
<< " to " << mat_new.getToken()
<< endl;
geolayers[j]->mat_index = mat_new.index;
}
}
}
else
{
MaterialInfo mat_old;
mat_old.decode(0, geolayers[layer]->mat_index);
if(conversionAllowed(out, mat_new, mat_old, force))
{
if(verbose)
out << "changing geolayer " << layer
<< " from " << mat_old.getToken()
<< " to " << mat_new.getToken()
<< endl;
geolayers[layer]->mat_index = mat_new.index;
}
}
}
out.print("Done.\n");
// Give control back to DF.
return CR_OK;
}
// check if user tries to convert soil <-> stone
// throw some warning if he does
bool conversionAllowed(color_ostream &out, MaterialInfo mat_new, MaterialInfo mat_old, bool force)
{
// check if current layer mat is stone or soil:
// by default don't allow to turn stone to soil and vice versa
bool unsafe = false;
bool allowed = true;
// throw warning if user wants to change soil to stone or vice versa
// while it does work it might be unsafe and can have weird results
// you can't simply convert stone to soil, the rock walls will remain (same the other way round)
// the floor will turn into soil, though, so it might be useful for creating farm plots
// therefore it's not completely forbidden and can be enabled by the 'force' option
if ( mat_new.inorganic->flags.is_set(inorganic_flags::SOIL_ANY)
&& !mat_old.inorganic->flags.is_set(inorganic_flags::SOIL_ANY))
{
if(!warned)
{
out << "Changing a stone layer into soil is probably not wise." << endl
<< "The stone will remain and you get a soil floor after digging." << endl;
}
unsafe = true;
}
else if ( !mat_new.inorganic->flags.is_set(inorganic_flags::SOIL_ANY)
&& mat_old.inorganic->flags.is_set(inorganic_flags::SOIL_ANY))
{
if(!warned)
{
out << "Changing a soil layer into stone is probably not wise." << endl
<< "The soil will remain and you only get a stone floor after digging." << endl;
}
unsafe = true;
}
if(unsafe)
{
if(force)
{
if(!warned)
{
out << "You've been warned, good luck." << endl;
}
allowed = true;
}
else
{
if(!warned)
{
out << "Use the option 'force' if you REALLY want to do that." << endl
<< "Weird things can happen with your map, so save your game before trying!" << endl
<< "Example: 'changelayer GRANITE force'" << endl;
}
allowed = false;
}
// avoid multiple warnings for the same stuff
warned = true;
}
return allowed;
}

@ -11,7 +11,7 @@
// detail - print full name, date of birth, date of curse (vamp might use fake identity, though) // detail - print full name, date of birth, date of curse (vamp might use fake identity, though)
// show if the creature is active or dead, missing, ghostly (ghost vampires should not exist in 34.05) // show if the creature is active or dead, missing, ghostly (ghost vampires should not exist in 34.05)
// identify type of curse (works fine for vanilla ghosts, vamps, werebeasts, zombies and necromancers) // identify type of curse (works fine for vanilla ghosts, vamps, werebeasts, zombies and necromancers)
// nick - set nickname to 'CURSED' (does not always show up ingame, some vamps don't like nicknames) // nick - set nickname to type of curse(does not always show up ingame, some vamps don't like nicknames)
// all - don't ignore dead and inactive creatures (former ghosts, dead necromancers, ...) // all - don't ignore dead and inactive creatures (former ghosts, dead necromancers, ...)
// verbose - acts like detail but also lists all curse tags (if you want to know it all). // verbose - acts like detail but also lists all curse tags (if you want to know it all).
@ -57,7 +57,6 @@ DFHACK_PLUGIN("cursecheck");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand("cursecheck", commands.push_back(PluginCommand("cursecheck",
"Checks for cursed creatures (vampires, necromancers, zombies, ...).", "Checks for cursed creatures (vampires, necromancers, zombies, ...).",
cursecheck, false )); cursecheck, false ));
@ -125,13 +124,13 @@ void setUnitNickname(df::unit *unit, const std::string &nick)
} }
} }
void cursedump (color_ostream &out, df::unit * unit);
std::string determineCurse(df::unit * unit) std::string determineCurse(df::unit * unit)
{ {
string cursetype = "unknown"; string cursetype = "unknown";
// ghosts: ghostly, duh // ghosts: ghostly, duh
// as of DF 34.05 and higher vampire ghosts and the like should not be possible
// if they get reintroduced later it will become necessary to watch 'ghostly' seperately
if(unit->flags3.bits.ghostly) if(unit->flags3.bits.ghostly)
cursetype = "ghost"; cursetype = "ghost";
@ -287,7 +286,9 @@ command_result cursecheck (color_ostream &out, vector <string> & parameters)
// dump all curse flags on demand // dump all curse flags on demand
if (verbose) if (verbose)
{ {
cursedump(out, unit); out << "Curse flags: "
<< bitfield_to_string(unit->curse.add_tags1) << endl
<< bitfield_to_string(unit->curse.add_tags2) << endl;
} }
} }
} }
@ -300,73 +301,3 @@ command_result cursecheck (color_ostream &out, vector <string> & parameters)
return CR_OK; return CR_OK;
} }
void cursedump (color_ostream &out, df::unit * unit)
{
out << "Curse flags: ";
if(unit->curse.add_tags1.bits.BLOODSUCKER)
out << "bloodsucker ";
if(unit->curse.add_tags1.bits.EXTRAVISION)
out << "extravision ";
if(unit->curse.add_tags1.bits.OPPOSED_TO_LIFE)
out << "opposed_to_life ";
if(unit->curse.add_tags1.bits.NOT_LIVING)
out << "not_living ";
if(unit->curse.add_tags1.bits.NOEXERT)
out << "noexpert ";
if(unit->curse.add_tags1.bits.NOPAIN)
out << "nopain ";
if(unit->curse.add_tags1.bits.NOBREATHE)
out << "nobreathe ";
if(unit->curse.add_tags1.bits.HAS_BLOOD)
out << "has_blood ";
if(unit->curse.add_tags1.bits.NOSTUN)
out << "nostun ";
if(unit->curse.add_tags1.bits.NONAUSEA)
out << "nonausea ";
if(unit->curse.add_tags1.bits.NO_DIZZINESS)
out << "no_dizziness ";
if(unit->curse.add_tags1.bits.TRANCES)
out << "trances ";
if(unit->curse.add_tags1.bits.NOEMOTION)
out << "noemotion ";
if(unit->curse.add_tags1.bits.PARALYZEIMMUNE)
out << "paralyzeimmune ";
if(unit->curse.add_tags1.bits.NOFEAR)
out << "nofear ";
if(unit->curse.add_tags1.bits.NO_EAT)
out << "no_eat ";
if(unit->curse.add_tags1.bits.NO_DRINK)
out << "no_drink ";
if(unit->curse.add_tags1.bits.MISCHIEVOUS)
out << "mischievous ";
if(unit->curse.add_tags1.bits.NO_PHYS_ATT_GAIN)
out << "no_phys_att_gain ";
if(unit->curse.add_tags1.bits.NO_PHYS_ATT_RUST)
out << "no_phys_att_rust ";
if(unit->curse.add_tags1.bits.NOTHOUGHT)
out << "nothought ";
if(unit->curse.add_tags1.bits.NO_THOUGHT_CENTER_FOR_MOVEMENT)
out << "no_thought_center_for_movement ";
if(unit->curse.add_tags1.bits.CAN_SPEAK)
out << "can_speak ";
if(unit->curse.add_tags1.bits.CAN_LEARN)
out << "can_learn ";
if(unit->curse.add_tags1.bits.CRAZED)
out << "crazed ";
if(unit->curse.add_tags1.bits.BLOODSUCKER)
out << "bloodsucker ";
if(unit->curse.add_tags1.bits.SUPERNATURAL)
out << "supernatural ";
if(unit->curse.add_tags2.bits.NO_AGING)
out << "no_aging ";
if(unit->curse.add_tags2.bits.STERILE)
out << "sterile ";
if(unit->curse.add_tags2.bits.FIT_FOR_ANIMATION)
out << "fit_for_animation ";
if(unit->curse.add_tags2.bits.FIT_FOR_RESURRECTION)
out << "fit_for_resurrection ";
out << endl << endl;
}

@ -56,7 +56,6 @@ DFHACK_PLUGIN("regrass");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand("regrass", "Regrows all surface grass, restoring outdoor plant growth for pre-0.31.19 worlds.", df_regrass)); commands.push_back(PluginCommand("regrass", "Regrows all surface grass, restoring outdoor plant growth for pre-0.31.19 worlds.", df_regrass));
return CR_OK; return CR_OK;
} }

@ -96,7 +96,6 @@ DFHACK_PLUGIN("feature");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"feature", "List or manage map features.", feature, false, "feature", "List or manage map features.", feature, false,
" feature list\n" " feature list\n"

@ -57,7 +57,6 @@ DFHACK_PLUGIN("liquids");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
liquids_hist.load("liquids.history"); liquids_hist.load("liquids.history");
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"liquids", "Place magma, water or obsidian.", "liquids", "Place magma, water or obsidian.",
df_liquids, true)); // interactive, needs console for prompt df_liquids, true)); // interactive, needs console for prompt

@ -30,7 +30,6 @@ DFHACK_PLUGIN("mapexport");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
commands.clear();
commands.push_back(PluginCommand("mapexport", "Exports the current map to a file.", mapexport, true)); commands.push_back(PluginCommand("mapexport", "Exports the current map to a file.", mapexport, true));
return CR_OK; return CR_OK;
} }

@ -18,7 +18,6 @@ DFHACK_PLUGIN("mode");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"mode","View, change and track game mode.", "mode","View, change and track game mode.",
mode, true, mode, true,
@ -96,7 +95,8 @@ void printCurrentModes(t_gamemodes gm, Console & con)
command_result mode (color_ostream &out_, vector <string> & parameters) command_result mode (color_ostream &out_, vector <string> & parameters)
{ {
assert(out_.is_console()); if(!out_.is_console())
return CR_FAILURE;
Console &out = static_cast<Console&>(out_); Console &out = static_cast<Console&>(out_);
string command = ""; string command = "";

@ -28,7 +28,6 @@ DFHACK_PLUGIN("plants");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand("grow", "Grows saplings into trees (with active cursor, only the targetted one).", df_grow)); commands.push_back(PluginCommand("grow", "Grows saplings into trees (with active cursor, only the targetted one).", df_grow));
commands.push_back(PluginCommand("immolate", "Set plants on fire (under cursor, 'shrubs', 'trees' or 'all').", df_immolate)); commands.push_back(PluginCommand("immolate", "Set plants on fire (under cursor, 'shrubs', 'trees' or 'all').", df_immolate));
commands.push_back(PluginCommand("extirpate", "Kill plants (same mechanics as immolate).", df_extirpate)); commands.push_back(PluginCommand("extirpate", "Kill plants (same mechanics as immolate).", df_extirpate));

@ -41,7 +41,6 @@ DFHACK_PLUGIN("probe");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand("probe", commands.push_back(PluginCommand("probe",
"A tile probe", "A tile probe",
df_probe)); df_probe));

@ -195,7 +195,6 @@ DFHACK_PLUGIN("prospector");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"prospect", "Show stats of available raw resources.", "prospect", "Show stats of available raw resources.",
prospector, false, prospector, false,

@ -1,42 +0,0 @@
find_package(Qt4 QUIET)
find_package(OpenGL QUIET)
if(QT4_FOUND AND OPENGL_FOUND AND OPENGL_GLU_FOUND)
IF(QT_VERSION_MAJOR MATCHES 4 AND QT_VERSION_MINOR GREATER 6)
set( QT_USE_QTGUI TRUE )
set( QT_USE_QTOPENGL TRUE )
INCLUDE( ${QT_USE_FILE} )
include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} "${dfhack_SOURCE_DIR}/library/depends/tthread")
set ( qtplug_SRCS
qtplug.cpp
blankslade.cpp
glwidget.cpp
${dfhack_SOURCE_DIR}/library/depends/tthread/tinythread.cpp
)
SET ( qtplug_UI
gui/main.ui
)
SET( qtplug_RCS
gui/resources.qrc
)
# this command will generate rules that will run rcc on all files from blankslade_RCS
# in result blankslade_RC_SRCS variable will contain paths to files produced by rcc
QT4_ADD_RESOURCES( qtplug_RC_SRCS ${qtplug_RCS} )
QT4_WRAP_UI(qtplug_UI_h ${qtplug_UI})
qt4_automoc(${qtplug_SRCS})
DFHACK_PLUGIN(qtplug ${qtplug_SRCS} ${qtplug_RC_SRCS} ${qtplug_UI_h})
# a small texture file
install(FILES terrain.png DESTINATION ${DFHACK_LIBRARY_DESTINATION})
target_link_libraries(qtplug ${OPENGL_LIBRARIES} ${QT_LIBRARIES} )
ELSE(QT_VERSION_MAJOR MATCHES 4 AND QT_VERSION_MINOR GREATER 6)
MESSAGE(STATUS "Can't build the Qt plugin. Your Qt is too old.")
ENDIF(QT_VERSION_MAJOR MATCHES 4 AND QT_VERSION_MINOR GREATER 6)
else(QT4_FOUND AND OPENGL_FOUND AND OPENGL_GLU_FOUND)
MESSAGE(STATUS "Required libraries (Qt, GL, GLU) not found - Qt plugin can't be built.")
endif(QT4_FOUND AND OPENGL_FOUND AND OPENGL_GLU_FOUND)

@ -1,98 +0,0 @@
/*
* Copyright (c) 2010 Petr Mrázek (peterix)
* See LICENSE for details.
*/
#include "blankslade.h"
#include <QFileDialog>
#include <QDebug>
#include "glwidget.h"
blankslade::blankslade(QWidget *parent): QMainWindow(parent)
{
ui.setupUi(this);
GLWidget * glw = new GLWidget();
ui.gridding->addWidget(glw);
connect(ui.actionOpen,SIGNAL(triggered(bool)),this,SLOT(slotOpen(bool)));
connect(ui.actionQuit,SIGNAL(triggered(bool)),this,SLOT(slotQuit(bool)));
connect(ui.actionSave,SIGNAL(triggered(bool)),this,SLOT(slotSave(bool)));
connect(ui.actionSave_As,SIGNAL(triggered(bool)),this,SLOT(slotSaveAs(bool)));
ui.actionOpen->setIcon(QIcon::fromTheme("document-open"));
ui.actionOpen->setIconText(tr("Open"));
ui.actionSave->setIcon(QIcon::fromTheme("document-save"));
ui.actionSave->setIconText(tr("Save"));
ui.actionSave_As->setIcon(QIcon::fromTheme("document-save-as"));
ui.actionSave_As->setIconText(tr("Save As"));
ui.actionQuit->setIcon(QIcon::fromTheme("application-exit"));
ui.actionQuit->setIconText(tr("Run DF"));
}
blankslade::~blankslade()
{}
void blankslade::slotOpen(bool )
{
/*
QFileDialog fd(this,tr("Locate the Memoxy.xml file"));
fd.setNameFilter(tr("Memory definition (*.xml)"));
fd.setFileMode(QFileDialog::ExistingFile);
fd.setAcceptMode(QFileDialog::AcceptOpen);
int result = fd.exec();
if(result == QDialog::Accepted)
{
QStringList files = fd.selectedFiles();
QString fileName = files[0];
QDomDocument doc("memxml");
QFile file(fileName);
if(!file.open(QIODevice::ReadOnly))
{
return;
}
if(!doc.setContent(&file))
{
file.close();
return;
}
mod = new MemXMLModel(doc,this);
ui.entryView->setModel(mod);
file.close();
}
*/
}
void blankslade::slotQuit(bool )
{
close();
}
void blankslade::slotSave(bool )
{
// blah
}
void blankslade::slotRunDF(bool )
{
// blah
}
void blankslade::slotSaveAs(bool )
{
QFileDialog fd(this,tr("Choose file to save as..."));
fd.setNameFilter(tr("Memory definition (*.xml)"));
fd.setFileMode(QFileDialog::AnyFile);
fd.selectFile("Memory.xml");
fd.setAcceptMode(QFileDialog::AcceptSave);
int result = fd.exec();
if(result == QDialog::Accepted)
{
QStringList files = fd.selectedFiles();
QString file = files[0];
qDebug() << "File:" << file;
}
}
void blankslade::slotSetupDFs(bool )
{
}
#include "blankslade.moc"

@ -1,29 +0,0 @@
/*
* Copyright (c) 2010 Petr Mrázek (peterix)
* See LICENSE for details.
*/
#ifndef blankslade_H
#define blankslade_H
#include <QtGui/QMainWindow>
#include "ui_main.h"
class blankslade : public QMainWindow
{
Q_OBJECT
public:
blankslade(QWidget *parent = 0);
virtual ~blankslade();
private:
Ui::MainWindow ui;
public slots:
void slotOpen(bool);
void slotQuit(bool);
void slotSave(bool);
void slotSaveAs(bool);
void slotRunDF(bool);
void slotSetupDFs(bool);
};
#endif // blankslade_H

@ -1,246 +0,0 @@
/*
* Copyright (c) 2010 Petr Mrázek (peterix)
* See LICENSE for details.
*/
#include "glwidget.h"
#include <QtOpenGL>
#include <QGLBuffer>
#include <QGLShaderProgram>
#include <QGLPixelBuffer>
#include <iostream>
#include <GL/gl.h>
struct Vertex
{
float texcoord[2];
float color[3];
float position[3];
};
#define FRS 0.0625
#define FRX FRS/2
// this is crap
const Vertex house_vert[] =
{
// walls
{ { 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, { -4.0, -4.0, -4.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 0.0 }, { -4.0, -4.0, 4.0 } },
{ { FRS, FRS }, { 0.0, 1.0, 1.0 }, { 4.0, -4.0, 4.0 } },
{ { FRS, 0.0 }, { 1.0, 0.0, 0.0 }, { 4.0, -4.0, -4.0 } },
{ { 0.0, 0.0 }, { 1.0, 0.0, 1.0 }, { -4.0, 4.0, -4.0 } },
{ { 0.0, FRS }, { 1.0, 1.0, 0.0 }, { -4.0, 4.0, 4.0 } },
{ { FRS, FRS }, { 1.0, 1.0, 1.0 }, { 4.0, 4.0, 4.0 } },
{ { FRS, 0.0 }, { 0.0, 0.0, 1.0 }, { 4.0, 4.0, -4.0 } },
{ { 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { -4.0, -4.0, -4.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 1.0 }, { -4.0, -4.0, 4.0 } },
{ { FRS, FRS }, { 1.0, 0.0, 0.0 }, { -4.0, 4.0, 4.0 } },
{ { FRS, 0.0 }, { 1.0, 0.0, 1.0 }, { -4.0, 4.0, -4.0 } },
{ { 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 4.0, -4.0, -4.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 1.0 }, { 4.0, -4.0, 4.0 } },
{ { FRS, FRS }, { 1.0, 0.0, 0.0 }, { 4.0, 4.0, 4.0 } },
{ { FRS, 0.0 }, { 1.0, 0.0, 1.0 }, { 4.0, 4.0, -4.0 } },
// roof
{ { 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, { -4.0, 4.0, -4.0 } },
{ { FRS, 0.0 }, { 0.0, 1.0, 1.0 }, { 4.0, 4.0, -4.0 } },
{ { FRX, FRX }, { 1.0, 1.0, 1.0 }, { 0.0, 9.0, 0.0 } },
{ { FRS, 0.0 }, { 1.0, 0.0, 0.0 }, { 4.0, 4.0, -4.0 } },
{ { FRS, FRS }, { 1.0, 1.0, 0.0 }, { 4.0, 4.0, 4.0 } },
{ { FRX, FRX }, { 1.0, 1.0, 1.0 }, { 0.0, 9.0, 0.0 } },
{ { FRS, FRS }, { 0.0, 1.0, 0.0 }, { 4.0, 4.0, 4.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 1.0 }, { -4.0, 4.0, 4.0 } },
{ { FRX, FRX }, { 1.0, 1.0, 1.0 }, { 0.0, 9.0, 0.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 0.0 }, { -4.0, 4.0, 4.0 } },
{ { 0.0, 0.0 }, { 1.0, 1.0, 0.0 }, { -4.0, 4.0, -4.0 } },
{ { FRX, FRX }, { 1.0, 1.0, 1.0 }, { 0.0, 9.0, 0.0 } }
};
const unsigned char house_idx[] =
{
// walls
0, 1, 2, 0, 2, 3,
4, 5, 6, 4, 6, 7,
8, 9, 10, 8, 10, 11,
12, 13, 14, 12, 14, 15,
// roof
16, 17, 18,
19, 20, 21,
22, 23, 24,
25, 26, 27
};
class GLWPrivate
{
public:
QGLBuffer *VBO;
QGLBuffer *EBO;
QGLShaderProgram prog;
int positionAttrib;
int colorAttrib;
int texcoordsAttrib;
int mvpUniform;
int textureUniform;
int terrain;
float pz,rx,ry;
QPoint lastMouse;
};
GLWidget::GLWidget()
{
d = new GLWPrivate;
d->pz = -140.0f;
d->rx = d->ry = 0.0f;
d->VBO = d->EBO = 0;
startTimer( 10 );
}
GLWidget::~GLWidget()
{
if(d->VBO) delete d->VBO;
if(d->EBO) delete d->EBO;
delete d;
}
const char * VS_src =
"#version 130\n"
"in vec3 position; in vec3 color; uniform mat4 mvp; out vec3 c;"
"in vec2 tc_in; out vec2 coord;"
"void main()"
"{"
"gl_Position = mvp*vec4(position,1);"
"c = color;"
"coord = tc_in;"
"}";
const char * FS_src =
"#version 130\n"
"in vec3 c;"
//"out vec4 gl_FragColor;"
"in vec2 coord; uniform sampler2D tex;"
"void main()"
"{"
// "gl_FragColor = vec4(c,1);"
// "gl_FragColor = mix( texture(tex, coord), vec4(c,1), 0.5);"
// "gl_FragColor = vec4(c,1) - texture(tex, coord);"
"gl_FragColor = vec4(c,1) * texture(tex, coord);"
"}";
//initialization of OpenGL
void GLWidget::initializeGL()
{
bool test = 1;
test &= d->prog.addShaderFromSourceCode(QGLShader::Vertex,VS_src);
test &= d->prog.addShaderFromSourceCode(QGLShader::Fragment,FS_src);
test &= d->prog.link();
if(!test)
std::cout << "OUCH!" << std::endl;
d->positionAttrib = d->prog.attributeLocation("position");
d->colorAttrib = d->prog.attributeLocation("color");
d->texcoordsAttrib = d->prog.attributeLocation("tc_in");
d->mvpUniform = d->prog.uniformLocation("mvp");
d->textureUniform = d->prog.uniformLocation("tex");
if(d->positionAttrib == -1 || d->colorAttrib == -1 || d->mvpUniform == -1)
std::cout << "Bad attribs!" << std::endl;
QGLBuffer &VBO = *(d->VBO = new QGLBuffer(QGLBuffer::VertexBuffer));
VBO.create();
VBO.bind();
VBO.allocate(sizeof(house_vert));
VBO.write(0,house_vert,sizeof(house_vert));
QGLBuffer &EBO = *(d->EBO = new QGLBuffer(QGLBuffer::IndexBuffer));
EBO.create();
EBO.bind();
EBO.allocate(sizeof(house_idx));
EBO.write(0,house_idx,sizeof(house_idx));
QImage texture;
texture.load("terrain.png");
d->terrain = bindTexture(texture);
glClearColor(0.0f, 0.0f, 0.0f, 0.f);
glShadeModel( GL_SMOOTH );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
glEnable( GL_TEXTURE_2D );
glEnable( GL_DEPTH_TEST );
}
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d->prog.bind();
QMatrix4x4 projection;
QMatrix4x4 mvp;
//projection.ortho(-10,10,-10,10,1,1000);
float aspect = (float)width()/(float)height();
projection.perspective(10,aspect,1,1000);
mvp = projection;
mvp.translate(0,0,d->pz);
mvp.rotate(d->ry,1,0,0);
mvp.rotate(d->rx,0,1,0);
d->prog.setUniformValue(d->mvpUniform,mvp);
//glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, d->terrain);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
d->prog.setUniformValue(d->textureUniform,0);
d->prog.enableAttributeArray(d->positionAttrib);
d->prog.enableAttributeArray(d->colorAttrib);
d->prog.enableAttributeArray(d->texcoordsAttrib);
d->VBO->bind();
d->prog.setAttributeBuffer(d->texcoordsAttrib, GL_FLOAT, offsetof(Vertex, texcoord), 2, sizeof(Vertex));
d->prog.setAttributeBuffer(d->positionAttrib, GL_FLOAT, offsetof(Vertex, position), 3, sizeof(Vertex));
d->prog.setAttributeBuffer(d->colorAttrib, GL_FLOAT, offsetof(Vertex, color), 3, sizeof(Vertex));
d->EBO->bind();
glDrawElements(GL_TRIANGLES, d->EBO->size(), GL_UNSIGNED_BYTE, NULL);
d->prog.release();
}
void GLWidget::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
}
void GLWidget::mousePressEvent(QMouseEvent *event)
{
d->lastMouse = event->pos();
}
void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
int dx = event->x() - d->lastMouse.x();
int dy = event->y() - d->lastMouse.y();
if (event->buttons() & Qt::LeftButton)
{
d->rx = d->rx + dx;
d->ry = d->ry + dy;
}
d->lastMouse = event->pos();
}
void GLWidget::timerEvent(QTimerEvent *event)
{
updateGL();
}

@ -1,32 +0,0 @@
/*
* Copyright (c) 2010 Petr Mrázek (peterix)
* See LICENSE for details.
*/
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QGLWidget>
class GLWPrivate;
class GLWidget : public QGLWidget
{
public:
GLWidget();
~GLWidget();
float rot;
void resizeGL(int width, int height);
protected:
void initializeGL();
void paintGL();
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void timerEvent(QTimerEvent *event);
private:
GLWPrivate * d;
};
#endif // GLWIDGET_H

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

@ -1,361 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>662</width>
<height>836</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="windowIcon">
<iconset resource="resources.qrc">
<normaloff>:/main_icon/main_64.png</normaloff>:/main_icon/main_64.png</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridding">
<property name="margin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="scene_dock">
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="allowedAreas">
<set>Qt::RightDockWidgetArea</set>
</property>
<property name="windowTitle">
<string>Scéna</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_2">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Exponent n</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSlider" name="slideExponentN">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="spinExponentN"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Exponent e</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QSlider" name="slideExponentE">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="spinExponentE"/>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QDial" name="dialLight"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Světlo</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Objekt</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDial" name="dial_2"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Textura</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>96</width>
<height>96</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/blah/tileable.jpg</normaloff>:/blah/tileable.jpg</iconset>
</property>
<property name="iconSize">
<size>
<width>80</width>
<height>80</height>
</size>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Render</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
<zorder>pushButton_2</zorder>
<zorder>verticalLayoutWidget</zorder>
<zorder>pushButton</zorder>
<zorder>gridLayoutWidget</zorder>
</widget>
</widget>
<widget class="QDockWidget" name="dock_example">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="allowedAreas">
<set>Qt::BottomDockWidgetArea|Qt::LeftDockWidgetArea|Qt::TopDockWidgetArea</set>
</property>
<property name="windowTitle">
<string>Ukázky</string>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_3">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QListWidget" name="listWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="movement">
<enum>QListView::Static</enum>
</property>
<property name="flow">
<enum>QListView::TopToBottom</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>true</bool>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="layoutMode">
<enum>QListView::SinglePass</enum>
</property>
<property name="spacing">
<number>10</number>
</property>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
<property name="uniformItemSizes">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="selectionRectVisible">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
<item>
<property name="text">
<string>Koule</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/blah/koule.png</normaloff>:/blah/koule.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>Krychle</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/blah/krychle.png</normaloff>:/blah/krychle.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>Válec</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/blah/valec.png</normaloff>:/blah/valec.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>Diamant</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/blah/diamant.png</normaloff>:/blah/diamant.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>a=3,b=3</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/blah/33.png</normaloff>:/blah/33.png</iconset>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="actionOpen">
<property name="text">
<string>Open</string>
</property>
</action>
<action name="actionSave">
<property name="text">
<string>Save</string>
</property>
</action>
<action name="actionSave_As">
<property name="text">
<string>Save As</string>
</property>
</action>
<action name="actionQuit">
<property name="text">
<string>Quit</string>
</property>
</action>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

@ -1,15 +0,0 @@
<RCC>
<qresource prefix="main_icon">
<file>main_64.png</file>
<file>main_16.png</file>
<file>main_32.png</file>
</qresource>
<qresource prefix="blah">
<file>tileable.jpg</file>
<file>33.png</file>
<file>diamant.png</file>
<file>koule.png</file>
<file>krychle.png</file>
<file>valec.png</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

@ -1,69 +0,0 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
#include <modules/Gui.h>
//#include <extra/MapExtras.h>
#include <vector>
#include <cstdio>
#include <stack>
#include <string>
#include <QtGui/QApplication>
#include "blankslade.h"
#include "tinythread.h"
using std::vector;
using std::string;
using std::stack;
using namespace DFHack;
static void runnable(void *);
static tthread::mutex * instance_mutex = 0;
static bool running = false;
static tthread::thread * QTThread;
command_result runqt (Core * c, vector <string> & parameters);
DFHACK_PLUGIN("qtplug");
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
instance_mutex = new tthread::mutex();
commands.clear();
commands.push_back(PluginCommand("runqt","Open an interactive Qt gui.",runqt));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_FAILURE;
}
command_result runqt (Core * c, vector <string> & parameters)
{
instance_mutex->lock();
if(!running)
{
running = true;
QTThread = new tthread::thread(runnable, 0);
}
else
{
c->con.printerr("The Qt test plugin is already running!\n");
}
instance_mutex->unlock();
return CR_OK;
}
static void runnable(void *)
{
int zero = 0;
QApplication app(zero, 0);
blankslade appGui;
appGui.show();
app.exec();
instance_mutex->lock();
running = false;
instance_mutex->unlock();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

@ -38,7 +38,6 @@ DFHACK_PLUGIN("rename");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
if (world && ui) { if (world && ui) {
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"rename", "Rename various things.", rename, false, "rename", "Rename various things.", rename, false,

@ -76,7 +76,6 @@ DFHACK_PLUGIN("reveal");
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand("reveal","Reveal the map. 'reveal hell' will also reveal hell. 'reveal demon' won't pause.",reveal)); commands.push_back(PluginCommand("reveal","Reveal the map. 'reveal hell' will also reveal hell. 'reveal demon' won't pause.",reveal));
commands.push_back(PluginCommand("unreveal","Revert the map to its previous state.",unreveal)); commands.push_back(PluginCommand("unreveal","Revert the map to its previous state.",unreveal));
commands.push_back(PluginCommand("revtoggle","Reveal/unreveal depending on state.",revtoggle)); commands.push_back(PluginCommand("revtoggle","Reveal/unreveal depending on state.",revtoggle));

@ -243,7 +243,6 @@ DFHACK_PLUGIN("seedwatch");
DFhackCExport command_result plugin_init(color_ostream &out, vector<PluginCommand>& commands) DFhackCExport command_result plugin_init(color_ostream &out, vector<PluginCommand>& commands)
{ {
commands.clear();
commands.push_back(PluginCommand("seedwatch", "Switches cookery based on quantity of seeds, to keep reserves", df_seedwatch)); commands.push_back(PluginCommand("seedwatch", "Switches cookery based on quantity of seeds, to keep reserves", df_seedwatch));
// fill in the abbreviations map, with abbreviations for the standard plants // fill in the abbreviations map, with abbreviations for the standard plants
abbreviations["bs"] = "SLIVER_BARB"; abbreviations["bs"] = "SLIVER_BARB";

@ -1,42 +0,0 @@
PROJECT (server)
SET(PROJECT_SRCS
main.cpp
)
include_directories( ${CMAKE_SOURCE_DIR} )
IF(UNIX)
OPTION(SERVER_INTERNAL_SO "Link with prebuilt internal zeromq lib and headers." ON)
IF(SERVER_INTERNAL_SO)
SET(PROJECT_LIBS
${server_SOURCE_DIR}/zeromq/libzmq.so.1
${PROJECT_LIBS}
)
include_directories (
${include_directories}
${server_SOURCE_DIR}/zeromq
)
install(PROGRAMS ${server_SOURCE_DIR}/zeromq/libzmq.so.1 DESTINATION ${DFHACK_LIBRARY_DESTINATION})
ELSE()
SET(PROJECT_LIBS
zmq
${PROJECT_LIBS}
)
ENDIF()
ELSE()
SET(PROJECT_LIBS
${server_SOURCE_DIR}/zeromq/libzmq.lib
${PROJECT_LIBS}
)
include_directories (
${include_directories}
${server_SOURCE_DIR}/zeromq
)
install(PROGRAMS ${server_SOURCE_DIR}/zeromq/libzmq.dll DESTINATION ${DFHACK_LIBRARY_DESTINATION})
ENDIF()
DFHACK_PLUGIN(server ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS})
add_executable ( helloclient hello.cpp )
target_link_libraries ( helloclient ${PROJECT_LIBS})
install(TARGETS helloclient RUNTIME DESTINATION . )

@ -1,39 +0,0 @@
//
// Hello World client
// Connects REQ socket to tcp://localhost:5555
// Sends "Hello" to server, expects "World" back
//
#include <zmq.h>
#include <string.h>
#include <stdio.h>
//#include <unistd.h>
int main (void)
{
void *context = zmq_init (1);
// Socket to talk to server
printf ("Connecting to hello world server...\n");
void *requester = zmq_socket (context, ZMQ_REQ);
zmq_connect (requester, "tcp://localhost:5555");
int request_nbr;
for (request_nbr = 0; request_nbr != 10; request_nbr++)
{
zmq_msg_t request;
zmq_msg_init_size (&request, 5);
memcpy (zmq_msg_data (&request), "Hello", 5);
printf ("Sending Hello %d...\n", request_nbr);
zmq_send (requester, &request, 0);
zmq_msg_close (&request);
zmq_msg_t reply;
zmq_msg_init (&reply);
zmq_recv (requester, &reply, 0);
printf ("Received World %d\n", request_nbr);
zmq_msg_close (&reply);
}
zmq_close (requester);
zmq_term (context);
return 0;
}

@ -1,79 +0,0 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <zmq.hpp>
#ifndef LINUX_BUILD
#include <windows.h>
#endif
using namespace DFHack;
// Here go all the command declarations...
// mostly to allow having the mandatory stuff on top of the file and commands on the bottom
command_result server (color_ostream &out, std::vector <std::string> & parameters);
// A plugins must be able to return its name. This must correspond to the filename - skeleton.plug.so or skeleton.plug.dll
DFHACK_PLUGIN("server");
// Mandatory init function. If you have some global state, create it here.
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
// Fill the command list with your commands.
commands.clear();
commands.push_back(PluginCommand("server",
"Inane zeromq example turned into a plugin.",
server));
return CR_OK;
}
// This is called right before the plugin library is removed from memory.
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
// You *MUST* kill all threads you created before this returns.
// If everythin fails, just return CR_FAILURE. Your plugin will be
// in a zombie state, but things won't crash.
return CR_OK;
}
// This is WRONG and STUPID. Never use this as an example!
command_result server (color_ostream &out, std::vector <std::string> & parameters)
{
// It's nice to provide a 'help' option for your command.
// It's also nice to print the same help if you get invalid options from the user instead of just acting strange
for(int i = 0; i < parameters.size();i++)
{
if(parameters[i] == "help" || parameters[i] == "?")
{
// Core has a handle to the console. The console is thread-safe.
// Only one thing can read from it at a time though...
out.print("This command is a simple Hello World example for zeromq!\n");
return CR_OK;
}
}
// Prepare our context and socket
zmq::context_t context (1);
zmq::socket_t socket (context, ZMQ_REP);
socket.bind ("tcp://*:5555");
while (true)
{
zmq::message_t request;
// Wait for next request from client
socket.recv (&request);
out.print("Received Hello\n");
// Do some 'work'
#ifdef LINUX_BUILD
sleep (1);
#else
Sleep(1000);
#endif
// Send reply back to client
zmq::message_t reply (5);
memcpy ((void *) reply.data (), "World", 5);
socket.send (reply);
}
return CR_OK;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -1,41 +0,0 @@
# libzmq.la - a libtool library file
# Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu1
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# The name that we can dlopen(3).
dlname='libzmq.so.1'
# Names of this library.
library_names='libzmq.so.1.0.0 libzmq.so.1 libzmq.so'
# The name of the static archive.
old_library='libzmq.a'
# Linker flags that can not go in dependency_libs.
inherited_linker_flags=''
# Libraries that this one depends upon.
dependency_libs=' -luuid -lrt -lpthread'
# Names of additional weak libraries provided by this library
weak_library_names=''
# Version information for libzmq.
current=1
age=0
revision=0
# Is this an already installed library?
installed=yes
# Should we warn about portability when linking against -modules?
shouldnotlink=no
# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''
# Directory that this library needs to be installed in:
libdir='/home/peterix/zeromq/lib'

Binary file not shown.

Binary file not shown.

@ -1,269 +0,0 @@
/*
Copyright (c) 2007-2011 iMatix Corporation
Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_H_INCLUDED__
#define __ZMQ_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
#include <errno.h>
#include <stddef.h>
#if defined _WIN32
#include <winsock2.h>
#endif
/* Handle DSO symbol visibility */
#if defined _WIN32
# if defined DLL_EXPORT
# define ZMQ_EXPORT __declspec(dllexport)
# else
# define ZMQ_EXPORT __declspec(dllimport)
# endif
#else
# if defined __SUNPRO_C || defined __SUNPRO_CC
# define ZMQ_EXPORT __global
# elif (defined __GNUC__ && __GNUC__ >= 4) || defined __INTEL_COMPILER
# define ZMQ_EXPORT __attribute__ ((visibility("default")))
# else
# define ZMQ_EXPORT
# endif
#endif
/******************************************************************************/
/* 0MQ versioning support. */
/******************************************************************************/
/* Version macros for compile-time API version detection */
#define ZMQ_VERSION_MAJOR 2
#define ZMQ_VERSION_MINOR 1
#define ZMQ_VERSION_PATCH 10
#define ZMQ_MAKE_VERSION(major, minor, patch) \
((major) * 10000 + (minor) * 100 + (patch))
#define ZMQ_VERSION \
ZMQ_MAKE_VERSION(ZMQ_VERSION_MAJOR, ZMQ_VERSION_MINOR, ZMQ_VERSION_PATCH)
/* Run-time API version detection */
ZMQ_EXPORT void zmq_version (int *major, int *minor, int *patch);
/******************************************************************************/
/* 0MQ errors. */
/******************************************************************************/
/* A number random enough not to collide with different errno ranges on */
/* different OSes. The assumption is that error_t is at least 32-bit type. */
#define ZMQ_HAUSNUMERO 156384712
/* On Windows platform some of the standard POSIX errnos are not defined. */
#ifndef ENOTSUP
#define ENOTSUP (ZMQ_HAUSNUMERO + 1)
#endif
#ifndef EPROTONOSUPPORT
#define EPROTONOSUPPORT (ZMQ_HAUSNUMERO + 2)
#endif
#ifndef ENOBUFS
#define ENOBUFS (ZMQ_HAUSNUMERO + 3)
#endif
#ifndef ENETDOWN
#define ENETDOWN (ZMQ_HAUSNUMERO + 4)
#endif
#ifndef EADDRINUSE
#define EADDRINUSE (ZMQ_HAUSNUMERO + 5)
#endif
#ifndef EADDRNOTAVAIL
#define EADDRNOTAVAIL (ZMQ_HAUSNUMERO + 6)
#endif
#ifndef ECONNREFUSED
#define ECONNREFUSED (ZMQ_HAUSNUMERO + 7)
#endif
#ifndef EINPROGRESS
#define EINPROGRESS (ZMQ_HAUSNUMERO + 8)
#endif
#ifndef ENOTSOCK
#define ENOTSOCK (ZMQ_HAUSNUMERO + 9)
#endif
/* Native 0MQ error codes. */
#define EFSM (ZMQ_HAUSNUMERO + 51)
#define ENOCOMPATPROTO (ZMQ_HAUSNUMERO + 52)
#define ETERM (ZMQ_HAUSNUMERO + 53)
#define EMTHREAD (ZMQ_HAUSNUMERO + 54)
/* This function retrieves the errno as it is known to 0MQ library. The goal */
/* of this function is to make the code 100% portable, including where 0MQ */
/* compiled with certain CRT library (on Windows) is linked to an */
/* application that uses different CRT library. */
ZMQ_EXPORT int zmq_errno (void);
/* Resolves system errors and 0MQ errors to human-readable string. */
ZMQ_EXPORT const char *zmq_strerror (int errnum);
/******************************************************************************/
/* 0MQ message definition. */
/******************************************************************************/
/* Maximal size of "Very Small Message". VSMs are passed by value */
/* to avoid excessive memory allocation/deallocation. */
/* If VMSs larger than 255 bytes are required, type of 'vsm_size' */
/* field in zmq_msg_t structure should be modified accordingly. */
#define ZMQ_MAX_VSM_SIZE 30
/* Message types. These integers may be stored in 'content' member of the */
/* message instead of regular pointer to the data. */
#define ZMQ_DELIMITER 31
#define ZMQ_VSM 32
/* Message flags. ZMQ_MSG_SHARED is strictly speaking not a message flag */
/* (it has no equivalent in the wire format), however, making it a flag */
/* allows us to pack the stucture tigher and thus improve performance. */
#define ZMQ_MSG_MORE 1
#define ZMQ_MSG_SHARED 128
#define ZMQ_MSG_MASK 129 /* Merges all the flags */
/* A message. Note that 'content' is not a pointer to the raw data. */
/* Rather it is pointer to zmq::msg_content_t structure */
/* (see src/msg_content.hpp for its definition). */
typedef struct
{
void *content;
unsigned char flags;
unsigned char vsm_size;
unsigned char vsm_data [ZMQ_MAX_VSM_SIZE];
} zmq_msg_t;
typedef void (zmq_free_fn) (void *data, void *hint);
ZMQ_EXPORT int zmq_msg_init (zmq_msg_t *msg);
ZMQ_EXPORT int zmq_msg_init_size (zmq_msg_t *msg, size_t size);
ZMQ_EXPORT int zmq_msg_init_data (zmq_msg_t *msg, void *data,
size_t size, zmq_free_fn *ffn, void *hint);
ZMQ_EXPORT int zmq_msg_close (zmq_msg_t *msg);
ZMQ_EXPORT int zmq_msg_move (zmq_msg_t *dest, zmq_msg_t *src);
ZMQ_EXPORT int zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src);
ZMQ_EXPORT void *zmq_msg_data (zmq_msg_t *msg);
ZMQ_EXPORT size_t zmq_msg_size (zmq_msg_t *msg);
/******************************************************************************/
/* 0MQ infrastructure (a.k.a. context) initialisation & termination. */
/******************************************************************************/
ZMQ_EXPORT void *zmq_init (int io_threads);
ZMQ_EXPORT int zmq_term (void *context);
/******************************************************************************/
/* 0MQ socket definition. */
/******************************************************************************/
/* Socket types. */
#define ZMQ_PAIR 0
#define ZMQ_PUB 1
#define ZMQ_SUB 2
#define ZMQ_REQ 3
#define ZMQ_REP 4
#define ZMQ_DEALER 5
#define ZMQ_ROUTER 6
#define ZMQ_PULL 7
#define ZMQ_PUSH 8
#define ZMQ_XPUB 9
#define ZMQ_XSUB 10
#define ZMQ_XREQ ZMQ_DEALER /* Old alias, remove in 3.x */
#define ZMQ_XREP ZMQ_ROUTER /* Old alias, remove in 3.x */
#define ZMQ_UPSTREAM ZMQ_PULL /* Old alias, remove in 3.x */
#define ZMQ_DOWNSTREAM ZMQ_PUSH /* Old alias, remove in 3.x */
/* Socket options. */
#define ZMQ_HWM 1
#define ZMQ_SWAP 3
#define ZMQ_AFFINITY 4
#define ZMQ_IDENTITY 5
#define ZMQ_SUBSCRIBE 6
#define ZMQ_UNSUBSCRIBE 7
#define ZMQ_RATE 8
#define ZMQ_RECOVERY_IVL 9
#define ZMQ_MCAST_LOOP 10
#define ZMQ_SNDBUF 11
#define ZMQ_RCVBUF 12
#define ZMQ_RCVMORE 13
#define ZMQ_FD 14
#define ZMQ_EVENTS 15
#define ZMQ_TYPE 16
#define ZMQ_LINGER 17
#define ZMQ_RECONNECT_IVL 18
#define ZMQ_BACKLOG 19
#define ZMQ_RECOVERY_IVL_MSEC 20 /* opt. recovery time, reconcile in 3.x */
#define ZMQ_RECONNECT_IVL_MAX 21
/* Send/recv options. */
#define ZMQ_NOBLOCK 1
#define ZMQ_SNDMORE 2
ZMQ_EXPORT void *zmq_socket (void *context, int type);
ZMQ_EXPORT int zmq_close (void *s);
ZMQ_EXPORT int zmq_setsockopt (void *s, int option, const void *optval,
size_t optvallen);
ZMQ_EXPORT int zmq_getsockopt (void *s, int option, void *optval,
size_t *optvallen);
ZMQ_EXPORT int zmq_bind (void *s, const char *addr);
ZMQ_EXPORT int zmq_connect (void *s, const char *addr);
ZMQ_EXPORT int zmq_send (void *s, zmq_msg_t *msg, int flags);
ZMQ_EXPORT int zmq_recv (void *s, zmq_msg_t *msg, int flags);
/******************************************************************************/
/* I/O multiplexing. */
/******************************************************************************/
#define ZMQ_POLLIN 1
#define ZMQ_POLLOUT 2
#define ZMQ_POLLERR 4
typedef struct
{
void *socket;
#if defined _WIN32
SOCKET fd;
#else
int fd;
#endif
short events;
short revents;
} zmq_pollitem_t;
ZMQ_EXPORT int zmq_poll (zmq_pollitem_t *items, int nitems, long timeout);
/******************************************************************************/
/* Built-in devices */
/******************************************************************************/
#define ZMQ_STREAMER 1
#define ZMQ_FORWARDER 2
#define ZMQ_QUEUE 3
ZMQ_EXPORT int zmq_device (int device, void * insocket, void* outsocket);
#undef ZMQ_EXPORT
#ifdef __cplusplus
}
#endif
#endif

@ -1,301 +0,0 @@
/*
Copyright (c) 2007-2011 iMatix Corporation
Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_HPP_INCLUDED__
#define __ZMQ_HPP_INCLUDED__
#include "zmq.h"
#include <cassert>
#include <cstring>
#include <exception>
namespace zmq
{
typedef zmq_free_fn free_fn;
typedef zmq_pollitem_t pollitem_t;
class error_t : public std::exception
{
public:
error_t () : errnum (zmq_errno ()) {}
virtual const char *what () const throw ()
{
return zmq_strerror (errnum);
}
int num () const
{
return errnum;
}
private:
int errnum;
};
inline int poll (zmq_pollitem_t *items_, int nitems_, long timeout_ = -1)
{
int rc = zmq_poll (items_, nitems_, timeout_);
if (rc < 0)
throw error_t ();
return rc;
}
inline void device (int device_, void * insocket_, void* outsocket_)
{
int rc = zmq_device (device_, insocket_, outsocket_);
if (rc != 0)
throw error_t ();
}
inline void version (int *major_, int *minor_, int *patch_)
{
zmq_version (major_, minor_, patch_);
}
class message_t : private zmq_msg_t
{
friend class socket_t;
public:
inline message_t ()
{
int rc = zmq_msg_init (this);
if (rc != 0)
throw error_t ();
}
inline message_t (size_t size_)
{
int rc = zmq_msg_init_size (this, size_);
if (rc != 0)
throw error_t ();
}
inline message_t (void *data_, size_t size_, free_fn *ffn_,
void *hint_ = NULL)
{
int rc = zmq_msg_init_data (this, data_, size_, ffn_, hint_);
if (rc != 0)
throw error_t ();
}
inline ~message_t ()
{
int rc = zmq_msg_close (this);
assert (rc == 0);
}
inline void rebuild ()
{
int rc = zmq_msg_close (this);
if (rc != 0)
throw error_t ();
rc = zmq_msg_init (this);
if (rc != 0)
throw error_t ();
}
inline void rebuild (size_t size_)
{
int rc = zmq_msg_close (this);
if (rc != 0)
throw error_t ();
rc = zmq_msg_init_size (this, size_);
if (rc != 0)
throw error_t ();
}
inline void rebuild (void *data_, size_t size_, free_fn *ffn_,
void *hint_ = NULL)
{
int rc = zmq_msg_close (this);
if (rc != 0)
throw error_t ();
rc = zmq_msg_init_data (this, data_, size_, ffn_, hint_);
if (rc != 0)
throw error_t ();
}
inline void move (message_t *msg_)
{
int rc = zmq_msg_move (this, (zmq_msg_t*) msg_);
if (rc != 0)
throw error_t ();
}
inline void copy (message_t *msg_)
{
int rc = zmq_msg_copy (this, (zmq_msg_t*) msg_);
if (rc != 0)
throw error_t ();
}
inline void *data ()
{
return zmq_msg_data (this);
}
inline size_t size ()
{
return zmq_msg_size (this);
}
private:
// Disable implicit message copying, so that users won't use shared
// messages (less efficient) without being aware of the fact.
message_t (const message_t&);
void operator = (const message_t&);
};
class context_t
{
friend class socket_t;
public:
inline context_t (int io_threads_)
{
ptr = zmq_init (io_threads_);
if (ptr == NULL)
throw error_t ();
}
inline ~context_t ()
{
int rc = zmq_term (ptr);
assert (rc == 0);
}
// Be careful with this, it's probably only useful for
// using the C api together with an existing C++ api.
// Normally you should never need to use this.
inline operator void* ()
{
return ptr;
}
private:
void *ptr;
context_t (const context_t&);
void operator = (const context_t&);
};
class socket_t
{
public:
inline socket_t (context_t &context_, int type_)
{
ptr = zmq_socket (context_.ptr, type_);
if (ptr == NULL)
throw error_t ();
}
inline ~socket_t ()
{
close();
}
inline operator void* ()
{
return ptr;
}
inline void close()
{
if(ptr == NULL)
// already closed
return ;
int rc = zmq_close (ptr);
if (rc != 0)
throw error_t ();
ptr = 0 ;
}
inline void setsockopt (int option_, const void *optval_,
size_t optvallen_)
{
int rc = zmq_setsockopt (ptr, option_, optval_, optvallen_);
if (rc != 0)
throw error_t ();
}
inline void getsockopt (int option_, void *optval_,
size_t *optvallen_)
{
int rc = zmq_getsockopt (ptr, option_, optval_, optvallen_);
if (rc != 0)
throw error_t ();
}
inline void bind (const char *addr_)
{
int rc = zmq_bind (ptr, addr_);
if (rc != 0)
throw error_t ();
}
inline void connect (const char *addr_)
{
int rc = zmq_connect (ptr, addr_);
if (rc != 0)
throw error_t ();
}
inline bool send (message_t &msg_, int flags_ = 0)
{
int rc = zmq_send (ptr, &msg_, flags_);
if (rc == 0)
return true;
if (rc == -1 && zmq_errno () == EAGAIN)
return false;
throw error_t ();
}
inline bool recv (message_t *msg_, int flags_ = 0)
{
int rc = zmq_recv (ptr, msg_, flags_);
if (rc == 0)
return true;
if (rc == -1 && zmq_errno () == EAGAIN)
return false;
throw error_t ();
}
private:
void *ptr;
socket_t (const socket_t&);
void operator = (const socket_t&);
};
}
#endif

@ -1,64 +0,0 @@
/*
Copyright (c) 2007-2011 iMatix Corporation
Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_UTILS_H_INCLUDED__
#define __ZMQ_UTILS_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
/* Handle DSO symbol visibility */
#if defined _WIN32
# if defined DLL_EXPORT
# define ZMQ_EXPORT __declspec(dllexport)
# else
# define ZMQ_EXPORT __declspec(dllimport)
# endif
#else
# if defined __SUNPRO_C || defined __SUNPRO_CC
# define ZMQ_EXPORT __global
# elif (defined __GNUC__ && __GNUC__ >= 4) || defined __INTEL_COMPILER
# define ZMQ_EXPORT __attribute__ ((visibility("default")))
# else
# define ZMQ_EXPORT
# endif
#endif
/* Helper functions are used by perf tests so that they don't have to care */
/* about minutiae of time-related functions on different OS platforms. */
/* Starts the stopwatch. Returns the handle to the watch. */
ZMQ_EXPORT void *zmq_stopwatch_start (void);
/* Stops the stopwatch. Returns the number of microseconds elapsed since */
/* the stopwatch was started. */
ZMQ_EXPORT unsigned long zmq_stopwatch_stop (void *watch_);
/* Sleeps for specified number of seconds. */
ZMQ_EXPORT void zmq_sleep (int seconds_);
#undef ZMQ_EXPORT
#ifdef __cplusplus
}
#endif
#endif

@ -272,7 +272,6 @@ DFHACK_PLUGIN("showmood");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand("showmood", "Shows items needed for current strange mood.", df_showmood)); commands.push_back(PluginCommand("showmood", "Shows items needed for current strange mood.", df_showmood));
return CR_OK; return CR_OK;
} }

@ -29,7 +29,6 @@ DFHACK_PLUGIN("skeleton");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
// Fill the command list with your commands. // Fill the command list with your commands.
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"skeleton", "Do nothing, look pretty.", "skeleton", "Do nothing, look pretty.",
skeleton, false, /* true means that the command can't be used from non-interactive user interface */ skeleton, false, /* true means that the command can't be used from non-interactive user interface */

@ -29,7 +29,6 @@ DFHACK_PLUGIN("stockpiles");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
if (world && ui) { if (world && ui) {
commands.push_back( commands.push_back(
PluginCommand( PluginCommand(

@ -1 +1 @@
Subproject commit 7525c003089367823183eaf5093a90271a5eb9b4 Subproject commit 906d6439d4cb694cf287d63badabb675a8b89329

@ -497,7 +497,6 @@ DFHACK_PLUGIN("tiletypes");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
tiletypes_hist.load("tiletypes.history"); tiletypes_hist.load("tiletypes.history");
commands.clear();
commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true)); commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true));
return CR_OK; return CR_OK;
} }
@ -525,7 +524,8 @@ command_result df_tiletypes (color_ostream &out, vector <string> & parameters)
} }
} }
assert(out.is_console()); if(!out.is_console())
return CR_FAILURE;
Console &con = static_cast<Console&>(out); Console &con = static_cast<Console&>(out);
TileType filter, paint; TileType filter, paint;

@ -23,7 +23,6 @@ DFHACK_PLUGIN("tubefill");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand("tubefill","Fill in all the adamantine tubes again.",tubefill)); commands.push_back(PluginCommand("tubefill","Fill in all the adamantine tubes again.",tubefill));
return CR_OK; return CR_OK;
} }

@ -41,7 +41,6 @@ DFHACK_PLUGIN("tweak");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"tweak", "Various tweaks for minor bugs.", tweak, false, "tweak", "Various tweaks for minor bugs.", tweak, false,
" tweak clear-missing\n" " tweak clear-missing\n"

@ -27,7 +27,6 @@ DFHACK_PLUGIN("vdig");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"vdig","Dig a whole vein.",vdig,Gui::cursor_hotkey, "vdig","Dig a whole vein.",vdig,Gui::cursor_hotkey,
" Designates a whole vein under the cursor for digging.\n" " Designates a whole vein under the cursor for digging.\n"

@ -46,7 +46,6 @@ DFTileSurface* createTile(int x, int y)
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand("versionosd", commands.push_back(PluginCommand("versionosd",
"Toggles displaying version in DF window", "Toggles displaying version in DF window",
df_versionosd)); df_versionosd));

@ -19,7 +19,6 @@ DFHACK_PLUGIN("weather");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"weather", "Print the weather map or change weather.", "weather", "Print the weather map or change weather.",
weather, false, weather, false,

@ -59,7 +59,6 @@ DFHACK_PLUGIN("workflow");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.clear();
if (!world || !ui) if (!world || !ui)
return CR_FAILURE; return CR_FAILURE;