From 6cf8220f28001c9b044cf7dc2717c882fe2d2ecc Mon Sep 17 00:00:00 2001
From: Will Rogers
Date: Tue, 10 Apr 2012 20:41:54 -0400
Subject: [PATCH 01/20] Add SetUnitLabors protobuf API.
---
library/RemoteTools.cpp | 16 ++++++++++++++++
library/proto/Basic.proto | 6 ++++++
library/proto/BasicApi.proto | 7 ++++++-
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp
index 00344d6a2..7f86134b1 100644
--- a/library/RemoteTools.cpp
+++ b/library/RemoteTools.cpp
@@ -614,6 +614,20 @@ static command_result ListSquads(color_ostream &stream,
return CR_OK;
}
+static command_result SetUnitLabors(color_ostream &stream, const SetUnitLaborsIn *in)
+{
+ for (size_t i = 0; i < in->change_size(); i++)
+ {
+ auto change = in->change(i);
+ auto unit = df::unit::find(change.unit_id());
+
+ if (unit)
+ unit->status.labors[change.labor()] = change.value();
+ }
+
+ return CR_OK;
+}
+
CoreService::CoreService() {
suspend_depth = 0;
@@ -637,6 +651,8 @@ CoreService::CoreService() {
addFunction("ListMaterials", ListMaterials, SF_CALLED_ONCE);
addFunction("ListUnits", ListUnits);
addFunction("ListSquads", ListSquads);
+
+ addFunction("SetUnitLabors", SetUnitLabors);
}
CoreService::~CoreService()
diff --git a/library/proto/Basic.proto b/library/proto/Basic.proto
index 246fba22e..64eaea8eb 100755
--- a/library/proto/Basic.proto
+++ b/library/proto/Basic.proto
@@ -188,3 +188,9 @@ message BasicSquadInfo {
// Member histfig ids:
repeated sint32 members = 4;
};
+
+message UnitLaborState {
+ required int32 unit_id = 1;
+ required int32 labor = 2;
+ required bool value = 3;
+};
diff --git a/library/proto/BasicApi.proto b/library/proto/BasicApi.proto
index 3072f9cad..a5a07aa1c 100755
--- a/library/proto/BasicApi.proto
+++ b/library/proto/BasicApi.proto
@@ -99,4 +99,9 @@ message ListUnitsOut {
message ListSquadsIn {}
message ListSquadsOut {
repeated BasicSquadInfo value = 1;
-}
+};
+
+// RPC SetUnitLabors : SetUnitLaborsIn -> EmptyMessage
+message SetUnitLaborsIn {
+ repeated UnitLaborState change = 1;
+};
From 8c40a27ea03f80419088e022e2675ac64d4bb962 Mon Sep 17 00:00:00 2001
From: Will Rogers
Date: Tue, 10 Apr 2012 20:42:23 -0400
Subject: [PATCH 02/20] Add unit_misc_trait list to BasicUnitInfo protobuf API.
---
library/RemoteTools.cpp | 14 ++++++++++++++
library/proto/Basic.proto | 9 +++++++++
2 files changed, 23 insertions(+)
diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp
index 7f86134b1..c8af46cbf 100644
--- a/library/RemoteTools.cpp
+++ b/library/RemoteTools.cpp
@@ -61,6 +61,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "df/world.h"
#include "df/world_data.h"
#include "df/unit.h"
+#include "df/unit_misc_trait.h"
#include "df/unit_soul.h"
#include "df/unit_skill.h"
#include "df/material.h"
@@ -316,6 +317,19 @@ void DFHack::describeUnit(BasicUnitInfo *info, df::unit *unit,
}
}
+ if (mask && mask->misc_traits())
+ {
+ auto &vec = unit -> status.misc_traits;
+
+ for (size_t i = 0; i < vec.size(); i++)
+ {
+ auto trait = vec[i];
+ auto item = info->add_misc_traits();
+ item->set_id(trait->id);
+ item->set_value(trait->value);
+ }
+ }
+
if (unit->curse.add_tags1.whole ||
unit->curse.add_tags2.whole ||
unit->curse.rem_tags1.whole ||
diff --git a/library/proto/Basic.proto b/library/proto/Basic.proto
index 64eaea8eb..c387bef01 100755
--- a/library/proto/Basic.proto
+++ b/library/proto/Basic.proto
@@ -130,6 +130,11 @@ message SkillInfo {
required int32 experience = 3;
};
+message UnitMiscTrait {
+ required int32 id = 1;
+ required int32 value = 2;
+};
+
message BasicUnitInfo {
required int32 unit_id = 1;
@@ -166,6 +171,9 @@ message BasicUnitInfo {
// IF mask.skills:
repeated SkillInfo skills = 12;
+ // IF mask.misc_traits:
+ repeated UnitMiscTrait misc_traits = 24;
+
optional UnitCurseInfo curse = 16;
repeated int32 burrows = 21;
@@ -175,6 +183,7 @@ message BasicUnitInfoMask {
optional bool labors = 1 [default = false];
optional bool skills = 2 [default = false];
optional bool profession = 3 [default = false];
+ optional bool misc_traits = 4 [default = false];
};
message BasicSquadInfo {
From d874c3b5386b5efad30a4a23afbb6fff03aba25f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Mr=C3=A1zek?=
Date: Wed, 11 Apr 2012 21:33:45 +0200
Subject: [PATCH 03/20] Track stonesense
---
plugins/stonesense | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/stonesense b/plugins/stonesense
index d1c87ec27..c50af342c 160000
--- a/plugins/stonesense
+++ b/plugins/stonesense
@@ -1 +1 @@
-Subproject commit d1c87ec273ef5c928989437379943a9a71a1d4e0
+Subproject commit c50af342c27542c3b2c51ddd9099798339b7aa62
From 583ccdcc0c33c396849fae93ecf7fbf69e0ff7bf Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 12 Apr 2012 10:54:53 +0400
Subject: [PATCH 04/20] Support pre-initializing vtable pointers from
symbols.xml
---
library/DataDefs.cpp | 29 ++++++++++++-----------------
library/VersionInfoFactory.cpp | 9 +++++++--
library/include/VersionInfo.h | 26 +++++++++++++++++++-------
library/modules/Items.cpp | 4 ++--
4 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp
index cf8a32fcc..76c872445 100644
--- a/library/DataDefs.cpp
+++ b/library/DataDefs.cpp
@@ -128,17 +128,6 @@ void compound_identity::Init(Core *core)
// they are called in an undefined order.
for (compound_identity *p = list; p; p = p->next)
p->doInit(core);
-
- //FIXME: ... nuked. the group was empty...
-/*
- // Read pre-filled vtable ptrs
- OffsetGroup *ptr_table = core->vinfo->getGroup("vtable");
- for (virtual_identity *p = list; p; p = p->next) {
- void * tmp;
- if (ptr_table->getSafeAddress(p->getName(),tmp))
- p->vtable_ptr = tmp;
- }
- */
}
bitfield_identity::bitfield_identity(size_t size,
@@ -223,17 +212,23 @@ virtual_identity::virtual_identity(size_t size, TAllocateFn alloc,
{
}
+/* Vtable name to identity lookup. */
static std::map name_lookup;
+/* Vtable pointer to identity lookup. */
+std::map virtual_identity::known;
+
void virtual_identity::doInit(Core *core)
{
struct_identity::doInit(core);
- name_lookup[getOriginalName()] = this;
-}
+ auto vtname = getOriginalName();
+ name_lookup[vtname] = this;
-/* Vtable to identity lookup. */
-std::map virtual_identity::known;
+ vtable_ptr = core->vinfo->getVTable(vtname);
+ if (vtable_ptr)
+ known[vtable_ptr] = this;
+}
virtual_identity *virtual_identity::get(virtual_ptr instance_ptr)
{
@@ -265,8 +260,8 @@ virtual_identity *virtual_identity::get(virtual_ptr instance_ptr)
<< ", previous 0x" << unsigned(p->vtable_ptr) << std::dec << std::endl;
abort();
} else if (!p->vtable_ptr) {
- std::cerr << "class '" << p->getName() << "': vtable = 0x"
- << std::hex << unsigned(vtable) << std::dec << std::endl;
+ std::cerr << "" << std::endl;
}
known[vtable] = p;
diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp
index cf63e3b1a..36dbd9aae 100644
--- a/library/VersionInfoFactory.cpp
+++ b/library/VersionInfoFactory.cpp
@@ -118,7 +118,8 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
string type, name, value;
const char *cstr_type = pMemEntry->Value();
type = cstr_type;
- if(type == "global-address")
+ bool is_vtable = (type == "vtable-address");
+ if(is_vtable || type == "global-address")
{
const char *cstr_key = pMemEntry->Attribute("name");
if(!cstr_key)
@@ -129,7 +130,11 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
cerr << "Dummy symbol table entry: " << cstr_key << endl;
continue;
}
- mem->setAddress(cstr_key, strtol(cstr_value, 0, 0));
+ uint32_t addr = strtol(cstr_value, 0, 0);
+ if (is_vtable)
+ mem->setVTable(cstr_key, addr);
+ else
+ mem->setAddress(cstr_key, addr);
}
else if (type == "md5-hash")
{
diff --git a/library/include/VersionInfo.h b/library/include/VersionInfo.h
index d996722c0..7f82163ef 100644
--- a/library/include/VersionInfo.h
+++ b/library/include/VersionInfo.h
@@ -51,6 +51,7 @@ namespace DFHack
std::vector md5_list;
std::vector PE_list;
std::map Addresses;
+ std::map VTables;
uint32_t base;
std::string version;
OSType OS;
@@ -66,6 +67,7 @@ namespace DFHack
md5_list = rhs.md5_list;
PE_list = rhs.PE_list;
Addresses = rhs.Addresses;
+ VTables = rhs.VTables;
base = rhs.base;
version = rhs.version;
OS = rhs.OS;
@@ -79,13 +81,10 @@ namespace DFHack
int64_t newx = new_base;
int64_t rebase = newx - old;
base = new_base;
- auto iter = Addresses.begin();
- while (iter != Addresses.end())
- {
- uint32_t & ref = (*iter).second;
- ref += rebase;
- iter ++;
- }
+ for (auto iter = Addresses.begin(); iter != Addresses.end(); ++iter)
+ iter->second += rebase;
+ for (auto iter = VTables.begin(); iter != VTables.end(); ++iter)
+ iter->second += rebase;
};
void addMD5 (const std::string & _md5)
@@ -125,6 +124,7 @@ namespace DFHack
value = (T) (*i).second;
return true;
};
+
uint32_t getAddress (const std::string& key) const
{
auto i = Addresses.find(key);
@@ -133,6 +133,18 @@ namespace DFHack
return (*i).second;
}
+ void setVTable (const std::string& key, const uint32_t value)
+ {
+ VTables[key] = value;
+ };
+ void *getVTable (const std::string& key) const
+ {
+ auto i = VTables.find(key);
+ if(i == VTables.end())
+ return 0;
+ return (void*)i->second;
+ }
+
void setOS(const OSType os)
{
OS = os;
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index d884a734e..20b95bc23 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -454,6 +454,8 @@ bool Items::setOwner(df::item *item, df::unit *unit)
vector_erase_at(item->itemrefs, i);
}
+ item->flags.bits.owned = false;
+
if (unit)
{
auto ref = df::allocate();
@@ -466,8 +468,6 @@ bool Items::setOwner(df::item *item, df::unit *unit)
insert_into_vector(unit->owned_items, item->id);
item->itemrefs.push_back(ref);
}
- else
- item->flags.bits.owned = false;
return true;
}
From 38a8c43a25221fdd0dfb21da297cb4c87621d21c Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 12 Apr 2012 11:21:25 +0400
Subject: [PATCH 05/20] Reverse-rebase the vtable pointers printed to
stderr.log.
---
library/DataDefs.cpp | 4 +++-
library/include/VersionInfo.h | 6 +++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp
index 76c872445..05988e419 100644
--- a/library/DataDefs.cpp
+++ b/library/DataDefs.cpp
@@ -260,8 +260,10 @@ virtual_identity *virtual_identity::get(virtual_ptr instance_ptr)
<< ", previous 0x" << unsigned(p->vtable_ptr) << std::dec << std::endl;
abort();
} else if (!p->vtable_ptr) {
+ uint32_t pv = unsigned(vtable);
+ pv -= Core::getInstance().vinfo->getRebaseDelta();
std::cerr << "" << std::endl;
+ << std::hex << pv << std::dec << "'/>" << std::endl;
}
known[vtable] = p;
diff --git a/library/include/VersionInfo.h b/library/include/VersionInfo.h
index 7f82163ef..5ff20516e 100644
--- a/library/include/VersionInfo.h
+++ b/library/include/VersionInfo.h
@@ -53,12 +53,13 @@ namespace DFHack
std::map Addresses;
std::map VTables;
uint32_t base;
+ int rebase_delta;
std::string version;
OSType OS;
public:
VersionInfo()
{
- base = 0;
+ base = 0; rebase_delta = 0;
version = "invalid";
OS = OS_BAD;
};
@@ -69,11 +70,13 @@ namespace DFHack
Addresses = rhs.Addresses;
VTables = rhs.VTables;
base = rhs.base;
+ rebase_delta = rhs.rebase_delta;
version = rhs.version;
OS = rhs.OS;
};
uint32_t getBase () const { return base; };
+ int getRebaseDelta() const { return rebase_delta; }
void setBase (const uint32_t _base) { base = _base; };
void rebaseTo(const uint32_t new_base)
{
@@ -81,6 +84,7 @@ namespace DFHack
int64_t newx = new_base;
int64_t rebase = newx - old;
base = new_base;
+ rebase_delta += rebase;
for (auto iter = Addresses.begin(); iter != Addresses.end(); ++iter)
iter->second += rebase;
for (auto iter = VTables.begin(); iter != VTables.end(); ++iter)
From 2d8611a4803edc6bd37030ac303230fee208f718 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 12 Apr 2012 18:37:27 +0400
Subject: [PATCH 06/20] Add core api for moving items between ground and
containers.
---
LUA_API.rst | 20 ++++
Lua API.html | 15 +++
library/LuaApi.cpp | 73 +++++++++++--
library/include/modules/Items.h | 18 ++--
library/lua/dfhack.lua | 15 +++
library/modules/Items.cpp | 177 +++++++++++++++++++++++++++++---
library/modules/Maps.cpp | 2 +-
plugins/autodump.cpp | 10 +-
8 files changed, 289 insertions(+), 41 deletions(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index fc86070c3..df997008c 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -699,6 +699,10 @@ Units module
Items module
------------
+* ``dfhack.items.getPosition(item)``
+
+ Returns true *x,y,z* of the item.
+
* ``dfhack.items.getOwner(item)``
Returns the owner unit or *nil*.
@@ -708,6 +712,22 @@ Items module
Replaces the owner of the item. If unit is *nil*, removes ownership.
Returns *false* in case of error.
+* ``dfhack.items.getContainer(item)``
+
+ Returns the container item or *nil*.
+
+* ``dfhack.items.getContainedItems(item)``
+
+ Returns a list of items contained in this one.
+
+* ``dfhack.items.moveToGround(item,pos)``
+
+ Move the item to the ground at position. Returns *false* if impossible.
+
+* ``dfhack.items.moveToContainer(item,container)``
+
+ Move the item to the container. Returns *false* if impossible.
+
Maps module
-----------
diff --git a/Lua API.html b/Lua API.html
index 7c3eeddb9..4be1050fb 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -929,6 +929,9 @@ a lua list containing them.
+dfhack.items.getPosition(item)
+Returns true x,y,z of the item.
+
dfhack.items.getOwner(item)
Returns the owner unit or nil.
@@ -936,6 +939,18 @@ a lua list containing them.
Replaces the owner of the item. If unit is nil, removes ownership.
Returns false in case of error.
+dfhack.items.getContainer(item)
+Returns the container item or nil.
+
+dfhack.items.getContainedItems(item)
+Returns a list of items contained in this one.
+
+dfhack.items.moveToGround(item,pos)
+Move the item to the ground at position. Returns false if impossible.
+
+dfhack.items.moveToContainer(item,container)
+Move the item to the container. Returns false if impossible.
+
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index febc59026..25f654b8c 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -45,6 +45,7 @@ distribution.
#include "modules/Items.h"
#include "modules/Materials.h"
#include "modules/Maps.h"
+#include "modules/MapCache.h"
#include "LuaWrapper.h"
#include "LuaTools.h"
@@ -85,6 +86,33 @@ void push_pointer_vector(lua_State *state, const std::vector
&pvec)
}
}
+template
+T *get_checked_arg(lua_State *state, int arg)
+{
+ luaL_checkany(state, arg);
+
+ auto ptr = Lua::GetDFObject(state, arg);
+ if (!ptr)
+ luaL_argerror(state, arg, "invalid type");
+ return ptr;
+}
+
+int push_pos(lua_State *state, df::coord pos)
+{
+ if (!pos.isValid())
+ {
+ lua_pushnil(state);
+ return 1;
+ }
+ else
+ {
+ lua_pushinteger(state, pos.x);
+ lua_pushinteger(state, pos.y);
+ lua_pushinteger(state, pos.z);
+ return 3;
+ }
+}
+
/**************************************************
* Per-world persistent configuration storage API *
**************************************************/
@@ -610,12 +638,47 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
{ NULL, NULL }
};
+static bool items_moveToGround(df::item *item, df::coord pos)
+{
+ MapExtras::MapCache mc;
+ return Items::moveToGround(mc, item, pos);
+}
+
+static bool items_moveToContainer(df::item *item, df::item *container)
+{
+ MapExtras::MapCache mc;
+ return Items::moveToContainer(mc, item, container);
+}
+
static const LuaWrapper::FunctionReg dfhack_items_module[] = {
WRAPM(Items, getOwner),
WRAPM(Items, setOwner),
+ WRAPM(Items, getContainer),
+ WRAPN(moveToGround, items_moveToGround),
+ WRAPN(moveToContainer, items_moveToContainer),
{ NULL, NULL }
};
+static int items_getPosition(lua_State *state)
+{
+ return push_pos(state, Items::getPosition(get_checked_arg(state,1)));
+}
+
+static int items_getContainedItems(lua_State *state)
+{
+ std::vector pvec;
+ Items::getContainedItems(get_checked_arg(state,1),&pvec);
+ push_pointer_vector(state, pvec);
+ return 1;
+}
+
+static const luaL_Reg dfhack_items_funcs[] = {
+ { "getPosition", items_getPosition },
+ { "getContainedItems", items_getContainedItems },
+ { NULL, NULL }
+};
+
+
static bool maps_isBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y)
{
return Maps::isBlockBurrowTile(burrow, block, df::coord2d(x,y));
@@ -642,14 +705,8 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
static int maps_listBurrowBlocks(lua_State *state)
{
- luaL_checkany(state, 1);
-
- auto ptr = Lua::GetDFObject(state, 1);
- if (!ptr)
- luaL_argerror(state, 1, "invalid burrow type");
-
std::vector pvec;
- Maps::listBurrowBlocks(&pvec, ptr);
+ Maps::listBurrowBlocks(&pvec, get_checked_arg(state,1));
push_pointer_vector(state, pvec);
return 1;
}
@@ -673,6 +730,6 @@ void OpenDFHackApi(lua_State *state)
OpenModule(state, "gui", dfhack_gui_module);
OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs);
OpenModule(state, "units", dfhack_units_module);
- OpenModule(state, "items", dfhack_items_module);
+ OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs);
OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs);
}
diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h
index 9bab02cc8..e7720fa91 100644
--- a/library/include/modules/Items.h
+++ b/library/include/modules/Items.h
@@ -42,6 +42,10 @@ namespace df
struct itemdef;
}
+namespace MapExtras {
+ class MapCache;
+}
+
/**
* \defgroup grp_items Items module and its types
* @ingroup grp_modules
@@ -128,13 +132,15 @@ DFHACK_EXPORT df::unit *getOwner(df::item *item);
DFHACK_EXPORT bool setOwner(df::item *item, df::unit *unit);
/// which item is it contained in?
-DFHACK_EXPORT int32_t getItemContainerID(const df::item * item);
-DFHACK_EXPORT df::item *getItemContainer(const df::item * item);
+DFHACK_EXPORT df::item *getContainer(df::item *item);
/// which items does it contain?
-DFHACK_EXPORT bool getContainedItems(const df::item * item, /*output*/ std::vector &items);
+DFHACK_EXPORT void getContainedItems(df::item *item, /*output*/ std::vector *items);
+
+/// Returns the true position of the item.
+DFHACK_EXPORT df::coord getPosition(df::item *item);
+
+DFHACK_EXPORT bool moveToGround(MapExtras::MapCache &mc, df::item *item, df::coord pos);
+DFHACK_EXPORT bool moveToContainer(MapExtras::MapCache &mc, df::item *item, df::item *container);
-/// read item references, filtered by class
-DFHACK_EXPORT bool readItemRefs(const df::item * item, const df::general_ref_type type,
- /*output*/ std::vector &values);
}
}
\ No newline at end of file
diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua
index a6606d152..626f60bec 100644
--- a/library/lua/dfhack.lua
+++ b/library/lua/dfhack.lua
@@ -86,6 +86,21 @@ function copyall(table)
return rv
end
+function pos2xyz(pos)
+ local x = pos.x
+ if x and x ~= -30000 then
+ return x, pos.y, pos.z
+ end
+end
+
+function xyz2pos(x,y,z)
+ if x then
+ return {x=x,y=y,z=z}
+ else
+ return {x=-30000,y=-30000,z=-30000}
+ end
+end
+
function dfhack.persistent:__tostring()
return ""
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index 20b95bc23..ca15ed278 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -39,6 +39,7 @@ using namespace std;
#include "modules/Materials.h"
#include "modules/Items.h"
#include "modules/Units.h"
+#include "modules/MapCache.h"
#include "ModuleFactory.h"
#include "Core.h"
#include "Error.h"
@@ -46,6 +47,7 @@ using namespace std;
#include "df/world.h"
#include "df/item.h"
+#include "df/building.h"
#include "df/tool_uses.h"
#include "df/itemdef_weaponst.h"
#include "df/itemdef_trapcompst.h"
@@ -65,6 +67,8 @@ using namespace std;
#include "df/job_item.h"
#include "df/general_ref.h"
#include "df/general_ref_unit_itemownerst.h"
+#include "df/general_ref_contains_itemst.h"
+#include "df/general_ref_contained_in_itemst.h"
using namespace DFHack;
using namespace df::enums;
@@ -472,44 +476,183 @@ bool Items::setOwner(df::item *item, df::unit *unit)
return true;
}
-
-int32_t Items::getItemContainerID(const df::item * item)
+df::item *Items::getContainer(df::item * item)
{
+ CHECK_NULL_POINTER(item);
+
for (size_t i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == general_ref_type::CONTAINED_IN_ITEM)
- return ref->getID();
+ return ref->getItem();
}
- return -1;
+
+ return NULL;
}
-df::item *Items::getItemContainer(const df::item * item)
+void Items::getContainedItems(df::item *item, std::vector *items)
{
+ CHECK_NULL_POINTER(item);
+
+ items->clear();
+
for (size_t i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
- if (ref->getType() == general_ref_type::CONTAINED_IN_ITEM)
- return ref->getItem();
+ if (ref->getType() != general_ref_type::CONTAINS_ITEM)
+ continue;
+
+ auto child = ref->getItem();
+ if (child)
+ items->push_back(child);
}
- return NULL;
}
-bool Items::getContainedItems(const df::item * item, std::vector &items)
+df::coord Items::getPosition(df::item *item)
{
- return readItemRefs(item, general_ref_type::CONTAINS_ITEM, items);
+ CHECK_NULL_POINTER(item);
+
+ if (item->flags.bits.in_inventory ||
+ item->flags.bits.in_chest ||
+ item->flags.bits.in_building)
+ {
+ for (size_t i = 0; i < item->itemrefs.size(); i++)
+ {
+ df::general_ref *ref = item->itemrefs[i];
+
+ switch (ref->getType())
+ {
+ case general_ref_type::CONTAINED_IN_ITEM:
+ if (auto item2 = ref->getItem())
+ return getPosition(item2);
+ break;
+
+ case general_ref_type::UNIT_HOLDER:
+ if (auto unit = ref->getUnit())
+ return unit->pos;
+ break;
+
+ case general_ref_type::BUILDING_HOLDER:
+ if (auto bld = ref->getBuilding())
+ return df::coord(bld->centerx, bld->centery, bld->z);
+ break;
+ }
+ }
+ }
+
+ return item->pos;
}
-bool Items::readItemRefs(const df::item * item, df::general_ref_type type, std::vector &values)
+static void removeRef(std::vector &vec, df::general_ref_type type, int id)
{
- values.clear();
+ for (int i = vec.size()-1; i >= 0; i--)
+ {
+ df::general_ref *ref = vec[i];
+ if (ref->getType() != type || ref->getID() != id)
+ continue;
- for (size_t i = 0; i < item->itemrefs.size(); i++)
+ vector_erase_at(vec, i);
+ delete ref;
+ }
+}
+
+static bool detachItem(MapExtras::MapCache &mc, df::item *item)
+{
+ if (item->flags.bits.on_ground)
{
- df::general_ref *ref = item->itemrefs[i];
- if (ref->getType() == type)
- values.push_back(ref->getID());
+ if (!mc.removeItemOnGround(item))
+ Core::printerr("Item was marked on_ground, but not in block: %d (%d,%d,%d)\n",
+ item->id, item->pos.x, item->pos.y, item->pos.z);
+
+ item->flags.bits.on_ground = false;
+ return true;
}
+ else if (item->flags.bits.in_inventory)
+ {
+ bool found = false;
- return !values.empty();
+ for (int i = item->itemrefs.size()-1; i >= 0; i--)
+ {
+ df::general_ref *ref = item->itemrefs[i];
+
+ switch (ref->getType())
+ {
+ case general_ref_type::CONTAINED_IN_ITEM:
+ if (auto item2 = ref->getItem())
+ removeRef(item2->itemrefs, general_ref_type::CONTAINS_ITEM, item->id);
+ break;
+
+ case general_ref_type::UNIT_HOLDER:
+ case general_ref_type::BUILDING_HOLDER:
+ return false;
+
+ default:
+ continue;
+ }
+
+ found = true;
+ vector_erase_at(item->itemrefs, i);
+ delete ref;
+ }
+
+ if (!found)
+ return false;
+
+ item->flags.bits.in_inventory = false;
+ return true;
+ }
+ else
+ return false;
+}
+
+static void putOnGround(MapExtras::MapCache &mc, df::item *item, df::coord pos)
+{
+ item->pos = pos;
+ item->flags.bits.on_ground = true;
+
+ if (!mc.addItemOnGround(item))
+ Core::printerr("Could not add item %d to ground at (%d,%d,%d)\n",
+ item->id, pos.x, pos.y, pos.z);
+}
+
+bool DFHack::Items::moveToGround(MapExtras::MapCache &mc, df::item *item, df::coord pos)
+{
+ CHECK_NULL_POINTER(item);
+
+ if (!detachItem(mc, item))
+ return false;
+
+ putOnGround(mc, item, pos);
+ return true;
+}
+
+bool DFHack::Items::moveToContainer(MapExtras::MapCache &mc, df::item *item, df::item *container)
+{
+ CHECK_NULL_POINTER(item);
+ CHECK_NULL_POINTER(container);
+
+ if (!detachItem(mc, item))
+ return false;
+
+ auto ref1 = df::allocate();
+ auto ref2 = df::allocate();
+
+ if (!ref1 || !ref2)
+ {
+ delete ref1; delete ref2;
+ Core::printerr("Could not allocate container refs.\n");
+ putOnGround(mc, item, getPosition(container));
+ return false;
+ }
+
+ item->pos = container->pos;
+ item->flags.bits.in_inventory = true;
+ container->flags.bits.container = true;
+
+ ref1->item_id = item->id;
+ container->itemrefs.push_back(ref1);
+ ref2->item_id = container->id;
+ item->itemrefs.push_back(ref2);
+
+ return true;
}
diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp
index c0aa9b634..fce80d775 100644
--- a/library/modules/Maps.cpp
+++ b/library/modules/Maps.cpp
@@ -596,7 +596,7 @@ void MapExtras::Block::init_item_counts()
if (item_counts) return;
item_counts = new T_item_counts[16];
- memset(item_counts, 0, sizeof(T_item_counts));
+ memset(item_counts, 0, sizeof(T_item_counts)*16);
if (!block) return;
diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp
index a71555b7a..2620d9dea 100644
--- a/plugins/autodump.cpp
+++ b/plugins/autodump.cpp
@@ -182,15 +182,7 @@ static command_result autodump_main(color_ostream &out, vector & parame
// Don't move items if they're already at the cursor
if (pos_cursor != pos_item)
- {
- if (!MC.removeItemOnGround(itm))
- out.printerr("Item %d wasn't in the source block.\n", itm->id);
-
- itm->pos = pos_cursor;
-
- if (!MC.addItemOnGround(itm))
- out.printerr("Could not add item %d to destination block.\n", itm->id);
- }
+ Items::moveToGround(MC, itm, pos_cursor);
}
else // destroy
{
From 37cfb1fdcd01e4a7dce1a2b759cc2655bd42cf03 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Fri, 13 Apr 2012 16:10:19 +0400
Subject: [PATCH 07/20] Add unit position and container api.
---
LUA_API.rst | 10 +++++++++-
Lua API.html | 8 +++++++-
library/LuaApi.cpp | 13 ++++++++++++-
library/include/modules/Units.h | 5 +++++
library/modules/Items.cpp | 8 +++++++-
library/modules/Units.cpp | 29 +++++++++++++++++++++++++++++
6 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index df997008c..673053189 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.
@@ -701,7 +709,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)``
diff --git a/Lua API.html b/Lua API.html
index 4be1050fb..32a3b7f04 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.
@@ -930,7 +936,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.
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 25f654b8c..6792c921e 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -627,6 +627,7 @@ 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),
@@ -638,6 +639,16 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
{ 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;
@@ -729,7 +740,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/include/modules/Units.h b/library/include/modules/Units.h
index 12e687112..d7dadb21b 100644
--- a/library/include/modules/Units.h
+++ b/library/include/modules/Units.h
@@ -193,6 +193,11 @@ DFHACK_EXPORT int32_t GetDwarfCivId ( void );
DFHACK_EXPORT void CopyNameTo(df::unit *creature, df::language_name * target);
+/// Returns the true position of the unit (non-trivial in case of caged).
+DFHACK_EXPORT df::coord getPosition(df::unit *unit);
+
+DFHACK_EXPORT df::item *getContainer(df::unit *unit);
+
DFHACK_EXPORT void setNickname(df::unit *unit, std::string nick);
DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit);
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index ca15ed278..9d0657e19 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -529,7 +529,7 @@ df::coord Items::getPosition(df::item *item)
case general_ref_type::UNIT_HOLDER:
if (auto unit = ref->getUnit())
- return unit->pos;
+ return Units::getPosition(unit);
break;
case general_ref_type::BUILDING_HOLDER:
@@ -579,7 +579,11 @@ static bool detachItem(MapExtras::MapCache &mc, df::item *item)
{
case general_ref_type::CONTAINED_IN_ITEM:
if (auto item2 = ref->getItem())
+ {
+ item2->flags.bits.weight_computed = false;
+
removeRef(item2->itemrefs, general_ref_type::CONTAINS_ITEM, item->id);
+ }
break;
case general_ref_type::UNIT_HOLDER:
@@ -649,6 +653,8 @@ bool DFHack::Items::moveToContainer(MapExtras::MapCache &mc, df::item *item, df:
item->flags.bits.in_inventory = true;
container->flags.bits.container = true;
+ container->flags.bits.weight_computed = false;
+
ref1->item_id = item->id;
container->itemrefs.push_back(ref1);
ref2->item_id = container->id;
diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp
index 3e58e0d5c..7dbb40c97 100644
--- a/library/modules/Units.cpp
+++ b/library/modules/Units.cpp
@@ -40,6 +40,7 @@ using namespace std;
// we connect to those
#include "modules/Units.h"
+#include "modules/Items.h"
#include "modules/Materials.h"
#include "modules/Translation.h"
#include "ModuleFactory.h"
@@ -500,6 +501,34 @@ void Units::CopyNameTo(df::unit * creature, df::language_name * target)
Translation::copyName(&creature->name, target);
}
+df::coord Units::getPosition(df::unit *unit)
+{
+ CHECK_NULL_POINTER(unit);
+
+ if (unit->flags1.bits.caged)
+ {
+ auto cage = getContainer(unit);
+ if (cage)
+ return Items::getPosition(cage);
+ }
+
+ return unit->pos;
+}
+
+df::item *Units::getContainer(df::unit *unit)
+{
+ CHECK_NULL_POINTER(unit);
+
+ for (size_t i = 0; i < unit->refs.size(); i++)
+ {
+ df::general_ref *ref = unit->refs[i];
+ if (ref->getType() == general_ref_type::CONTAINED_IN_ITEM)
+ return ref->getItem();
+ }
+
+ return NULL;
+}
+
void Units::setNickname(df::unit *unit, std::string nick)
{
CHECK_NULL_POINTER(unit);
From 2f54a48e6391720c62a62cad9839f3d36a6e7385 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Fri, 13 Apr 2012 21:41:42 +0400
Subject: [PATCH 08/20] Add a plugin that makes selected burrows auto-grow on
digging.
---
library/include/TileTypes.h | 12 +
library/include/modules/Maps.h | 8 +-
plugins/CMakeLists.txt | 1 +
plugins/burrows.cpp | 413 +++++++++++++++++++++++++++++++++
4 files changed, 430 insertions(+), 4 deletions(-)
create mode 100644 plugins/burrows.cpp
diff --git a/library/include/TileTypes.h b/library/include/TileTypes.h
index 26df7c3cd..55628b3df 100644
--- a/library/include/TileTypes.h
+++ b/library/include/TileTypes.h
@@ -203,6 +203,18 @@ namespace DFHack
return ENUM_ATTR(tiletype_shape, passable_flow, tileShape(tiletype));
}
+ inline
+ bool isWalkable(df::tiletype tiletype)
+ {
+ return ENUM_ATTR(tiletype_shape, walkable, tileShape(tiletype));
+ }
+
+ inline
+ bool isWalkableUp(df::tiletype tiletype)
+ {
+ return ENUM_ATTR(tiletype_shape, walkable_up, tileShape(tiletype));
+ }
+
inline
bool isWallTerrain(df::tiletype tiletype)
{
diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h
index 0de262264..3cd1187a5 100644
--- a/library/include/modules/Maps.h
+++ b/library/include/modules/Maps.h
@@ -262,12 +262,12 @@ extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, d
DFHACK_EXPORT df::burrow *findBurrowByName(std::string name);
-void listBurrowBlocks(std::vector *pvec, df::burrow *burrow);
+DFHACK_EXPORT void listBurrowBlocks(std::vector *pvec, df::burrow *burrow);
-df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false);
+DFHACK_EXPORT df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false);
-bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile);
-bool setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable);
+DFHACK_EXPORT bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile);
+DFHACK_EXPORT bool setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable);
inline bool isBurrowTile(df::burrow *burrow, df::coord tile) {
return isBlockBurrowTile(burrow, getTileBlock(tile), tile);
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 6c2a537d1..d30d25697 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -97,6 +97,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(feature feature.cpp)
DFHACK_PLUGIN(lair lair.cpp)
DFHACK_PLUGIN(zone zone.cpp)
+ DFHACK_PLUGIN(burrows burrows.cpp)
# not yet. busy with other crud again...
#DFHACK_PLUGIN(versionosd versionosd.cpp)
endif()
diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp
new file mode 100644
index 000000000..a559573ac
--- /dev/null
+++ b/plugins/burrows.cpp
@@ -0,0 +1,413 @@
+#include "Core.h"
+#include "Console.h"
+#include "Export.h"
+#include "PluginManager.h"
+
+#include "modules/Gui.h"
+#include "modules/Job.h"
+#include "modules/Maps.h"
+#include "modules/MapCache.h"
+#include "modules/World.h"
+#include "TileTypes.h"
+
+#include "DataDefs.h"
+#include "df/ui.h"
+#include "df/world.h"
+#include "df/unit.h"
+#include "df/burrow.h"
+#include "df/map_block.h"
+#include "df/job.h"
+#include "df/job_list_link.h"
+
+#include "MiscUtils.h"
+
+#include
+
+using std::vector;
+using std::string;
+using std::endl;
+using namespace DFHack;
+using namespace df::enums;
+using namespace dfproto;
+
+using df::global::ui;
+using df::global::world;
+
+/*
+ * Initialization.
+ */
+
+static command_result burrow(color_ostream &out, vector & parameters);
+
+DFHACK_PLUGIN("burrows");
+
+static void init_map(color_ostream &out);
+static void deinit_map(color_ostream &out);
+
+DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands)
+{
+ commands.push_back(PluginCommand(
+ "burrow", "Miscellaneous burrow control.", burrow, false,
+ " burrow enable options...\n"
+ " burrow disable options...\n"
+ " Enable or disable features of the plugin.\n"
+ " See below for a list and explanation.\n"
+ "Implemented features:\n"
+ " auto-grow\n"
+ " When a wall inside a burrow with a name ending in '+' is dug\n"
+ " out, the burrow is extended to newly-revealed adjacent walls.\n"
+ " Digging 1-wide corridors with the miner inside the burrow is SLOW.\n"
+ ));
+
+ if (Core::getInstance().isMapLoaded())
+ init_map(out);
+
+ return CR_OK;
+}
+
+DFhackCExport command_result plugin_shutdown ( color_ostream &out )
+{
+ deinit_map(out);
+
+ return CR_OK;
+}
+
+DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
+{
+ switch (event) {
+ case SC_MAP_LOADED:
+ deinit_map(out);
+ if (df::global::game_mode &&
+ *df::global::game_mode == GAMEMODE_DWARF)
+ init_map(out);
+ break;
+ case SC_MAP_UNLOADED:
+ deinit_map(out);
+ break;
+ default:
+ break;
+ }
+
+ return CR_OK;
+}
+
+/*
+ * State change tracking.
+ */
+
+static int name_burrow_id = -1;
+
+static void handle_burrow_rename(color_ostream &out, df::burrow *burrow);
+
+static void detect_burrow_renames(color_ostream &out)
+{
+ if (ui->main.mode == ui_sidebar_mode::Burrows &&
+ ui->burrows.in_edit_name_mode &&
+ ui->burrows.sel_id >= 0)
+ {
+ name_burrow_id = ui->burrows.sel_id;
+ }
+ else if (name_burrow_id >= 0)
+ {
+ auto burrow = df::burrow::find(name_burrow_id);
+ name_burrow_id = -1;
+ if (burrow)
+ handle_burrow_rename(out, burrow);
+ }
+}
+
+struct DigJob {
+ int id;
+ df::job_type job;
+ df::coord pos;
+ df::tiletype old_tile;
+};
+
+static int next_job_id_save = 0;
+static std::map diggers;
+
+static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord pos,
+ df::tiletype old_tile, df::tiletype new_tile);
+
+static void detect_digging(color_ostream &out)
+{
+ for (auto it = diggers.begin(); it != diggers.end();)
+ {
+ auto worker = df::unit::find(it->first);
+
+ if (!worker || !worker->job.current_job ||
+ worker->job.current_job->id != it->second.id)
+ {
+ //out.print("Dig job %d expired.\n", it->second.id);
+
+ df::coord pos = it->second.pos;
+
+ if (auto block = Maps::getTileBlock(pos))
+ {
+ df::tiletype new_tile = block->tiletype[pos.x&15][pos.y&15];
+
+ //out.print("Tile %d -> %d\n", it->second.old_tile, new_tile);
+
+ if (new_tile != it->second.old_tile)
+ {
+ handle_dig_complete(out, it->second.job, pos, it->second.old_tile, new_tile);
+
+ //if (worker && !worker->job.current_job)
+ // worker->counters.think_counter = worker->counters.job_counter = 0;
+ }
+ }
+
+ auto cur = it; ++it; diggers.erase(cur);
+ }
+ else
+ ++it;
+ }
+
+ std::vector jvec;
+
+ if (Job::listNewlyCreated(&jvec, &next_job_id_save))
+ {
+ for (size_t i = 0; i < jvec.size(); i++)
+ {
+ auto job = jvec[i];
+ auto type = ENUM_ATTR(job_type, type, job->job_type);
+ if (type != job_type_class::Digging)
+ continue;
+
+ auto worker = Job::getWorker(job);
+ if (!worker)
+ continue;
+
+ df::coord pos = job->pos;
+ auto block = Maps::getTileBlock(pos);
+ if (!block)
+ continue;
+
+ auto &info = diggers[worker->id];
+
+ //out.print("New dig job %d.\n", job->id);
+
+ info.id = job->id;
+ info.job = job->job_type;
+ info.pos = pos;
+ info.old_tile = block->tiletype[pos.x&15][pos.y&15];
+ }
+ }
+}
+
+static bool active = false;
+static bool auto_grow = false;
+static std::vector grow_burrows;
+
+DFhackCExport command_result plugin_onupdate(color_ostream &out)
+{
+ if (!active || !auto_grow)
+ return CR_OK;
+
+ detect_burrow_renames(out);
+ detect_digging(out);
+ return CR_OK;
+}
+
+/*
+ * Config and processing
+ */
+
+static void parse_names()
+{
+ auto &list = ui->burrows.list;
+
+ grow_burrows.clear();
+
+ for (size_t i = 0; i < list.size(); i++)
+ {
+ auto burrow = list[i];
+
+ if (!burrow->name.empty() && burrow->name[burrow->name.size()-1] == '+')
+ grow_burrows.push_back(burrow->id);
+ }
+}
+
+static void reset_tracking()
+{
+ name_burrow_id = -1;
+ diggers.clear();
+ next_job_id_save = 0;
+}
+
+static void init_map(color_ostream &out)
+{
+ auto config = Core::getInstance().getWorld()->GetPersistentData("burrows/config");
+ if (config.isValid())
+ {
+ auto_grow = !!(config.ival(0) & 1);
+ }
+
+ parse_names();
+ reset_tracking();
+ active = true;
+
+ if (auto_grow && !grow_burrows.empty())
+ out.print("Auto-growing %d burrows.\n", grow_burrows.size());
+}
+
+static void deinit_map(color_ostream &out)
+{
+ active = false;
+ auto_grow = false;
+ reset_tracking();
+}
+
+static PersistentDataItem create_config(color_ostream &out)
+{
+ bool created;
+ auto rv = Core::getInstance().getWorld()->GetPersistentData("burrows/config", &created);
+ if (created && rv.isValid())
+ rv.ival(0) = 0;
+ if (!rv.isValid())
+ out.printerr("Could not write configuration.");
+ return rv;
+}
+
+static void enable_auto_grow(color_ostream &out, bool enable)
+{
+ if (enable == auto_grow)
+ return;
+
+ auto config = create_config(out);
+ if (!config.isValid())
+ return;
+
+ if (enable)
+ config.ival(0) |= 1;
+ else
+ config.ival(0) &= ~1;
+
+ auto_grow = enable;
+
+ if (enable)
+ {
+ parse_names();
+ reset_tracking();
+ }
+}
+
+static void handle_burrow_rename(color_ostream &out, df::burrow *burrow)
+{
+ parse_names();
+}
+
+static void add_to_burrows(std::vector &burrows, df::coord pos)
+{
+ for (size_t i = 0; i < burrows.size(); i++)
+ Maps::setBurrowTile(burrows[i], pos, true);
+}
+
+static void add_walls_to_burrows(color_ostream &out, std::vector &burrows,
+ MapExtras::MapCache &mc, df::coord pos1, df::coord pos2)
+{
+ for (int x = pos1.x; x <= pos2.x; x++)
+ {
+ for (int y = pos1.y; y <= pos2.y; y++)
+ {
+ for (int z = pos1.z; z <= pos2.z; z++)
+ {
+ df::coord pos(x,y,z);
+
+ auto tile = mc.tiletypeAt(pos);
+
+ if (isWallTerrain(tile))
+ add_to_burrows(burrows, pos);
+ }
+ }
+ }
+}
+
+static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord pos,
+ df::tiletype old_tile, df::tiletype new_tile)
+{
+ if (!isWalkable(new_tile))
+ return;
+
+ std::vector to_grow;
+
+ for (size_t i = 0; i < grow_burrows.size(); i++)
+ {
+ auto b = df::burrow::find(grow_burrows[i]);
+ if (b && Maps::isBurrowTile(b, pos))
+ to_grow.push_back(b);
+ }
+
+ //out.print("%d to grow.\n", to_grow.size());
+
+ if (to_grow.empty())
+ return;
+
+ MapExtras::MapCache mc;
+
+ if (!isWalkable(old_tile))
+ {
+ add_walls_to_burrows(out, to_grow, mc, pos+df::coord(-1,-1,0), pos+df::coord(1,1,0));
+
+ if (isWalkableUp(new_tile))
+ add_to_burrows(to_grow, pos+df::coord(0,0,1));
+
+ if (tileShape(new_tile) == tiletype_shape::RAMP)
+ {
+ add_walls_to_burrows(out, to_grow, mc,
+ pos+df::coord(-1,-1,1), pos+df::coord(1,1,1));
+ }
+ }
+
+ if (LowPassable(new_tile) && !LowPassable(old_tile))
+ {
+ add_to_burrows(to_grow, pos-df::coord(0,0,1));
+
+ if (tileShape(new_tile) == tiletype_shape::RAMP_TOP)
+ {
+ add_walls_to_burrows(out, to_grow, mc,
+ pos+df::coord(-1,-1,-1), pos+df::coord(1,1,-1));
+ }
+ }
+}
+
+static command_result burrow(color_ostream &out, vector ¶meters)
+{
+ CoreSuspender suspend;
+
+ if (!active)
+ {
+ out.printerr("The plugin cannot be used without map.\n");
+ return CR_FAILURE;
+ }
+
+ string cmd;
+ if (!parameters.empty())
+ cmd = parameters[0];
+
+ if (cmd == "enable" || cmd == "disable")
+ {
+ if (parameters.size() < 2)
+ return CR_WRONG_USAGE;
+
+ bool state = (cmd == "enable");
+
+ for (int i = 1; i < parameters.size(); i++)
+ {
+ string &option = parameters[i];
+
+ if (option == "auto-grow")
+ enable_auto_grow(out, state);
+ else
+ return CR_WRONG_USAGE;
+ }
+ }
+ else
+ {
+ if (!parameters.empty() && cmd != "?")
+ out.printerr("Invalid command: %s\n", cmd.c_str());
+ return CR_WRONG_USAGE;
+ }
+
+ return CR_OK;
+}
From 7a34a89f53071a8368ec5bd064accb10354b6d56 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sat, 14 Apr 2012 14:12:59 +0400
Subject: [PATCH 09/20] Add burrow subcommands to modify burrow unit and tile
sets.
---
LUA_API.rst | 8 +
Lua API.html | 6 +
library/LuaApi.cpp | 2 +
.../df/custom/block_burrow.methods.inc | 9 +-
.../block_square_event_mineralst.methods.inc | 9 +-
library/include/modules/Maps.h | 8 +
library/include/modules/Units.h | 4 +
library/modules/Maps.cpp | 71 +++++
library/modules/Units.cpp | 45 +++
plugins/burrows.cpp | 262 +++++++++++++++++-
10 files changed, 413 insertions(+), 11 deletions(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index 673053189..d5af5e7a4 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -695,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.
@@ -776,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 32a3b7f04..66385840b 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -924,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.
@@ -989,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/LuaApi.cpp b/library/LuaApi.cpp
index 6792c921e..917e44d38 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -634,6 +634,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, isDead),
WRAPM(Units, isAlive),
WRAPM(Units, isSane),
+ WRAPM(Units, clearBurrowMembers),
WRAPM(Units, isInBurrow),
WRAPM(Units, setInBurrow),
{ NULL, NULL }
@@ -707,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),
diff --git a/library/include/df/custom/block_burrow.methods.inc b/library/include/df/custom/block_burrow.methods.inc
index 7754ab0db..216a58662 100644
--- a/library/include/df/custom/block_burrow.methods.inc
+++ b/library/include/df/custom/block_burrow.methods.inc
@@ -16,4 +16,11 @@ inline void setassignment( int x, int y, bool bit )
tile_bitmask[y] |= (1 << x);
else
tile_bitmask[y] &= ~(1 << x);
-}
\ No newline at end of file
+}
+bool has_assignments()
+{
+ for (int i = 0; i < 16; i++)
+ if (tile_bitmask[i])
+ return true;
+ return false;
+}
diff --git a/library/include/df/custom/block_square_event_mineralst.methods.inc b/library/include/df/custom/block_square_event_mineralst.methods.inc
index 7754ab0db..216a58662 100644
--- a/library/include/df/custom/block_square_event_mineralst.methods.inc
+++ b/library/include/df/custom/block_square_event_mineralst.methods.inc
@@ -16,4 +16,11 @@ inline void setassignment( int x, int y, bool bit )
tile_bitmask[y] |= (1 << x);
else
tile_bitmask[y] &= ~(1 << x);
-}
\ No newline at end of file
+}
+bool has_assignments()
+{
+ for (int i = 0; i < 16; i++)
+ if (tile_bitmask[i])
+ return true;
+ return false;
+}
diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h
index 3cd1187a5..b7341f87c 100644
--- a/library/include/modules/Maps.h
+++ b/library/include/modules/Maps.h
@@ -263,8 +263,16 @@ extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, d
DFHACK_EXPORT df::burrow *findBurrowByName(std::string name);
DFHACK_EXPORT void listBurrowBlocks(std::vector *pvec, df::burrow *burrow);
+DFHACK_EXPORT void clearBurrowTiles(df::burrow *burrow);
DFHACK_EXPORT df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false);
+DFHACK_EXPORT bool deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask);
+
+inline bool deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block)
+{
+ return deleteBlockBurrowMask(burrow, block, getBlockBurrowMask(burrow, block));
+}
+
DFHACK_EXPORT bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile);
DFHACK_EXPORT bool setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable);
diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h
index d7dadb21b..e093ed1ef 100644
--- a/library/include/modules/Units.h
+++ b/library/include/modules/Units.h
@@ -206,6 +206,10 @@ DFHACK_EXPORT df::nemesis_record *getNemesis(df::unit *unit);
DFHACK_EXPORT bool isDead(df::unit *unit);
DFHACK_EXPORT bool isAlive(df::unit *unit);
DFHACK_EXPORT bool isSane(df::unit *unit);
+DFHACK_EXPORT bool isCitizen(df::unit *unit);
+DFHACK_EXPORT bool isDwarf(df::unit *unit);
+
+DFHACK_EXPORT void clearBurrowMembers(df::burrow *burrow);
DFHACK_EXPORT bool isInBurrow(df::unit *unit, df::burrow *burrow);
DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable);
diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp
index fce80d775..327e26986 100644
--- a/library/modules/Maps.cpp
+++ b/library/modules/Maps.cpp
@@ -715,6 +715,42 @@ void Maps::listBurrowBlocks(std::vector *pvec, df::burrow *burro
}
}
+static void destroyBurrowMask(df::block_burrow *mask)
+{
+ if (!mask) return;
+
+ auto link = mask->link;
+
+ link->prev->next = link->next;
+ if (link->next)
+ link->next->prev = link->prev;
+ delete link;
+
+ delete mask;
+}
+
+void Maps::clearBurrowTiles(df::burrow *burrow)
+{
+ CHECK_NULL_POINTER(burrow);
+
+ df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
+
+ for (size_t i = 0; i < burrow->block_x.size(); i++)
+ {
+ df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]);
+
+ auto block = getBlock(pos - base);
+ if (!block)
+ continue;
+
+ destroyBurrowMask(getBlockBurrowMask(burrow, block));
+ }
+
+ burrow->block_x.clear();
+ burrow->block_y.clear();
+ burrow->block_z.clear();
+}
+
df::block_burrow *Maps::getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create)
{
CHECK_NULL_POINTER(burrow);
@@ -754,6 +790,36 @@ df::block_burrow *Maps::getBlockBurrowMask(df::burrow *burrow, df::map_block *bl
return NULL;
}
+bool Maps::deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask)
+{
+ CHECK_NULL_POINTER(burrow);
+ CHECK_NULL_POINTER(block);
+
+ if (!mask)
+ return false;
+
+ df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
+ df::coord pos = base + block->map_pos/16;
+
+ destroyBurrowMask(mask);
+
+ for (size_t i = 0; i < burrow->block_x.size(); i++)
+ {
+ df::coord cur(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]);
+
+ if (cur == pos)
+ {
+ vector_erase_at(burrow->block_x, i);
+ vector_erase_at(burrow->block_y, i);
+ vector_erase_at(burrow->block_z, i);
+
+ break;
+ }
+ }
+
+ return true;
+}
+
bool Maps::isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile)
{
CHECK_NULL_POINTER(burrow);
@@ -774,8 +840,13 @@ bool Maps::setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coor
auto mask = getBlockBurrowMask(burrow, block, enable);
if (mask)
+ {
mask->setassignment(tile & 15, enable);
+ if (!enable && !mask->has_assignments())
+ deleteBlockBurrowMask(burrow, block, mask);
+ }
+
return true;
}
diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp
index 7dbb40c97..8b44d4cf9 100644
--- a/library/modules/Units.cpp
+++ b/library/modules/Units.cpp
@@ -653,6 +653,51 @@ bool DFHack::Units::isSane(df::unit *unit)
return true;
}
+bool DFHack::Units::isCitizen(df::unit *unit)
+{
+ CHECK_NULL_POINTER(unit);
+
+ return unit->civ_id == ui->civ_id &&
+ !unit->flags1.bits.merchant &&
+ !unit->flags1.bits.diplomat &&
+ !unit->flags2.bits.resident &&
+ !unit->flags1.bits.dead &&
+ !unit->flags3.bits.ghostly;
+}
+
+bool DFHack::Units::isDwarf(df::unit *unit)
+{
+ CHECK_NULL_POINTER(unit);
+
+ return unit->race == ui->race_id;
+}
+
+void DFHack::Units::clearBurrowMembers(df::burrow *burrow)
+{
+ CHECK_NULL_POINTER(burrow);
+
+ for (size_t i = 0; i < burrow->units.size(); i++)
+ {
+ auto unit = df::unit::find(burrow->units[i]);
+
+ if (unit)
+ erase_from_vector(unit->burrows, burrow->id);
+ }
+
+ burrow->units.clear();
+
+ // Sync ui if active
+ if (ui && ui->main.mode == ui_sidebar_mode::Burrows &&
+ ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id)
+ {
+ auto &sel = ui->burrows.sel_units;
+
+ for (size_t i = 0; i < sel.size(); i++)
+ sel[i] = false;
+ }
+}
+
+
bool DFHack::Units::isInBurrow(df::unit *unit, df::burrow *burrow)
{
CHECK_NULL_POINTER(unit);
diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp
index a559573ac..c973405ee 100644
--- a/plugins/burrows.cpp
+++ b/plugins/burrows.cpp
@@ -8,6 +8,7 @@
#include "modules/Maps.h"
#include "modules/MapCache.h"
#include "modules/World.h"
+#include "modules/Units.h"
#include "TileTypes.h"
#include "DataDefs.h"
@@ -16,6 +17,7 @@
#include "df/unit.h"
#include "df/burrow.h"
#include "df/map_block.h"
+#include "df/block_burrow.h"
#include "df/job.h"
#include "df/job_list_link.h"
@@ -52,11 +54,28 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector grow_burrows;
DFhackCExport command_result plugin_onupdate(color_ostream &out)
{
- if (!active || !auto_grow)
+ if (!active)
return CR_OK;
detect_burrow_renames(out);
- detect_digging(out);
+
+ if (auto_grow)
+ detect_digging(out);
+
return CR_OK;
}
@@ -213,24 +235,39 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out)
* Config and processing
*/
+static std::map name_lookup;
+
static void parse_names()
{
auto &list = ui->burrows.list;
grow_burrows.clear();
+ name_lookup.clear();
for (size_t i = 0; i < list.size(); i++)
{
auto burrow = list[i];
- if (!burrow->name.empty() && burrow->name[burrow->name.size()-1] == '+')
- grow_burrows.push_back(burrow->id);
+ std::string name = burrow->name;
+
+ if (!name.empty())
+ {
+ name_lookup[name] = burrow->id;
+
+ if (name[name.size()-1] == '+')
+ {
+ grow_burrows.push_back(burrow->id);
+ name.resize(name.size()-1);
+ }
+
+ if (!name.empty())
+ name_lookup[name] = burrow->id;
+ }
}
}
static void reset_tracking()
{
- name_burrow_id = -1;
diggers.clear();
next_job_id_save = 0;
}
@@ -244,6 +281,8 @@ static void init_map(color_ostream &out)
}
parse_names();
+ name_burrow_id = -1;
+
reset_tracking();
active = true;
@@ -286,10 +325,7 @@ static void enable_auto_grow(color_ostream &out, bool enable)
auto_grow = enable;
if (enable)
- {
- parse_names();
reset_tracking();
- }
}
static void handle_burrow_rename(color_ostream &out, df::burrow *burrow)
@@ -371,6 +407,137 @@ static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord
}
}
+static df::burrow *findByName(color_ostream &out, std::string name, bool silent = false)
+{
+ int id = -1;
+ if (name_lookup.count(name))
+ id = name_lookup[name];
+ auto rv = df::burrow::find(id);
+ if (!rv && !silent)
+ out.printerr("Burrow not found: '%s'\n", name.c_str());
+ return rv;
+}
+
+static void copyUnits(df::burrow *target, df::burrow *source, bool enable)
+{
+ if (source == target)
+ {
+ if (!enable)
+ Units::clearBurrowMembers(target);
+
+ return;
+ }
+
+ for (size_t i = 0; i < source->units.size(); i++)
+ {
+ auto unit = df::unit::find(source->units[i]);
+
+ if (unit)
+ Units::setInBurrow(unit, target, enable);
+ }
+}
+
+static void copyTiles(df::burrow *target, df::burrow *source, bool enable)
+{
+ if (source == target)
+ {
+ if (!enable)
+ Maps::clearBurrowTiles(target);
+
+ return;
+ }
+
+ std::vector pvec;
+ Maps::listBurrowBlocks(&pvec, source);
+
+ for (size_t i = 0; i < pvec.size(); i++)
+ {
+ auto block = pvec[i];
+ auto smask = Maps::getBlockBurrowMask(source, block);
+ if (!smask)
+ continue;
+
+ auto tmask = Maps::getBlockBurrowMask(target, block, enable);
+ if (!tmask)
+ continue;
+
+ if (enable)
+ {
+ for (int j = 0; j < 16; j++)
+ tmask->tile_bitmask[j] |= smask->tile_bitmask[j];
+ }
+ else
+ {
+ for (int j = 0; j < 16; j++)
+ tmask->tile_bitmask[j] &= ~smask->tile_bitmask[j];
+
+ if (!tmask->has_assignments())
+ Maps::deleteBlockBurrowMask(target, block, tmask);
+ }
+ }
+}
+
+static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask,
+ df::tile_designation d_value, bool enable)
+{
+ auto &blocks = world->map.map_blocks;
+
+ for (size_t i = 0; i < blocks.size(); i++)
+ {
+ auto block = blocks[i];
+ df::block_burrow *mask = NULL;
+
+ for (int x = 0; x < 16; x++)
+ {
+ for (int y = 0; y < 16; y++)
+ {
+ if ((block->designation[x][y].whole & d_mask.whole) != d_value.whole)
+ continue;
+
+ if (!mask)
+ mask = Maps::getBlockBurrowMask(target, block, enable);
+ if (!mask)
+ goto next_block;
+
+ mask->setassignment(x, y, enable);
+ }
+ }
+
+ if (mask && !enable && !mask->has_assignments())
+ Maps::deleteBlockBurrowMask(target, block, mask);
+
+ next_block:;
+ }
+}
+
+static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable)
+{
+ df::tile_designation mask(0);
+ df::tile_designation value(0);
+
+ if (name == "ABOVE_GROUND")
+ mask.bits.subterranean = true;
+ else if (name == "SUBTERRANEAN")
+ mask.bits.subterranean = value.bits.subterranean = true;
+ else if (name == "LIGHT")
+ mask.bits.light = value.bits.light = true;
+ else if (name == "DARK")
+ mask.bits.light = true;
+ else if (name == "OUTSIDE")
+ mask.bits.outside = value.bits.outside = true;
+ else if (name == "INSIDE")
+ mask.bits.outside = true;
+ else if (name == "HIDDEN")
+ mask.bits.hidden = value.bits.hidden = true;
+ else if (name == "REVEALED")
+ mask.bits.hidden = true;
+ else
+ return false;
+
+ setTilesByDesignation(target, mask, value, enable);
+ return true;
+}
+
static command_result burrow(color_ostream &out, vector ¶meters)
{
CoreSuspender suspend;
@@ -402,6 +569,83 @@ static command_result burrow(color_ostream &out, vector ¶meters)
return CR_WRONG_USAGE;
}
}
+ else if (cmd == "clear-units")
+ {
+ if (parameters.size() < 2)
+ return CR_WRONG_USAGE;
+
+ for (int i = 1; i < parameters.size(); i++)
+ {
+ auto target = findByName(out, parameters[i]);
+ if (!target)
+ return CR_WRONG_USAGE;
+
+ Units::clearBurrowMembers(target);
+ }
+ }
+ else if (cmd == "set-units" || cmd == "add-units" || cmd == "remove-units")
+ {
+ if (parameters.size() < 3)
+ return CR_WRONG_USAGE;
+
+ auto target = findByName(out, parameters[1]);
+ if (!target)
+ return CR_WRONG_USAGE;
+
+ if (cmd == "set-units")
+ Units::clearBurrowMembers(target);
+
+ bool enable = (cmd != "remove-units");
+
+ for (int i = 2; i < parameters.size(); i++)
+ {
+ auto source = findByName(out, parameters[i]);
+ if (!source)
+ return CR_WRONG_USAGE;
+
+ copyUnits(target, source, enable);
+ }
+ }
+ else if (cmd == "clear-tiles")
+ {
+ if (parameters.size() < 2)
+ return CR_WRONG_USAGE;
+
+ for (int i = 1; i < parameters.size(); i++)
+ {
+ auto target = findByName(out, parameters[i]);
+ if (!target)
+ return CR_WRONG_USAGE;
+
+ Maps::clearBurrowTiles(target);
+ }
+ }
+ else if (cmd == "set-tiles" || cmd == "add-tiles" || cmd == "remove-tiles")
+ {
+ if (parameters.size() < 3)
+ return CR_WRONG_USAGE;
+
+ auto target = findByName(out, parameters[1]);
+ if (!target)
+ return CR_WRONG_USAGE;
+
+ if (cmd == "set-tiles")
+ Maps::clearBurrowTiles(target);
+
+ bool enable = (cmd != "remove-tiles");
+
+ for (int i = 2; i < parameters.size(); i++)
+ {
+ if (setTilesByKeyword(target, parameters[i], enable))
+ continue;
+
+ auto source = findByName(out, parameters[i]);
+ if (!source)
+ return CR_WRONG_USAGE;
+
+ copyTiles(target, source, enable);
+ }
+ }
else
{
if (!parameters.empty() && cmd != "?")
From a2a47c5d63efe42b05a90ecedd2b95544ced2234 Mon Sep 17 00:00:00 2001
From: Warmist
Date: Sat, 14 Apr 2012 13:30:48 +0300
Subject: [PATCH 10/20] Fix to init (no need to add " around). Added
experimental (crashy as hell) tools.project
---
plugins/Dfusion/luafiles/init.lua | 15 +++++----
plugins/Dfusion/luafiles/tools/init.lua | 43 +++++++++++++++++++++----
2 files changed, 45 insertions(+), 13 deletions(-)
diff --git a/plugins/Dfusion/luafiles/init.lua b/plugins/Dfusion/luafiles/init.lua
index 358f93d00..e68684bf7 100644
--- a/plugins/Dfusion/luafiles/init.lua
+++ b/plugins/Dfusion/luafiles/init.lua
@@ -86,14 +86,15 @@ loadall(plugins)
dofile_silent("dfusion/initcustom.lua")
local args={...}
-for k,v in pairs(args) do
- local f,err=load(v)
- if f then
- f()
- else
- Console.printerr(err)
- end
+
+
+local f,err=load(table.concat(args,' '))
+if f then
+ f()
+else
+ Console.printerr(err)
end
+
if not INIT then
mainmenu(plugins)
end
diff --git a/plugins/Dfusion/luafiles/tools/init.lua b/plugins/Dfusion/luafiles/tools/init.lua
index e690e9412..b01157c87 100644
--- a/plugins/Dfusion/luafiles/tools/init.lua
+++ b/plugins/Dfusion/luafiles/tools/init.lua
@@ -274,19 +274,50 @@ function tools.changesite(names)
print(string.format("%x->%d",off,n2))
engine.poke(off,ptr_site.type,n2)
end
-function tools.project(unit)
+function tools.project(unit,trg)
if unit==nil then
- unit=getSelectedUnit()
- end
-
- if unit==nil then
- unit=getCreatureAtPos(getxyz())
+ unit=getCreatureAtPointer()
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.
+ local p=df.proj_unitst:new()
+ local startpos={x=unit.pos.x,y=unit.pos.y,z=unit.pos.z}
+ p.origin_pos=startpos
+ p.target_pos=trg
+ p.cur_pos=startpos
+ p.prev_pos=startpos
+ p.unit=unit
+ --- wtf stuff
+ p.unk14=100
+ p.unk16=-1
+ p.unk23=-1
+ p.fall_delay=5
+ p.fall_counter=5
+ p.collided=true
+ -- end wtf
+ local citem=df.global.world.proj_list
+ local maxid=1
+ local newlink=df.proj_list_link:new()
+ newlink.item=p
+ while citem.item~= nil do
+ if citem.item.id>maxid then maxid=citem.item.id end
+ if citem.next ~= nil then
+ citem=citem.next
+ else
+ break
+ end
+ end
+ p.id=maxid+1
+ newlink.prev=citem
+ citem.next=newlink
+
+ local proj_ref=df.general_ref_projectile:new()
+ proj_ref.projectile_id=p.id
+ unit.refs:insert(#unit.refs,proj_ref)
+ unit.flags1.projectile=true
end
function tools.empregnate(unit)
if unit==nil then
From bbf28eb33d7cd1a851c89dfcb102cbfa50e3f2e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Mr=C3=A1zek?=
Date: Sat, 14 Apr 2012 14:15:46 +0200
Subject: [PATCH 11/20] Disable df2minecraft again.
---
plugins/CMakeLists.txt | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 6c2a537d1..f72245b95 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -20,10 +20,11 @@ if(BUILD_DEV_PLUGINS)
add_subdirectory (devel)
endif()
-OPTION(BUILD_DF2MC "Build DF2MC (needs a checkout first)." OFF)
-if(BUILD_DF2MC)
- add_subdirectory (df2mc)
-endif()
+#It's dead :<
+#OPTION(BUILD_DF2MC "Build DF2MC (needs a checkout first)." OFF)
+#if(BUILD_DF2MC)
+# add_subdirectory (df2mc)
+#endif()
OPTION(BUILD_MAPEXPORT "Build map exporter." ON)
if (BUILD_MAPEXPORT)
From cb49c92b99a5aab3f95c811a43fe4dadc1115b99 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sat, 14 Apr 2012 19:44:07 +0400
Subject: [PATCH 12/20] Allow plugins to export functions to lua with safe
reload support.
- To ensure reload safety functions have to be wrapped. Every call
checks the loaded state and locks a mutex in Plugin. If the plugin
is unloaded, calling its functions throws a lua error. Therefore,
plugins may not create closures or export yieldable functions.
- The set of function argument and return types supported by
LuaWrapper is severely limited when compared to being compiled
inside the main library.
Currently supported types: numbers, bool, std::string, df::foo,
df::foo*, std::vector, std::vector.
- To facilitate postponing initialization until after all plugins
have been loaded, the core sends a SC_CORE_INITIALIZED event.
- As an example, the burrows plugin now exports its functions.
---
library/Core.cpp | 20 ++++--
library/LuaTools.cpp | 17 +++++
library/LuaTypes.cpp | 6 ++
library/PluginManager.cpp | 112 ++++++++++++++++++++++++++++++--
library/include/Core.h | 2 +
library/include/DataFuncs.h | 6 +-
library/include/DataIdentity.h | 48 +++++++++-----
library/include/LuaWrapper.h | 11 ++--
library/include/PluginManager.h | 53 ++++++++++++++-
library/lua/dfhack.lua | 4 ++
plugins/CMakeLists.txt | 4 ++
plugins/burrows.cpp | 21 ++++++
plugins/lua/burrows.lua | 33 ++++++++++
13 files changed, 298 insertions(+), 39 deletions(-)
create mode 100644 plugins/lua/burrows.lua
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/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