From c7f4f8c281217c88c0b1e4fc5b5a91cc9fb96656 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 12 May 2011 20:30:42 +0400 Subject: [PATCH] Support printing refs in dfitemdump, and add methods for containers. --- library/include/dfhack/DFProcess.h | 4 +- library/include/dfhack/modules/Items.h | 11 ++- library/modules/Items.cpp | 52 +++++++++----- tools/examples/dfitemdump.cpp | 98 ++++++++++++++++---------- 4 files changed, 105 insertions(+), 60 deletions(-) diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index 9fddd8f18..f3b165ece 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -226,14 +226,14 @@ namespace DFHack class DFHACK_EXPORT ClassNameCheck { std::string name; - uint32_t vptr; + mutable uint32_t vptr; public: ClassNameCheck() : vptr(0) {} ClassNameCheck(std::string _name) : name(_name), vptr(0) {} ClassNameCheck &operator= (const ClassNameCheck &b) { name = b.name; vptr = b.vptr; return *this; } - bool operator() (Process *p, uint32_t ptr) { + bool operator() (Process *p, uint32_t ptr) const { if (vptr == 0 && p->readClassName(ptr) == name) vptr = ptr; return (vptr && vptr == ptr); diff --git a/library/include/dfhack/modules/Items.h b/library/include/dfhack/modules/Items.h index 966bd1b99..c009f3b9f 100644 --- a/library/include/dfhack/modules/Items.h +++ b/library/include/dfhack/modules/Items.h @@ -129,10 +129,17 @@ public: bool readItem(uint32_t itemptr, dfh_item & item); /// write item base (position and flags only = t_item part of dfh_item) bool writeItem(const dfh_item & item); - /// who owns this item we already read? - int32_t getItemOwnerID(const dfh_item & item); /// dump offsets used by accessors to a string std::string dumpAccessors(const dfh_item & item); + + /// who owns this item we already read? + int32_t getItemOwnerID(const dfh_item & item); + /// which item is it contained in? + int32_t getItemContainerID(const dfh_item & item); + /// which items does it contain? + bool getContainedItems(const dfh_item & item, std::vector &items); + + bool readItemRefs(const dfh_item &item, const ClassNameCheck &classname, std::vector &values); private: class Private; Private* d; diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 0dcb62677..9ab8c9c18 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -426,10 +426,11 @@ class Items::Private std::map descVTable; std::map idLookupTable; uint32_t refVectorOffset; - uint32_t refIDOffset; uint32_t idFieldOffset; uint32_t itemVectorAddress; ClassNameCheck isOwnerRefClass; + ClassNameCheck isContainerRefClass; + ClassNameCheck isContainsRefClass; }; Items::Items(DFContextShared * d_) @@ -437,12 +438,15 @@ Items::Items(DFContextShared * d_) d = new Private; d->d = d_; d->owner = d_->p; - d->refVectorOffset = d->refIDOffset = 0; + d->isOwnerRefClass = ClassNameCheck("general_ref_unit_itemownerst"); + d->isContainerRefClass = ClassNameCheck("general_ref_contained_in_itemst"); + d->isContainsRefClass = ClassNameCheck("general_ref_contains_itemst"); DFHack::OffsetGroup* itemGroup = d_->offset_descriptor->getGroup("Items"); d->itemVectorAddress = itemGroup->getAddress("items_vector"); d->idFieldOffset = itemGroup->getOffset("id"); + d->refVectorOffset = itemGroup->getOffset("item_ref_vector"); } bool Items::Start() @@ -538,27 +542,41 @@ void Items::setItemFlags(uint32_t itemptr, t_itemflags new_flags) */ int32_t Items::getItemOwnerID(const DFHack::dfh_item &item) { - if (!d->refVectorOffset) - { - OffsetGroup * Items = d->owner->getDescriptor()->getGroup("Items"); - d->refVectorOffset = Items->getOffset("item_ref_vector"); - d->refIDOffset = Items->getOffset("owner_ref_id_field"); - } + std::vector vals; + if (readItemRefs(item, d->isOwnerRefClass, vals)) + return vals[0]; + else + return -1; +} - DFHack::DfVector p_refs(d->owner, item.origin + d->refVectorOffset); - uint32_t size = p_refs.size(); +int32_t Items::getItemContainerID(const DFHack::dfh_item &item) +{ + std::vector vals; + if (readItemRefs(item, d->isContainerRefClass, vals)) + return vals[0]; + else + return -1; +} - for (uint32_t i=0;iowner->readDWord(curRef); +bool Items::getContainedItems(const DFHack::dfh_item &item, std::vector &items) +{ + return readItemRefs(item, d->isContainsRefClass, items); +} - if (!d->isOwnerRefClass(d->owner, vtbl)) continue; +bool Items::readItemRefs(const dfh_item &item, const ClassNameCheck &classname, std::vector &values) +{ + DFHack::DfVector p_refs(d->owner, item.origin + d->refVectorOffset); - return d->owner->readDWord(curRef + d->refIDOffset); + values.clear(); + + for (uint32_t i=0; iowner->readDWord(p_refs[i]); + if (classname(d->owner, vtbl)) + values.push_back(int32_t(d->owner->readDWord(p_refs[i] + 4))); } - return -1; + return !values.empty(); } std::string Items::getItemClass(const dfh_item & item) diff --git a/tools/examples/dfitemdump.cpp b/tools/examples/dfitemdump.cpp index 5ebc7eb49..acad786c5 100644 --- a/tools/examples/dfitemdump.cpp +++ b/tools/examples/dfitemdump.cpp @@ -14,8 +14,28 @@ using namespace std; #include #include -int main () +int main (int argc, char *argv[]) { + bool print_refs = false; + bool print_hex = false; + bool print_acc = false; + + for(int i = 1; i < argc; i++) + { + char *arg = argv[i]; + if (arg[0] != '-') + continue; + + for (; *arg; arg++) { + switch (arg[0]) { + case 'r': print_refs = true; break; + case 'x': print_hex = true; break; + case 'a': print_acc = true; break; + } + } + } + + DFHack::Process * p; unsigned int i,j; DFHack::ContextManager DFMgr("Memory.xml"); @@ -45,54 +65,54 @@ int main () p = DF->getProcess(); int32_t x,y,z; Gui->getCursorCoords(x,y,z); + + std::vector p_items; + Items->readItemVector(p_items); + uint32_t size = p_items.size(); + // FIXME: tools should never be exposed to DFHack internals! DFHack::OffsetGroup* itemGroup = mem->getGroup("Items"); - DFHack::DfVector p_items (p, itemGroup->getAddress("items_vector")); - uint32_t size = p_items.size(); + uint32_t ref_vector = itemGroup->getOffset("item_ref_vector"); for(int i = 0; i < size; i++) { DFHack::dfh_item itm; memset(&itm, 0, sizeof(DFHack::dfh_item)); Items->readItem(p_items[i],itm); - if(x != -30000) - { - if(itm.base.x == x - && itm.base.y == y - && itm.base.z == z - && itm.base.flags.on_ground - && !itm.base.flags.in_chest - && !itm.base.flags.in_inventory - && !itm.base.flags.in_building - ) - { - printf( - "%5d: %08x %6d %08x (%d,%d,%d) #%08x [%d] %s - %s. Stack: %d\n", - i, itm.origin, itm.id, itm.base.flags.whole, - itm.base.x, itm.base.y, itm.base.z, - itm.base.vtable, - itm.wear_level, - Items->getItemClass(itm.matdesc.itemType).c_str(), - Items->getItemDescription(itm, Materials).c_str(), - itm.quantity - ); - hexdump(DF,p_items[i],0x300); - cout << Items->dumpAccessors(itm) << endl; + + if (x != -30000 + && !(itm.base.x == x && itm.base.y == y && itm.base.z == z + && itm.base.flags.on_ground + && !itm.base.flags.in_chest + && !itm.base.flags.in_inventory + && !itm.base.flags.in_building)) + continue; + + printf( + "%5d: %08x %6d %08x (%d,%d,%d) #%08x [%d] *%d %s - %s\n", + i, itm.origin, itm.id, itm.base.flags.whole, + itm.base.x, itm.base.y, itm.base.z, + itm.base.vtable, + itm.wear_level, + itm.quantity, + Items->getItemClass(itm.matdesc.itemType).c_str(), + Items->getItemDescription(itm, Materials).c_str() + ); + + if (print_hex) + hexdump(DF,p_items[i],0x300); + + if (print_acc) + cout << Items->dumpAccessors(itm) << endl; + + if (print_refs) { + DFHack::DfVector p_refs(p, itm.origin + ref_vector); + for (int j = 0; j < p_refs.size(); j++) { + uint32_t vptr = p->readDWord(p_refs[j]); + uint32_t val = p->readDWord(p_refs[j]+4); + printf("\t-> %d \t%s\n", int(val), p->readClassName(vptr).c_str()); } } - else - { - printf( - "%5d: %08x %6d %08x (%d,%d,%d) #%08x [%d] %s - %s. Stack: %d\n", - i, itm.origin, itm.id, itm.base.flags.whole, - itm.base.x, itm.base.y, itm.base.z, - itm.base.vtable, - itm.wear_level, - Items->getItemClass(itm.matdesc.itemType).c_str(), - Items->getItemDescription(itm, Materials).c_str(), - itm.quantity - ); - } } /* printf("type\tvtable\tname\tquality\tdecorate\n");