diff --git a/LUA_API.rst b/LUA_API.rst
index df997008c..d5af5e7a4 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -663,6 +663,14 @@ Job module
Units module
------------
+* ``dfhack.units.getPosition(unit)``
+
+ Returns true *x,y,z* of the unit; may be not equal to unit.pos if caged.
+
+* ``dfhack.units.getContainer(unit)``
+
+ Returns the container (cage) item or *nil*.
+
* ``dfhack.units.setNickname(unit,nick)``
Sets the unit's nickname properly.
@@ -687,6 +695,10 @@ Units module
The unit is capable of rational action, i.e. not dead, insane or zombie.
+* ``dfhack.units.clearBurrowMembers(burrow)``
+
+ Removes all units from the burrow.
+
* ``dfhack.units.isInBurrow(unit,burrow)``
Checks if the unit is in the burrow.
@@ -701,7 +713,7 @@ Items module
* ``dfhack.items.getPosition(item)``
- Returns true *x,y,z* of the item.
+ Returns true *x,y,z* of the item; may be not equal to item.pos if in inventory.
* ``dfhack.items.getOwner(item)``
@@ -768,6 +780,10 @@ Maps module
Returns a table of map block pointers.
+* ``dfhack.maps.clearBurrowTiles(burrow)``
+
+ Removes all tiles from the burrow.
+
* ``dfhack.maps.isBurrowTile(burrow,tile_coord)``
Checks if the tile is in burrow.
diff --git a/Lua API.html b/Lua API.html
index 4be1050fb..66385840b 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -900,6 +900,12 @@ a lua list containing them.
+dfhack.units.getPosition(unit)
+Returns true x,y,z of the unit; may be not equal to unit.pos if caged.
+
+dfhack.units.getContainer(unit)
+Returns the container (cage) item or nil.
+
dfhack.units.setNickname(unit,nick)
Sets the unit's nickname properly.
@@ -918,6 +924,9 @@ a lua list containing them.
dfhack.units.isSane(unit)
The unit is capable of rational action, i.e. not dead, insane or zombie.
+dfhack.units.clearBurrowMembers(burrow)
+Removes all units from the burrow.
+
dfhack.units.isInBurrow(unit,burrow)
Checks if the unit is in the burrow.
@@ -930,7 +939,7 @@ a lua list containing them.
dfhack.items.getPosition(item)
-Returns true x,y,z of the item.
+Returns true x,y,z of the item; may be not equal to item.pos if in inventory.
dfhack.items.getOwner(item)
Returns the owner unit or nil.
@@ -983,6 +992,9 @@ Returns false in case of error.
dfhack.maps.listBurrowBlocks(burrow)
Returns a table of map block pointers.
+dfhack.maps.clearBurrowTiles(burrow)
+Removes all tiles from the burrow.
+
dfhack.maps.isBurrowTile(burrow,tile_coord)
Checks if the tile is in burrow.
diff --git a/library/Core.cpp b/library/Core.cpp
index a752ae628..e6b9c45ff 100644
--- a/library/Core.cpp
+++ b/library/Core.cpp
@@ -861,13 +861,9 @@ int Core::TileUpdate()
// should always be from simulation thread!
int Core::Update()
{
- if(!started)
- Init();
if(errorstate)
return -1;
- color_ostream_proxy out(con);
-
// Pretend this thread has suspended the core in the usual way
{
lock_guard lock(d->AccessMutex);
@@ -877,6 +873,22 @@ int Core::Update()
d->df_suspend_depth = 1000;
}
+ // Initialize the core
+ bool first_update = false;
+
+ if(!started)
+ {
+ first_update = true;
+ Init();
+ if(errorstate)
+ return -1;
+ }
+
+ color_ostream_proxy out(con);
+
+ if (first_update)
+ plug_mgr->OnStateChange(out, SC_CORE_INITIALIZED);
+
// detect if the game was loaded or unloaded in the meantime
void *new_wdata = NULL;
void *new_mapdata = NULL;
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 25f654b8c..917e44d38 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -627,17 +627,29 @@ static const luaL_Reg dfhack_job_funcs[] = {
static const LuaWrapper::FunctionReg dfhack_units_module[] = {
+ WRAPM(Units, getContainer),
WRAPM(Units, setNickname),
WRAPM(Units, getVisibleName),
WRAPM(Units, getNemesis),
WRAPM(Units, isDead),
WRAPM(Units, isAlive),
WRAPM(Units, isSane),
+ WRAPM(Units, clearBurrowMembers),
WRAPM(Units, isInBurrow),
WRAPM(Units, setInBurrow),
{ NULL, NULL }
};
+static int units_getPosition(lua_State *state)
+{
+ return push_pos(state, Units::getPosition(get_checked_arg(state,1)));
+}
+
+static const luaL_Reg dfhack_units_funcs[] = {
+ { "getPosition", units_getPosition },
+ { NULL, NULL }
+};
+
static bool items_moveToGround(df::item *item, df::coord pos)
{
MapExtras::MapCache mc;
@@ -696,6 +708,7 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
WRAPM(Maps, getGlobalInitFeature),
WRAPM(Maps, getLocalInitFeature),
WRAPM(Maps, findBurrowByName),
+ WRAPM(Maps, clearBurrowTiles),
WRAPN(isBlockBurrowTile, maps_isBlockBurrowTile),
WRAPN(setBlockBurrowTile, maps_setBlockBurrowTile),
WRAPM(Maps, isBurrowTile),
@@ -729,7 +742,7 @@ void OpenDFHackApi(lua_State *state)
LuaWrapper::SetFunctionWrappers(state, dfhack_module);
OpenModule(state, "gui", dfhack_gui_module);
OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs);
- OpenModule(state, "units", dfhack_units_module);
+ OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs);
OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs);
OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs);
}
diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp
index 471ffd550..5129ba648 100644
--- a/library/LuaTools.cpp
+++ b/library/LuaTools.cpp
@@ -745,6 +745,22 @@ static int lua_dfhack_with_suspend(lua_State *L)
return lua_gettop(L);
}
+static int dfhack_open_plugin(lua_State *L)
+{
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checktype(L, 2, LUA_TSTRING);
+ const char *name = lua_tostring(L, 2);
+
+ PluginManager *pmgr = Core::getInstance().getPluginManager();
+ Plugin *plugin = pmgr->getPluginByName(name);
+
+ if (!plugin)
+ luaL_error(L, "plugin not found: '%s'", name);
+
+ plugin->open_lua(L, 1);
+ return 0;
+}
+
static const luaL_Reg dfhack_funcs[] = {
{ "print", lua_dfhack_print },
{ "println", lua_dfhack_println },
@@ -757,6 +773,7 @@ static const luaL_Reg dfhack_funcs[] = {
{ "onerror", dfhack_onerror },
{ "call_with_finalizer", dfhack_call_with_finalizer },
{ "with_suspend", lua_dfhack_with_suspend },
+ { "open_plugin", dfhack_open_plugin },
{ NULL, NULL }
};
diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp
index 40269da80..f5ba565d5 100644
--- a/library/LuaTypes.cpp
+++ b/library/LuaTypes.cpp
@@ -1030,6 +1030,12 @@ static int meta_global_newindex(lua_State *state)
static int meta_call_function(lua_State *state)
{
auto id = (function_identity_base*)lua_touserdata(state, UPVAL_CONTAINER_ID);
+
+ return method_wrapper_core(state, id);
+}
+
+int LuaWrapper::method_wrapper_core(lua_State *state, function_identity_base *id)
+{
if (lua_gettop(state) != id->getNumArgs())
field_error(state, UPVAL_METHOD_NAME, "invalid argument count", "invoke");
diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp
index a7faabeec..4d0c06ddf 100644
--- a/library/PluginManager.cpp
+++ b/library/PluginManager.cpp
@@ -32,6 +32,8 @@ distribution.
#include "DataDefs.h"
#include "MiscUtils.h"
+#include "LuaWrapper.h"
+
using namespace DFHack;
#include
@@ -107,8 +109,8 @@ struct Plugin::RefLock
void lock_sub()
{
mut->lock();
- refcount --;
- wakeup->notify_one();
+ if (--refcount == 0)
+ wakeup->notify_one();
mut->unlock();
}
void wait()
@@ -130,6 +132,13 @@ struct Plugin::RefAutolock
~RefAutolock(){ lock->unlock(); };
};
+struct Plugin::RefAutoinc
+{
+ RefLock * lock;
+ RefAutoinc(RefLock * lck):lock(lck){ lock->lock_add(); };
+ ~RefAutoinc(){ lock->lock_sub(); };
+};
+
Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _filename, PluginManager * pm)
{
filename = filepath;
@@ -210,6 +219,7 @@ bool Plugin::load(color_ostream &con)
plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown");
plugin_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange");
plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect");
+ index_lua(plug);
this->name = *plug_name;
plugin_lib = plug;
commands.clear();
@@ -222,6 +232,7 @@ bool Plugin::load(color_ostream &con)
else
{
con.printerr("Plugin %s has failed to initialize properly.\n", filename.c_str());
+ reset_lua();
ClosePlugin(plugin_lib);
state = PS_BROKEN;
return false;
@@ -235,13 +246,22 @@ bool Plugin::unload(color_ostream &con)
// if we are actually loaded
if(state == PS_LOADED)
{
+ // notify the plugin about an attempt to shutdown
+ if (plugin_onstatechange &&
+ plugin_onstatechange(con, SC_BEGIN_UNLOAD) == CR_NOT_FOUND)
+ {
+ con.printerr("Plugin %s has refused to be unloaded.\n", name.c_str());
+ access->unlock();
+ return false;
+ }
+ // wait for all calls to finish
+ access->wait();
// notify plugin about shutdown, if it has a shutdown function
command_result cr = CR_OK;
if(plugin_shutdown)
cr = plugin_shutdown(con);
- // wait for all calls to finish
- access->wait();
// cleanup...
+ reset_lua();
parent->unregisterCommands(this);
commands.clear();
if(cr == CR_OK)
@@ -418,6 +438,90 @@ Plugin::plugin_state Plugin::getState() const
return state;
}
+void Plugin::index_lua(DFLibrary *lib)
+{
+ if (auto cmdlist = (CommandReg*)LookupPlugin(lib, "plugin_lua_commands"))
+ {
+ for (; cmdlist->name; ++cmdlist)
+ {
+ auto &cmd = lua_commands[cmdlist->name];
+ if (!cmd) cmd = new LuaCommand;
+ cmd->owner = this;
+ cmd->name = cmdlist->name;
+ cmd->command = cmdlist->command;
+ }
+ }
+ if (auto funlist = (FunctionReg*)LookupPlugin(lib, "plugin_lua_functions"))
+ {
+ for (; funlist->name; ++funlist)
+ {
+ auto &cmd = lua_functions[funlist->name];
+ if (!cmd) cmd = new LuaFunction;
+ cmd->owner = this;
+ cmd->name = funlist->name;
+ cmd->identity = funlist->identity;
+ }
+ }
+}
+
+void Plugin::reset_lua()
+{
+ for (auto it = lua_commands.begin(); it != lua_commands.end(); ++it)
+ it->second->command = NULL;
+ for (auto it = lua_functions.begin(); it != lua_functions.end(); ++it)
+ it->second->identity = NULL;
+}
+
+int Plugin::lua_cmd_wrapper(lua_State *state)
+{
+ auto cmd = (LuaCommand*)lua_touserdata(state, lua_upvalueindex(1));
+
+ RefAutoinc lock(cmd->owner->access);
+
+ if (!cmd->command)
+ luaL_error(state, "plugin command %s() has been unloaded",
+ (cmd->owner->name+"."+cmd->name).c_str());
+
+ return cmd->command(state);
+}
+
+int Plugin::lua_fun_wrapper(lua_State *state)
+{
+ auto cmd = (LuaFunction*)lua_touserdata(state, UPVAL_CONTAINER_ID);
+
+ RefAutoinc lock(cmd->owner->access);
+
+ if (!cmd->identity)
+ luaL_error(state, "plugin function %s() has been unloaded",
+ (cmd->owner->name+"."+cmd->name).c_str());
+
+ return LuaWrapper::method_wrapper_core(state, cmd->identity);
+}
+
+void Plugin::open_lua(lua_State *state, int table)
+{
+ table = lua_absindex(state, table);
+
+ RefAutolock lock(access);
+
+ for (auto it = lua_commands.begin(); it != lua_commands.end(); ++it)
+ {
+ lua_pushlightuserdata(state, it->second);
+ lua_pushcclosure(state, lua_cmd_wrapper, 1);
+ lua_setfield(state, table, it->first.c_str());
+ }
+
+ for (auto it = lua_functions.begin(); it != lua_functions.end(); ++it)
+ {
+ lua_rawgetp(state, LUA_REGISTRYINDEX, &LuaWrapper::DFHACK_TYPETABLE_TOKEN);
+ lua_pushlightuserdata(state, NULL);
+ lua_pushfstring(state, "%s.%s()", name.c_str(), it->second->name.c_str());
+ lua_pushlightuserdata(state, it->second);
+ lua_pushcclosure(state, lua_fun_wrapper, 4);
+ lua_setfield(state, table, it->first.c_str());
+ }
+}
+
PluginManager::PluginManager(Core * core)
{
#ifdef LINUX_BUILD
diff --git a/library/include/Core.h b/library/include/Core.h
index 290a324b9..8c2a284df 100644
--- a/library/include/Core.h
+++ b/library/include/Core.h
@@ -139,6 +139,8 @@ namespace DFHack
static void print(const char *format, ...);
static void printerr(const char *format, ...);
+ PluginManager *getPluginManager() { return plug_mgr; }
+
private:
DFHack::Console con;
diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h
index d78fe9e27..a949e784b 100644
--- a/library/include/DataFuncs.h
+++ b/library/include/DataFuncs.h
@@ -32,10 +32,6 @@ distribution.
#include "DataIdentity.h"
#include "LuaWrapper.h"
-#ifndef BUILD_DFHACK_LIB
-#error Due to export issues this header is internal to the main library.
-#endif
-
namespace df {
// A very simple and stupid implementation of some stuff from boost
template struct is_same_type { static const bool value = false; };
@@ -50,7 +46,7 @@ namespace df {
template::type,void>::value>
struct function_wrapper {};
- class cur_lua_ostream_argument {
+ class DFHACK_EXPORT cur_lua_ostream_argument {
DFHack::color_ostream *out;
public:
cur_lua_ostream_argument(lua_State *state);
diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h
index bab87e1bb..279400f74 100644
--- a/library/include/DataIdentity.h
+++ b/library/include/DataIdentity.h
@@ -160,8 +160,6 @@ namespace DFHack
};
}
-// Due to export issues, this stuff can only work in the main dll
-#ifdef BUILD_DFHACK_LIB
namespace df
{
using DFHack::function_identity_base;
@@ -171,7 +169,7 @@ namespace df
using DFHack::ptr_container_identity;
using DFHack::bit_container_identity;
- class number_identity_base : public primitive_identity {
+ class DFHACK_EXPORT number_identity_base : public primitive_identity {
const char *name;
public:
@@ -197,7 +195,7 @@ namespace df
virtual void write(void *ptr, double val) { *(T*)ptr = T(val); }
};
- class bool_identity : public primitive_identity {
+ class DFHACK_EXPORT bool_identity : public primitive_identity {
public:
bool_identity() : primitive_identity(sizeof(bool)) {};
@@ -207,7 +205,7 @@ namespace df
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
- class ptr_string_identity : public primitive_identity {
+ class DFHACK_EXPORT ptr_string_identity : public primitive_identity {
public:
ptr_string_identity() : primitive_identity(sizeof(char*)) {};
@@ -217,7 +215,7 @@ namespace df
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
- class stl_string_identity : public DFHack::constructed_identity {
+ class DFHACK_EXPORT stl_string_identity : public DFHack::constructed_identity {
public:
stl_string_identity()
: constructed_identity(sizeof(std::string), &allocator_fn)
@@ -233,7 +231,7 @@ namespace df
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
};
- class stl_ptr_vector_identity : public ptr_container_identity {
+ class DFHACK_EXPORT stl_ptr_vector_identity : public ptr_container_identity {
public:
typedef std::vector container;
@@ -276,6 +274,8 @@ namespace df
}
};
+// Due to export issues, this stuff can only work in the main dll
+#ifdef BUILD_DFHACK_LIB
class buffer_container_identity : public container_identity {
int size;
@@ -370,8 +370,9 @@ namespace df
((container*)ptr)->set(idx, val);
}
};
+#endif
- class stl_bit_vector_identity : public bit_container_identity {
+ class DFHACK_EXPORT stl_bit_vector_identity : public bit_container_identity {
public:
typedef std::vector container;
@@ -400,6 +401,7 @@ namespace df
}
};
+#ifdef BUILD_DFHACK_LIB
template
class enum_list_attr_identity : public container_identity {
public:
@@ -421,9 +423,10 @@ namespace df
return (void*)&((container*)ptr)->items[idx];
}
};
+#endif
#define NUMBER_IDENTITY_TRAITS(type) \
- template<> struct identity_traits { \
+ template<> struct DFHACK_EXPORT identity_traits { \
static number_identity identity; \
static number_identity_base *get() { return &identity; } \
};
@@ -439,37 +442,37 @@ namespace df
NUMBER_IDENTITY_TRAITS(uint64_t);
NUMBER_IDENTITY_TRAITS(float);
- template<> struct identity_traits {
+ template<> struct DFHACK_EXPORT identity_traits {
static bool_identity identity;
static bool_identity *get() { return &identity; }
};
- template<> struct identity_traits {
+ template<> struct DFHACK_EXPORT identity_traits {
static stl_string_identity identity;
static stl_string_identity *get() { return &identity; }
};
- template<> struct identity_traits {
+ template<> struct DFHACK_EXPORT identity_traits {
static ptr_string_identity identity;
static ptr_string_identity *get() { return &identity; }
};
- template<> struct identity_traits {
+ template<> struct DFHACK_EXPORT identity_traits {
static ptr_string_identity identity;
static ptr_string_identity *get() { return &identity; }
};
- template<> struct identity_traits {
+ template<> struct DFHACK_EXPORT identity_traits {
static pointer_identity identity;
static pointer_identity *get() { return &identity; }
};
- template<> struct identity_traits > {
+ template<> struct DFHACK_EXPORT identity_traits > {
static stl_ptr_vector_identity identity;
static stl_ptr_vector_identity *get() { return &identity; }
};
- template<> struct identity_traits > {
+ template<> struct DFHACK_EXPORT identity_traits > {
static stl_bit_vector_identity identity;
static stl_bit_vector_identity *get() { return &identity; }
};
@@ -478,14 +481,17 @@ namespace df
// Container declarations
+#ifdef BUILD_DFHACK_LIB
template struct identity_traits > {
static primitive_identity *get();
};
+#endif
template struct identity_traits {
static pointer_identity *get();
};
+#ifdef BUILD_DFHACK_LIB
template struct identity_traits {
static container_identity *get();
};
@@ -493,11 +499,13 @@ namespace df
template struct identity_traits > {
static container_identity *get();
};
+#endif
template struct identity_traits > {
static stl_ptr_vector_identity *get();
};
+#ifdef BUILD_DFHACK_LIB
template struct identity_traits > {
static container_identity *get();
};
@@ -518,13 +526,16 @@ namespace df
template struct identity_traits > {
static container_identity *get();
};
+#endif
// Container definitions
+#ifdef BUILD_DFHACK_LIB
template
inline primitive_identity *identity_traits >::get() {
return identity_traits::get();
}
+#endif
template
inline pointer_identity *identity_traits::get() {
@@ -532,6 +543,7 @@ namespace df
return &identity;
}
+#ifdef BUILD_DFHACK_LIB
template
inline container_identity *identity_traits::get() {
static buffer_container_identity identity(sz, identity_traits::get());
@@ -544,6 +556,7 @@ namespace df
static stl_container_identity identity("vector", identity_traits::get());
return &identity;
}
+#endif
template
inline stl_ptr_vector_identity *identity_traits >::get() {
@@ -551,6 +564,7 @@ namespace df
return &identity;
}
+#ifdef BUILD_DFHACK_LIB
template
inline container_identity *identity_traits >::get() {
typedef std::deque container;
@@ -576,5 +590,5 @@ namespace df
static enum_list_attr_identity identity(identity_traits::get());
return &identity;
}
-}
#endif
+}
diff --git a/library/include/LuaWrapper.h b/library/include/LuaWrapper.h
index 479ca0d67..2304b940d 100644
--- a/library/include/LuaWrapper.h
+++ b/library/include/LuaWrapper.h
@@ -30,6 +30,7 @@ distribution.
#include