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

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=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,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) { - std::cerr << "class '" << p->getName() << "': vtable = 0x" - << std::hex << unsigned(vtable) << std::dec << std::endl; + uint32_t pv = unsigned(vtable); + pv -= Core::getInstance().vinfo->getRebaseDelta(); + std::cerr << "" << std::endl; } known[vtable] = p; 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/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..5ff20516e 100644 --- a/library/include/VersionInfo.h +++ b/library/include/VersionInfo.h @@ -51,13 +51,15 @@ namespace DFHack std::vector md5_list; std::vector PE_list; 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; }; @@ -66,12 +68,15 @@ namespace DFHack md5_list = rhs.md5_list; PE_list = rhs.PE_list; 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) { @@ -79,13 +84,11 @@ 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 ++; - } + rebase_delta += rebase; + 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 +128,7 @@ namespace DFHack value = (T) (*i).second; return true; }; + uint32_t getAddress (const std::string& key) const { auto i = Addresses.find(key); @@ -133,6 +137,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/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 d884a734e..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; @@ -454,6 +458,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,50 +472,187 @@ 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; } - -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/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 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 {