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.

Items module

    +
  • 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.

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.

  • @@ -930,7 +936,7 @@ a lua list containing them.

    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)

      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 #include "DataDefs.h" +#include "PluginManager.h" #include #include @@ -156,7 +157,7 @@ namespace DFHack { namespace LuaWrapper { * Verify that the object is a DF ref with UPVAL_METATABLE. * If everything ok, extract the address. */ - uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode); + DFHACK_EXPORT uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode); bool is_type_compatible(lua_State *state, type_identity *type1, int meta1, type_identity *type2, int meta2, bool exact_equal); @@ -221,16 +222,14 @@ namespace DFHack { namespace LuaWrapper { */ void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum); - struct FunctionReg { - const char *name; - function_identity_base *identity; - }; - /** * Wrap functions and add them to the table on the top of the stack. */ + using DFHack::FunctionReg; void SetFunctionWrappers(lua_State *state, const FunctionReg *reg); + int method_wrapper_core(lua_State *state, function_identity_base *id); + void IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct); void AttachDFGlobals(lua_State *state); diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index 8f02099be..554860dee 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -33,6 +33,8 @@ distribution. #include "RemoteClient.h" +typedef struct lua_State lua_State; + struct DFLibrary; namespace tthread { @@ -49,6 +51,7 @@ namespace DFHack class PluginManager; class virtual_identity; class RPCService; + class function_identity_base; enum state_change_event { @@ -56,7 +59,17 @@ namespace DFHack SC_WORLD_UNLOADED, SC_MAP_LOADED, SC_MAP_UNLOADED, - SC_VIEWSCREEN_CHANGED + SC_VIEWSCREEN_CHANGED, + SC_CORE_INITIALIZED, + SC_BEGIN_UNLOAD + }; + struct DFHACK_EXPORT CommandReg { + const char *name; + int (*command)(lua_State*); + }; + struct DFHACK_EXPORT FunctionReg { + const char *name; + function_identity_base *identity; }; struct DFHACK_EXPORT PluginCommand { @@ -102,6 +115,7 @@ namespace DFHack { struct RefLock; struct RefAutolock; + struct RefAutoinc; enum plugin_state { PS_UNLOADED, @@ -138,6 +152,9 @@ namespace DFHack { return name; } + + void open_lua(lua_State *state, int table); + private: RefLock * access; std::vector commands; @@ -147,6 +164,26 @@ namespace DFHack DFLibrary * plugin_lib; PluginManager * parent; plugin_state state; + + struct LuaCommand { + Plugin *owner; + std::string name; + int (*command)(lua_State *state); + }; + std::map lua_commands; + static int lua_cmd_wrapper(lua_State *state); + + struct LuaFunction { + Plugin *owner; + std::string name; + function_identity_base *identity; + }; + std::map lua_functions; + static int lua_fun_wrapper(lua_State *state); + + void index_lua(DFLibrary *lib); + void reset_lua(); + command_result (*plugin_init)(color_ostream &, std::vector &); command_result (*plugin_status)(color_ostream &, std::string &); command_result (*plugin_shutdown)(color_ostream &); @@ -199,5 +236,15 @@ namespace DFHack }; /// You have to have this in every plugin you write - just once. Ideally on top of the main file. -#define DFHACK_PLUGIN(plugin_name) DFhackDataExport const char * version = DFHACK_VERSION;\ -DFhackDataExport const char * name = plugin_name; +#define DFHACK_PLUGIN(plugin_name) \ + DFhackDataExport const char * version = DFHACK_VERSION;\ + DFhackDataExport const char * name = plugin_name; + +#define DFHACK_PLUGIN_LUA_COMMANDS \ + DFhackCExport const DFHack::CommandReg plugin_lua_commands[] = +#define DFHACK_PLUGIN_LUA_FUNCTIONS \ + DFhackCExport const DFHack::FunctionReg plugin_lua_functions[] = + +#define DFHACK_LUA_COMMAND(name) { #name, name } +#define DFHACK_LUA_FUNCTION(name) { #name, df::wrap_function(name) } +#define DFHACK_LUA_END { NULL, NULL } diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 626f60bec..7230a12aa 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -55,6 +55,10 @@ function mkmodule(module,env) error("Not a table in package.loaded["..module.."]") end end + local plugname = string.match(module,'^plugins%.(%w+)$') + if plugname then + dfhack.open_plugin(pkg,plugname) + end setmetatable(pkg, { __index = (env or _G) }) return pkg end diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index d30d25697..9d236fbe6 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -35,6 +35,10 @@ if (BUILD_DWARFEXPORT) add_subdirectory (dwarfexport) endif() +install(DIRECTORY lua/ + DESTINATION ${DFHACK_LUA_DESTINATION}/plugins + FILES_MATCHING PATTERN "*.lua") + # Protobuf FILE(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto) diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp index c973405ee..74cb57c45 100644 --- a/plugins/burrows.cpp +++ b/plugins/burrows.cpp @@ -2,6 +2,9 @@ #include "Console.h" #include "Export.h" #include "PluginManager.h" +#include "Error.h" + +#include "DataFuncs.h" #include "modules/Gui.h" #include "modules/Job.h" @@ -420,6 +423,9 @@ static df::burrow *findByName(color_ostream &out, std::string name, bool silent static void copyUnits(df::burrow *target, df::burrow *source, bool enable) { + CHECK_NULL_POINTER(target); + CHECK_NULL_POINTER(source); + if (source == target) { if (!enable) @@ -439,6 +445,9 @@ static void copyUnits(df::burrow *target, df::burrow *source, bool enable) static void copyTiles(df::burrow *target, df::burrow *source, bool enable) { + CHECK_NULL_POINTER(target); + CHECK_NULL_POINTER(source); + if (source == target) { if (!enable) @@ -480,6 +489,8 @@ static void copyTiles(df::burrow *target, df::burrow *source, bool enable) static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask, df::tile_designation d_value, bool enable) { + CHECK_NULL_POINTER(target); + auto &blocks = world->map.map_blocks; for (size_t i = 0; i < blocks.size(); i++) @@ -512,6 +523,8 @@ static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mas static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) { + CHECK_NULL_POINTER(target); + df::tile_designation mask(0); df::tile_designation value(0); @@ -538,6 +551,14 @@ static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) return true; } +DFHACK_PLUGIN_LUA_FUNCTIONS { + DFHACK_LUA_FUNCTION(findByName), + DFHACK_LUA_FUNCTION(copyUnits), + DFHACK_LUA_FUNCTION(copyTiles), + DFHACK_LUA_FUNCTION(setTilesByKeyword), + DFHACK_LUA_END +}; + static command_result burrow(color_ostream &out, vector ¶meters) { CoreSuspender suspend; diff --git a/plugins/lua/burrows.lua b/plugins/lua/burrows.lua new file mode 100644 index 000000000..b1d51f6a6 --- /dev/null +++ b/plugins/lua/burrows.lua @@ -0,0 +1,33 @@ +local _ENV = mkmodule('plugins.burrows') + +--[[ + + Native functions: + + * findByName(name) -> burrow + * copyUnits(dest,src,enable) + * copyTiles(dest,src,enable) + * setTilesByKeyword(dest,kwd,enable) -> success + + 'enable' selects between add and remove modes + +--]] + +clearUnits = dfhack.units.clearBurrowMembers + +function isBurrowUnit(burrow,unit) + return dfhack.units.isInBurrow(unit,burrow) +end +function setBurrowUnit(burrow,unit,enable) + return dfhack.units.setInBurrow(unit,burrow,enable) +end + +clearTiles = dfhack.maps.clearBurrowTiles +listBlocks = dfhack.maps.listBurrowBlocks + +isBurrowTile = dfhack.maps.isBurrowTile +setBurrowTile = dfhack.maps.setBurrowTile +isBlockBurrowTile = dfhack.maps.isBlockBurrowTile +setBlockBurrowTile = dfhack.maps.setBlockBurrowTile + +return _ENV \ No newline at end of file From 451f07ecb45ac7ddd84d4e586ea6681ff9153c41 Mon Sep 17 00:00:00 2001 From: Warmist Date: Sun, 15 Apr 2012 00:03:12 +0300 Subject: [PATCH 13/20] breakfast build bat... --- build/generate-MSVC-all-breakfast.bat | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 build/generate-MSVC-all-breakfast.bat diff --git a/build/generate-MSVC-all-breakfast.bat b/build/generate-MSVC-all-breakfast.bat new file mode 100644 index 000000000..08c5b03ff --- /dev/null +++ b/build/generate-MSVC-all-breakfast.bat @@ -0,0 +1,8 @@ +@echo off +IF EXIST DF_PATH.txt SET /P _DF_PATH= Date: Sat, 14 Apr 2012 23:36:45 +0200 Subject: [PATCH 14/20] Make release string tweakable. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cbbe6a1f..8c9ace59b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ set(DF_VERSION_MINOR "34") set(DF_VERSION_PATCH "07") set(DF_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}") -set(DFHACK_RELEASE "1") +SET(DFHACK_RELEASE "1" CACHE STRING "Current release revision.") set(DFHACK_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}-r${DFHACK_RELEASE}") add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}") From c6c6c517667563a07a7dc29761656f73c2da9656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 14 Apr 2012 23:38:29 +0200 Subject: [PATCH 15/20] The 'r' in release string is now also tweakable. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c9ace59b..107626b13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,9 +58,9 @@ set(DF_VERSION_MINOR "34") set(DF_VERSION_PATCH "07") set(DF_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}") -SET(DFHACK_RELEASE "1" CACHE STRING "Current release revision.") +SET(DFHACK_RELEASE "r1" CACHE STRING "Current release revision.") -set(DFHACK_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}-r${DFHACK_RELEASE}") +set(DFHACK_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}-${DFHACK_RELEASE}") add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}") ## where to install things (after the build is done, classic 'make install' or package structure) From fa063e293610bae49be81f62b869ec3f5cfdf547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 15 Apr 2012 00:35:59 +0200 Subject: [PATCH 16/20] Track structures, fix trivial problem in zone plugin --- library/xml | 2 +- plugins/zone.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 27fec9797..a54516705 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 27fec9797d7d1215bd3f5530b44a55a9d394fe75 +Subproject commit a545167050fee9eedd5e319b518d961f933154a3 diff --git a/plugins/zone.cpp b/plugins/zone.cpp index 2f2b64588..9f71b85d8 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -890,6 +890,8 @@ df::general_ref_building_civzone_assignedst * createCivzoneRef() return newref; } +bool isInBuiltCage(df::unit* unit); + // check if assigned to pen, pit, (built) cage or chain // note: BUILDING_CAGED is not set for animals (maybe it's used for dwarves who get caged as sentence) // animals in cages (no matter if built or on stockpile) get the ref CONTAINED_IN_ITEM instead From e686b1c8e280051e20ba187bc4ea66ebedc21f97 Mon Sep 17 00:00:00 2001 From: Warmist Date: Sun, 15 Apr 2012 01:20:59 +0300 Subject: [PATCH 17/20] Orbital nuking of C4819 (code-page warning) --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cbbe6a1f..e39784adc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,9 @@ endif(CMAKE_CONFIGURATION_TYPES) cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(dfhack) +# disable C4819 code-page warning +add_definitions( "/wd4819" ) + # set up folder structures for IDE solutions # MSVC Express won't load solutions that use this. It also doesn't include MFC supported # Check for MFC! From f235d8f371082e4bc9bb17651eb7d3cc6fb5e54e Mon Sep 17 00:00:00 2001 From: Warmist Date: Sun, 15 Apr 2012 01:27:02 +0300 Subject: [PATCH 18/20] Orbital nuking was bit excessive... --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e39784adc..01b7c5804 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,10 @@ endif(CMAKE_CONFIGURATION_TYPES) cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(dfhack) +if(MSVC) # disable C4819 code-page warning add_definitions( "/wd4819" ) +endif() # set up folder structures for IDE solutions # MSVC Express won't load solutions that use this. It also doesn't include MFC supported From fc38371b29ff20b959a401222a74e6a31f1b95c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 15 Apr 2012 01:15:15 +0200 Subject: [PATCH 19/20] Clean up some chaos in old code. --- library/PlugLoad-linux.cpp | 2 +- library/PlugLoad-windows.cpp | 2 +- library/include/Core.h | 6 ------ library/include/PluginManager.h | 11 ++++++++++- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/library/PlugLoad-linux.cpp b/library/PlugLoad-linux.cpp index aaf7b2c33..69945c6f4 100644 --- a/library/PlugLoad-linux.cpp +++ b/library/PlugLoad-linux.cpp @@ -14,7 +14,7 @@ #include #include "DFHack.h" -#include "Core.h" +#include "PluginManager.h" #include "Hooks.h" #include diff --git a/library/PlugLoad-windows.cpp b/library/PlugLoad-windows.cpp index eadc9343d..f9a75df97 100644 --- a/library/PlugLoad-windows.cpp +++ b/library/PlugLoad-windows.cpp @@ -28,7 +28,7 @@ distribution. #include #include #include -#include "Core.h" +#include "PluginManager.h" #include "Hooks.h" #include diff --git a/library/include/Core.h b/library/include/Core.h index 8c2a284df..f8ac8e783 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -65,12 +65,6 @@ namespace DFHack { class df_window; } - // anon type, pretty much - struct DFLibrary; - - DFLibrary * OpenPlugin (const char * filename); - void * LookupPlugin (DFLibrary * plugin ,const char * function); - void ClosePlugin (DFLibrary * plugin); // Core is a singleton. Why? Because it is closely tied to SDL calls. It tracks the global state of DF. // There should never be more than one instance diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index 554860dee..080e66e66 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -35,7 +35,6 @@ distribution. typedef struct lua_State lua_State; -struct DFLibrary; namespace tthread { class mutex; @@ -53,6 +52,16 @@ namespace DFHack class RPCService; class function_identity_base; + // anon type, pretty much + struct DFLibrary; + + // Open a plugin library + DFLibrary * OpenPlugin (const char * filename); + // find a symbol inside plugin + void * LookupPlugin (DFLibrary * plugin ,const char * function); + // Close a plugin library + void ClosePlugin (DFLibrary * plugin); + enum state_change_event { SC_WORLD_LOADED, From c69af6ab9eff10fc59f68d462656caa2dacd266c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 15 Apr 2012 01:58:02 +0200 Subject: [PATCH 20/20] Fix missing lua linkage in burrows plugin. --- plugins/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 5fe21f66e..b520c5f19 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -102,7 +102,8 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(feature feature.cpp) DFHACK_PLUGIN(lair lair.cpp) DFHACK_PLUGIN(zone zone.cpp) - DFHACK_PLUGIN(burrows burrows.cpp) + # this one exports functions to lua + DFHACK_PLUGIN(burrows burrows.cpp LINK_LIBRARIES lua) # not yet. busy with other crud again... #DFHACK_PLUGIN(versionosd versionosd.cpp) endif()