From cfc1dad4b616657fe207eb8cb26f6b3e25c5d06d Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 10 Apr 2011 16:55:22 +0400 Subject: [PATCH 1/7] Fix the item flag bitfield & set the item vector ptr. --- Memory.xml | 3 ++ library/include/dfhack/DFTypes.h | 72 ++++++++++++++++---------------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/Memory.xml b/Memory.xml index d40c4a737..f53bcd96e 100644 --- a/Memory.xml +++ b/Memory.xml @@ -2948,6 +2948,9 @@
+ +
+ diff --git a/library/include/dfhack/DFTypes.h b/library/include/dfhack/DFTypes.h index d5a72e6e7..c1d7c646e 100644 --- a/library/include/dfhack/DFTypes.h +++ b/library/include/dfhack/DFTypes.h @@ -120,46 +120,46 @@ struct t_item_df40d //They all seem to be valid on 40d as well struct naked_itemflags { - unsigned int on_ground : 1; // Item on ground - unsigned int in_job : 1; // item currently being used in a job - unsigned int in_inventory : 1; // Item in a creatures inventory - unsigned int u_ngrd1 : 1; // only occurs when not on ground, unknown function + unsigned int on_ground : 1; // 0000 0001 Item on ground + unsigned int in_job : 1; // 0000 0002 Item currently being used in a job + unsigned int u_ngrd1 : 1; // 0000 0004 unknown, unseen + unsigned int in_inventory : 1; // 0000 0008 Item in a creature or workshop inventory + + unsigned int u_ngrd2 : 1; // 0000 0010 unknown, lost (artifact)?, unseen + unsigned int in_building : 1; // 0000 0020 Part of a building (including mechanisms, bodies in coffins) + unsigned int u_ngrd3 : 1; // 0000 0040 unknown, unseen + unsigned int dead_body : 1; // 0000 0080 Dwarf's dead body or body part + + unsigned int rotten : 1; // 0000 0100 Rotten food + unsigned int spider_web : 1; // 0000 0200 Spider web + unsigned int construction : 1; // 0000 0400 Material used in construction + unsigned int u_ngrd5 : 1; // 0000 0800 unknown, unseen + + unsigned int unk3 : 1; // 0000 1000 unknown, unseen + unsigned int u_ngrd6 : 1; // 0000 2000 unknown, unseen + unsigned int foreign : 1; // 0000 4000 Item is imported + unsigned int u_ngrd7 : 1; // 0000 8000 unknown, unseen + + unsigned int owned : 1; // 0001 0000 Item is owned by a dwarf + unsigned int unk4 : 1; // 0002 0000 unknown, unseen + unsigned int artifact1 : 1; // 0004 0000 Artifact ? + unsigned int forbid : 1; // 0008 0000 Forbidden item - unsigned int in_workshop : 1; // Item is in a workshops inventory - unsigned int u_ngrd2 : 1; // only occurs when not on ground, unknown function - unsigned int u_ngrd3 : 1; // only occurs when not on ground, unknown function - unsigned int rotten : 1; // Item is rotten - - unsigned int unk1 : 1; // unknown function - unsigned int u_ngrd4 : 1; // only occurs when not on ground, unknown function - unsigned int unk2 : 1; // unknown function - unsigned int u_ngrd5 : 1; // only occurs when not on ground, unknown function - - unsigned int unk3 : 1; // unknown function - unsigned int u_ngrd6 : 1; // only occurs when not on ground, unknown function - unsigned int narrow : 1; // Item is narrow - unsigned int u_ngrd7 : 1; // only occurs when not on ground, unknown function - - unsigned int worn : 1; // item shows wear - unsigned int unk4 : 1; // unknown function - unsigned int u_ngrd8 : 1; // only occurs when not on ground, unknown function - unsigned int forbid : 1; // designate forbid item - - unsigned int unk5 : 1; // unknown function - unsigned int dump : 1; // designate dump item - unsigned int on_fire: 1; //indicates if item is on fire, Will Set Item On Fire if Set! - unsigned int melt : 1; // designate melt item, if item cannot be melted, does nothing it seems + unsigned int unk5 : 1; // 0010 0000 unknown, unseen + unsigned int dump : 1; // 0020 0000 Designated for dumping + unsigned int on_fire: 1; // 0040 0000 Indicates if item is on fire, Will Set Item On Fire if Set! + unsigned int melt : 1; // 0080 0000 Designated for melting, if applicable // 0100 0000 - 8000 0000 - unsigned int hidden : 1; // designate hide item - unsigned int u_ngrd9 : 1; // only occurs when not on ground, unknown function - unsigned int unk6 : 1; // unknown function - unsigned int unk7 : 1; // unknown function + unsigned int hidden : 1; // 0100 0000 Hidden item + unsigned int in_chest : 1; // 0200 0000 Stored in chest/part of well? + unsigned int unk6 : 1; // 0400 0000 unknown, unseen + unsigned int artifact2 : 1; // 0800 0000 Artifact ? - unsigned int unk8 : 1; // unknown function - unsigned int unk9 : 1; // unknown function - unsigned int unk10 : 1; // unknown function - unsigned int unk11 : 1; // unknown function + unsigned int unk8 : 1; // 1000 0000 unknown, unseen + unsigned int unk9 : 1; // 2000 0000 unknown, set when viewing details + unsigned int unk10 : 1; // 4000 0000 unknown, unseen + unsigned int unk11 : 1; // 8000 0000 unknown, unseen }; union t_itemflags From e3897b0f935ecdbed5e1394b1d5bb0d4f6231825 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 10 Apr 2011 21:51:21 +0400 Subject: [PATCH 2/7] Improve the accessor instruction parser. Instead of hard-coding complete machine code patterns, try to really parse a certain subset of MOV instructions. --- library/modules/Items.cpp | 184 ++++++++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 65 deletions(-) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index e398f8e16..dfc47962a 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -54,8 +54,8 @@ class DFHACK_EXPORT Accessor private: accessor_type type; int32_t constant; - uint32_t offset1; - uint32_t offset2; + int32_t offset1; + int32_t offset2; Process * p; uint32_t dataWidth; public: @@ -95,89 +95,143 @@ public: std::vector improvement; }; +inline bool do_match(uint32_t &ptr, uint64_t val, int size, uint64_t mask, uint64_t check) +{ + if ((val & mask) == check) { + ptr += size; + return true; + } + return false; +} + +static bool match_MEM_ACCESS(uint32_t &ptr, uint64_t v, int isize, int in_reg, int &out_reg, int &offset) +{ + // ESP & EBP are hairy + if (in_reg == 4 || in_reg == 5) + return false; + + if ((v & 7) != in_reg) + return false; + + out_reg = (v>>3) & 7; + + switch ((v>>6)&3) { + case 0: // MOV REG2, [REG] + offset = 0; + ptr += isize+1; + return true; + case 1: // MOV REG2, [REG+offset8] + offset = (signed char)(v >> 8); + ptr += isize+2; + return true; + case 2: // MOV REG2, [REG+offset32] + offset = (signed int)(v >> 8); + ptr += isize+5; + return true; + default: + return false; + } +} + +static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, int &offset, bool &size16) +{ + int prefix = 0; + size16 = false; + if ((v & 0xFF) == 0x8B) { // MOV + v >>= 8; + prefix = 1; + } + else if ((v & 0xFFFF) == 0x8B66) { // MOV 16-bit + v >>= 16; + prefix = 2; + size16 = true; + } + else if ((v & 0xFFFF) == 0xBF0F) { // MOVSX + v >>= 16; + prefix = 2; + size16 = true; + } + else if ((v & 0xFFFF) == 0xB70F) { // MOVZ + v >>= 16; + prefix = 2; + size16 = true; + } + else + return false; + + return match_MEM_ACCESS(ptr, v, prefix, in_reg, out_reg, offset); +} // FIXME: this is crazy Accessor::Accessor(uint32_t function, Process *p) { this->p = p; - this->constant = 0; - this->offset1 = 0; - this->offset2 = 0; this->type = ACCESSOR_CONSTANT; - this->dataWidth = 2; - uint64_t funcText = p->readQuad(function); - if( funcText == 0xCCCCCCCCCCC3C033LL ) + uint32_t ptr = function; + uint64_t v = p->readQuad(ptr); + int data_reg = -1; + + if (do_match(ptr, v, 2, 0xFFFF, 0xC033) || + do_match(ptr, v, 2, 0xFFFF, 0xC031)) // XOR EAX, EAX { - return; + data_reg = 0; + this->constant = 0; } - if( funcText == 0xCCCCCCCCC3FFC883LL ) + else if (do_match(ptr, v, 3, 0xFFFFFF, 0xFFC883)) // OR EAX, -1 { - /* or eax,-1; ret; */ + data_reg = 0; this->constant = -1; - return; } - if( (funcText&0xFFFFFFFFFF0000FFLL) == 0xCCCCC300000000B8LL ) + else if (do_match(ptr, v, 5, 0xFF, 0xB8)) // MOV EAX,imm { - /* mov eax, xx; ret; */ - this->constant = (funcText>>8) & 0xffff; - return; + data_reg = 0; + this->constant = (v>>8) & 0xFFFFFFFF; } - if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC300000000818B66LL ) - { - /* mov ax, [ecx+xx]; ret; */ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>24) & 0xffff; - return; - } - if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL ) - { - /* mov ax, [ecx+xx]; ret; (shorter instruction)*/ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>24) & 0xff; - return; - } - if( (funcText&0x00000000FF00FFFFLL) == 0x00000000C300418BLL ) - { - /* mov eax, [ecx+xx]; ret; */ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>16) & 0xff; - this->dataWidth = 4; - return; - } - if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL ) + else { - uint64_t funcText2 = p->readQuad(function+8); - if( (funcText2&0xFFFFFFFFFFFF00FFLL) == 0xCCCCCCCCCCC30040LL ) + bool size16; + int ptr_reg = 1, tmp; // ECX + + // MOV REG,[ESP+4] + if (do_match(ptr, v, 4, 0xFFFFC7FFU, 0x0424448B)) { - this->type = ACCESSOR_DOUBLE_INDIRECT; - this->offset1 = (funcText>>16) & 0xffff; - this->offset2 = (funcText2>>8) & 0xff; - return; + ptr_reg = (v>>11)&7; + v = p->readQuad(ptr); + } + + this->dataWidth = 4; + + if (match_MOV_MEM(ptr, v, ptr_reg, tmp, this->offset1, size16)) { + data_reg = tmp; + this->type = ACCESSOR_INDIRECT; + + if (size16) + this->dataWidth = 2; + else + { + v = p->readQuad(ptr); + + if (match_MOV_MEM(ptr, v, data_reg, tmp, this->offset2, size16)) { + data_reg = tmp; + this->type = ACCESSOR_DOUBLE_INDIRECT; + + if (size16) + this->dataWidth = 2; + } + } } } - if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL ) - { - /* movsx eax, word ptr [ecx+xx]; ret */ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>24) & 0xffff; - return; - } - if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL ) - { - /* movsx eax, word ptr [ecx+xx]; ret (shorter opcode)*/ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>24) & 0xff; + + v = p->readQuad(ptr); + + if (data_reg == 0 && do_match(ptr, v, 1, 0xFF, 0xC3)) // RET return; - } - if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL ) + else { - /* mov eax, [ecx+xx]; ret; */ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>16) & 0xffff; - this->dataWidth = 4; - return; + this->type = ACCESSOR_CONSTANT; + this->constant = 0; + printf("bad accessor @0x%x\n", function); } - printf("bad accessor @0x%x\n", function); } bool Accessor::isConstant() From f6ae41fe49266ed0de42002a01c593e2360b87e1 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 10 Apr 2011 22:42:25 +0400 Subject: [PATCH 3/7] Provide access to item header, including flags, and wear information. Add preliminary offsets for the item data to Memory.xml --- Memory.xml | 8 +++++++- library/include/dfhack/modules/Items.h | 13 +++++++++++++ library/modules/Items.cpp | 12 ++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Memory.xml b/Memory.xml index f53bcd96e..654363ca6 100644 --- a/Memory.xml +++ b/Memory.xml @@ -995,7 +995,7 @@ - (in the vtable) +
@@ -2950,6 +2950,12 @@
+ + + + + + diff --git a/library/include/dfhack/modules/Items.h b/library/include/dfhack/modules/Items.h index 8940b6c95..871b7b01d 100644 --- a/library/include/dfhack/modules/Items.h +++ b/library/include/dfhack/modules/Items.h @@ -6,17 +6,29 @@ */ #include "dfhack/DFExport.h" #include "dfhack/DFModule.h" +#include "dfhack/DFTypes.h" + namespace DFHack { class Context; class DFContextShared; +struct t_item_header +{ + int16_t x; + int16_t y; + int16_t z; + t_itemflags flags; +}; + struct t_item { + t_item_header header; t_material matdesc; int32_t quantity; int32_t quality; + int16_t wear_level; }; struct t_improvement @@ -35,6 +47,7 @@ public: std::string getItemDescription(uint32_t itemptr, Materials * Materials); std::string getItemClass(int32_t index); bool getItemData(uint32_t itemptr, t_item & item); + void setItemFlags(uint32_t itemptr, t_itemflags new_flags); private: class Private; Private* d; diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index dfc47962a..c1c554c73 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -84,6 +84,7 @@ private: Accessor * ASubIndex; Accessor * AIndex; Accessor * AQuality; + Accessor * AWear; Process * p; bool hasDecoration; public: @@ -284,6 +285,7 @@ ItemDesc::ItemDesc(uint32_t VTable, Process *p) uint32_t funcOffsetC = Items->getOffset("item_subindex_accessor"); uint32_t funcOffsetD = Items->getOffset("item_index_accessor"); uint32_t funcOffsetQuality = Items->getOffset("item_quality_accessor"); + uint32_t funcOffsetWear = Items->getOffset("item_wear_accessor"); this->vtable = VTable; this->p = p; this->className = p->readClassName(VTable).substr(5); @@ -293,6 +295,7 @@ ItemDesc::ItemDesc(uint32_t VTable, Process *p) this->ASubIndex = new Accessor( p->readDWord( VTable + funcOffsetC ), p); this->AIndex = new Accessor( p->readDWord( VTable + funcOffsetD ), p); this->AQuality = new Accessor( p->readDWord( VTable + funcOffsetQuality ), p); + this->AWear = new Accessor( p->readDWord( VTable + funcOffsetWear ), p); this->hasDecoration = false; if(this->AMainType->isConstant()) this->mainType = this->AMainType->getValue(0); @@ -305,12 +308,16 @@ ItemDesc::ItemDesc(uint32_t VTable, Process *p) bool ItemDesc::getItem(uint32_t itemptr, DFHack::t_item &item) { + this->p->read(itemptr+4, sizeof(t_item_header), (uint8_t*)&item.header); item.matdesc.itemType = this->AMainType->getValue(itemptr); item.matdesc.subType = this->ASubType->getValue(itemptr); item.matdesc.subIndex = this->ASubIndex->getValue(itemptr); item.matdesc.index = this->AIndex->getValue(itemptr); item.quality = this->AQuality->getValue(itemptr); item.quantity = 1; /* TODO */ + // Note: this accessor returns a 32-bit value with the higher + // half sometimes containing garbage, so the cast is essential: + item.wear_level = (int16_t)this->AWear->getValue(itemptr); return true; } @@ -375,6 +382,11 @@ bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item) return desc->getItem(itemptr, item); } +void Items::setItemFlags(uint32_t itemptr, t_itemflags new_flags) +{ + d->owner->writeDWord(itemptr + 0x0C, new_flags.whole); +} + std::string Items::getItemClass(int32_t index) { std::map::iterator it; From fbf76440b5ada754315035ef9a2b1998f941ed62 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 10 Apr 2011 22:44:01 +0400 Subject: [PATCH 4/7] Try to handle signed and unsigned 16-bit accessors. Not sure whether it makes much sense, seeing as some accessors (e.g. wear) actually return 32-bit values, assuming that the caller would correctly sign-extend the lower half and discard the upper. --- library/modules/Items.cpp | 62 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index c1c554c73..742c91fa5 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -51,13 +51,19 @@ enum accessor_type {ACCESSOR_CONSTANT, ACCESSOR_INDIRECT, ACCESSOR_DOUBLE_INDIRE /* this is used to store data about the way accessors work */ class DFHACK_EXPORT Accessor { +public: + enum DataWidth { + Data32 = 0, + DataSigned16, + DataUnsigned16 + }; private: accessor_type type; int32_t constant; int32_t offset1; int32_t offset2; Process * p; - uint32_t dataWidth; + DataWidth dataWidth; public: Accessor(uint32_t function, Process * p); Accessor(accessor_type type, int32_t constant, uint32_t offset1, uint32_t offset2, uint32_t dataWidth, Process * p); @@ -134,10 +140,10 @@ static bool match_MEM_ACCESS(uint32_t &ptr, uint64_t v, int isize, int in_reg, i } } -static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, int &offset, bool &size16) +static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, int &offset, Accessor::DataWidth &size) { int prefix = 0; - size16 = false; + size = Accessor::Data32; if ((v & 0xFF) == 0x8B) { // MOV v >>= 8; prefix = 1; @@ -145,17 +151,17 @@ static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, i else if ((v & 0xFFFF) == 0x8B66) { // MOV 16-bit v >>= 16; prefix = 2; - size16 = true; + size = Accessor::DataUnsigned16; } else if ((v & 0xFFFF) == 0xBF0F) { // MOVSX v >>= 16; prefix = 2; - size16 = true; + size = Accessor::DataSigned16; } else if ((v & 0xFFFF) == 0xB70F) { // MOVZ v >>= 16; prefix = 2; - size16 = true; + size = Accessor::DataUnsigned16; } else return false; @@ -190,7 +196,7 @@ Accessor::Accessor(uint32_t function, Process *p) } else { - bool size16; + DataWidth xsize; int ptr_reg = 1, tmp; // ECX // MOV REG,[ESP+4] @@ -200,24 +206,19 @@ Accessor::Accessor(uint32_t function, Process *p) v = p->readQuad(ptr); } - this->dataWidth = 4; - - if (match_MOV_MEM(ptr, v, ptr_reg, tmp, this->offset1, size16)) { + if (match_MOV_MEM(ptr, v, ptr_reg, tmp, this->offset1, xsize)) { data_reg = tmp; this->type = ACCESSOR_INDIRECT; + this->dataWidth = xsize; - if (size16) - this->dataWidth = 2; - else + if (xsize == Data32) { v = p->readQuad(ptr); - if (match_MOV_MEM(ptr, v, data_reg, tmp, this->offset2, size16)) { + if (match_MOV_MEM(ptr, v, data_reg, tmp, this->offset2, xsize)) { data_reg = tmp; this->type = ACCESSOR_DOUBLE_INDIRECT; - - if (size16) - this->dataWidth = 2; + this->dataWidth = xsize; } } } @@ -245,29 +246,26 @@ bool Accessor::isConstant() int32_t Accessor::getValue(uint32_t objectPtr) { + int32_t offset = this->offset1; + switch(this->type) { case ACCESSOR_CONSTANT: return this->constant; break; - case ACCESSOR_INDIRECT: - switch(this->dataWidth) - { - case 2: - return (int16_t) p->readWord(objectPtr + this->offset1); - case 4: - return p->readDWord(objectPtr + this->offset1); - default: - return -1; - } - break; case ACCESSOR_DOUBLE_INDIRECT: + objectPtr = p->readDWord(objectPtr + this->offset1); + offset = this->offset2; + // fallthrough + case ACCESSOR_INDIRECT: switch(this->dataWidth) { - case 2: - return (int16_t) p->readWord(p->readDWord(objectPtr + this->offset1) + this->offset2); - case 4: - return p->readDWord(p->readDWord(objectPtr + this->offset1) + this->offset2); + case Data32: + return p->readDWord(objectPtr + offset); + case DataSigned16: + return (int16_t) p->readWord(objectPtr + offset); + case DataUnsigned16: + return (uint16_t) p->readWord(objectPtr + offset); default: return -1; } From 109d20d2517d69e3a25ff8a49e033a5565de1fb4 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 10 Apr 2011 23:25:41 +0400 Subject: [PATCH 5/7] Add an experimental program for cleaning up garbage owned by dwarfs. As noted by Quietust on the forum, cleaning the owned flag from the items does not actually remove the owner, but the item ceases to be protected from manipulation by other dwarfs. This should be enough to work around various bugs, like untouchable rotten food producing miasma, or dwarfs littering the place with worn objects. --- tools/playground/CMakeLists.txt | 2 + tools/playground/cleanowned.cpp | 132 ++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 tools/playground/cleanowned.cpp diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index b44cb9c9b..7bc5ad1e9 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -80,6 +80,8 @@ DFHACK_TOOL(dfprinttiletypes printtiletypes.cpp) # Will have many options in the future. DFHACK_TOOL(dfhellhole hellhole.cpp) +DFHACK_TOOL(dfcleanowned cleanowned.cpp) + # this needs the C bindings IF(BUILD_DFHACK_C_BINDINGS) # for trying out some 'stuff' diff --git a/tools/playground/cleanowned.cpp b/tools/playground/cleanowned.cpp new file mode 100644 index 000000000..ddd54de69 --- /dev/null +++ b/tools/playground/cleanowned.cpp @@ -0,0 +1,132 @@ +/* + * Confiscates and dumps garbage owned by dwarfs. + */ + +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include + +DFHack::Materials * Materials; +DFHack::Items * Items; + +int main (int argc, char *argv[]) +{ + bool dump_scattered = false; + int wear_dump_level = 65536; + + for(int i = 1; i < argc; i++) + { + char *arg = argv[i]; + if (arg[0] != '-') + continue; + + for (; *arg; arg++) { + switch (arg[0]) { + case 'j': + dump_scattered = true; + break; + case 'x': + wear_dump_level = 1; + break; + case 'X': + wear_dump_level = 2; + break; + } + } + } + + DFHack::Process * p; + unsigned int i,j; + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context * DF; + try + { + DF = DFMgr.getSingleContext(); + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; +#ifndef LINUX_BUILD + cin.ignore(); +#endif + return 1; + } + + DFHack::VersionInfo * mem = DF->getMemoryInfo(); + Materials = DF->getMaterials(); + Items = DF->getItems(); + + Materials->ReadAllMaterials(); + p = DF->getProcess(); + DFHack::OffsetGroup* itemGroup = mem->getGroup("Items"); + unsigned vector_addr = itemGroup->getAddress("items_vector"); + DFHack::DfVector p_items (p, vector_addr); + uint32_t size = p_items.size(); + + printf("Found total %d items.\n", size); + + for (i=0;igetItemData(curItem, itm); + + if (!itm.header.flags.bits.owned) + continue; + + bool confiscate = false; + bool dump = false; + + if (itm.header.flags.bits.rotten) + { + printf("Confiscating a rotten item.\n"); + confiscate = true; + } + else if (itm.wear_level >= wear_dump_level) + { + printf("Confiscating and dumping a worn item.\n"); + confiscate = true; + dump = true; + } + else if (dump_scattered && itm.header.flags.bits.on_ground) + { + printf("Confiscating and dumping an untidily placed item.\n"); + confiscate = true; + dump = true; + } + + if (confiscate) + { + itm.header.flags.bits.owned = 0; + if (dump) + itm.header.flags.bits.dump = 1; + + Items->setItemFlags(curItem, itm.header.flags); + + printf( + "%5d: %08x %08x (%d,%d,%d) #%08x [%d] %s - %s\n", + i, curItem, itm.header.flags.whole, + itm.header.x, itm.header.y, itm.header.z, + p->readDWord(curItem), + itm.wear_level, + Items->getItemClass(itm.matdesc.itemType).c_str(), + Items->getItemDescription(curItem, Materials).c_str() + ); + } + } + +#ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); +#endif + return 0; +} From 2e0ec2db7251666fce7093f33098ce6ca89f2dd7 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 11 Apr 2011 14:32:53 +0400 Subject: [PATCH 6/7] Support retrieving the item owner reference. Reference is done by item id, and stored in some kind of generic reference vector in the item structure. --- Memory.xml | 6 +++- library/include/dfhack/DFTypes.h | 4 +-- library/include/dfhack/modules/Creatures.h | 2 ++ library/include/dfhack/modules/Items.h | 1 + library/modules/Creatures.cpp | 33 +++++++++++++++++++ library/modules/Items.cpp | 38 ++++++++++++++++++++++ 6 files changed, 81 insertions(+), 3 deletions(-) diff --git a/Memory.xml b/Memory.xml index 654363ca6..d92156255 100644 --- a/Memory.xml +++ b/Memory.xml @@ -870,7 +870,7 @@ - + @@ -996,6 +996,8 @@ + +
@@ -2956,6 +2958,8 @@ + + diff --git a/library/include/dfhack/DFTypes.h b/library/include/dfhack/DFTypes.h index c1d7c646e..56ea5d857 100644 --- a/library/include/dfhack/DFTypes.h +++ b/library/include/dfhack/DFTypes.h @@ -128,10 +128,10 @@ struct naked_itemflags unsigned int u_ngrd2 : 1; // 0000 0010 unknown, lost (artifact)?, unseen unsigned int in_building : 1; // 0000 0020 Part of a building (including mechanisms, bodies in coffins) unsigned int u_ngrd3 : 1; // 0000 0040 unknown, unseen - unsigned int dead_body : 1; // 0000 0080 Dwarf's dead body or body part + unsigned int dead_dwarf : 1; // 0000 0080 Dwarf's dead body or body part unsigned int rotten : 1; // 0000 0100 Rotten food - unsigned int spider_web : 1; // 0000 0200 Spider web + unsigned int spider_web : 1; // 0000 0200 Thread in spider web unsigned int construction : 1; // 0000 0400 Material used in construction unsigned int u_ngrd5 : 1; // 0000 0800 unknown, unseen diff --git a/library/include/dfhack/modules/Creatures.h b/library/include/dfhack/modules/Creatures.h index 4f1ee296f..fe8c1ac58 100644 --- a/library/include/dfhack/modules/Creatures.h +++ b/library/include/dfhack/modules/Creatures.h @@ -320,6 +320,8 @@ namespace DFHack bool ReadInventoryIdx(const uint32_t index, std::vector & item); bool ReadInventoryPtr(const uint32_t index, std::vector & item); + int32_t FindIndexById(int32_t id); + /* Getters */ uint32_t GetDwarfRaceIndex ( void ); int32_t GetDwarfCivId ( void ); diff --git a/library/include/dfhack/modules/Items.h b/library/include/dfhack/modules/Items.h index 871b7b01d..72dcd9967 100644 --- a/library/include/dfhack/modules/Items.h +++ b/library/include/dfhack/modules/Items.h @@ -47,6 +47,7 @@ public: std::string getItemDescription(uint32_t itemptr, Materials * Materials); std::string getItemClass(int32_t index); bool getItemData(uint32_t itemptr, t_item & item); + int32_t getItemOwnerID(uint32_t itemptr); void setItemFlags(uint32_t itemptr, t_itemflags new_flags); private: class Private; diff --git a/library/modules/Creatures.cpp b/library/modules/Creatures.cpp index 2e589d967..9e91a1e76 100644 --- a/library/modules/Creatures.cpp +++ b/library/modules/Creatures.cpp @@ -106,6 +106,8 @@ struct Creatures::Private uint32_t creature_module; uint32_t dwarf_race_index_addr; uint32_t dwarf_civ_id_addr; + bool IdMapReady; + std::map IdMap; DfVector *p_cre; DFContextShared *d; Process *owner; @@ -123,6 +125,7 @@ Creatures::Creatures(DFContextShared* _d) d->owner = _d->p; d->Inited = false; d->Started = false; + d->IdMapReady = false; d->p_cre = NULL; d->d->InitReadNames(); // throws on error VersionInfo * minfo = d->d->offset_descriptor; @@ -228,6 +231,7 @@ bool Creatures::Start( uint32_t &numcreatures ) d->p_cre = new DfVector (d->owner, d->creatures.vector); d->Started = true; numcreatures = d->p_cre->size(); + d->IdMapReady = false; return true; } return false; @@ -407,6 +411,35 @@ int32_t Creatures::ReadCreatureInBox (int32_t index, t_creature & furball, return -1; } +int32_t Creatures::FindIndexById(int32_t creature_id) +{ + if (!d->Started || !d->Ft_basic) + return -1; + + if (!d->IdMapReady) + { + d->IdMap.clear(); + + Process * p = d->owner; + Private::t_offsets &offs = d->creatures; + + uint32_t size = d->p_cre->size(); + for (uint32_t index = 0; index < size; index++) + { + uint32_t temp = d->p_cre->at(index); + int32_t id = p->readDWord (temp + offs.id_offset); + d->IdMap[id] = index; + } + } + + std::map::iterator it; + it = d->IdMap.find(creature_id); + if(it == d->IdMap.end()) + return -1; + else + return it->second; +} + bool Creatures::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]) { if(!d->Started || !d->Ft_advanced) return false; diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 742c91fa5..d29753b7d 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -326,6 +326,9 @@ class Items::Private Process * owner; std::map descType; std::map descVTable; + uint32_t refVectorOffset; + uint32_t refIDOffset; + uint32_t ownerRefVTable; }; Items::Items(DFContextShared * d_) @@ -333,6 +336,7 @@ Items::Items(DFContextShared * d_) d = new Private; d->d = d_; d->owner = d_->p; + d->ownerRefVTable = d->refVectorOffset = d->refIDOffset = 0; } bool Items::Start() @@ -385,6 +389,40 @@ void Items::setItemFlags(uint32_t itemptr, t_itemflags new_flags) d->owner->writeDWord(itemptr + 0x0C, new_flags.whole); } +int32_t Items::getItemOwnerID(uint32_t itemptr) +{ + 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"); + } + + DFHack::DfVector p_refs(d->owner, itemptr + d->refVectorOffset); + uint32_t size = p_refs.size(); + + for (uint32_t i=0;iowner->readDWord(curRef); + + if (!d->ownerRefVTable) + { + std::string className = d->owner->readClassName(vtbl); + if (className == "general_ref_unit_itemownerst") + d->ownerRefVTable = vtbl; + else + continue; + } + else if (d->ownerRefVTable != vtbl) + continue; + + return d->owner->readDWord(curRef + d->refIDOffset); + } + + return -1; +} + std::string Items::getItemClass(int32_t index) { std::map::iterator it; From 325e817d71bf37ee20b0cc1dd5ba854b98d8205c Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 11 Apr 2011 14:33:30 +0400 Subject: [PATCH 7/7] Improve the owner cleanup program a bit more. --- tools/playground/cleanowned.cpp | 91 ++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/tools/playground/cleanowned.cpp b/tools/playground/cleanowned.cpp index ddd54de69..116754dc8 100644 --- a/tools/playground/cleanowned.cpp +++ b/tools/playground/cleanowned.cpp @@ -14,25 +14,30 @@ using namespace std; #include #include -DFHack::Materials * Materials; -DFHack::Items * Items; - int main (int argc, char *argv[]) { bool dump_scattered = false; + bool confiscate_all = false; + bool dry_run = false; int wear_dump_level = 65536; - + for(int i = 1; i < argc; i++) { char *arg = argv[i]; if (arg[0] != '-') continue; - + for (; *arg; arg++) { switch (arg[0]) { - case 'j': + case 'd': + dry_run = true; + break; + case 'l': dump_scattered = true; break; + case 'a': + confiscate_all = true; + break; case 'x': wear_dump_level = 1; break; @@ -42,7 +47,7 @@ int main (int argc, char *argv[]) } } } - + DFHack::Process * p; unsigned int i,j; DFHack::ContextManager DFMgr("Memory.xml"); @@ -62,16 +67,22 @@ int main (int argc, char *argv[]) } DFHack::VersionInfo * mem = DF->getMemoryInfo(); - Materials = DF->getMaterials(); - Items = DF->getItems(); - + DFHack::Materials *Materials = DF->getMaterials(); + DFHack::Items *Items = DF->getItems(); + DFHack::Creatures *Creatures = DF->getCreatures(); + DFHack::Translation *Tran = DF->getTranslation(); + Materials->ReadAllMaterials(); + uint32_t num_creatures; + Creatures->Start(num_creatures); + Tran->Start(); + p = DF->getProcess(); DFHack::OffsetGroup* itemGroup = mem->getGroup("Items"); unsigned vector_addr = itemGroup->getAddress("items_vector"); DFHack::DfVector p_items (p, vector_addr); uint32_t size = p_items.size(); - + printf("Found total %d items.\n", size); for (i=0;igetItemData(curItem, itm); - + if (!itm.header.flags.bits.owned) continue; bool confiscate = false; bool dump = false; - + if (itm.header.flags.bits.rotten) { - printf("Confiscating a rotten item.\n"); + printf("Confiscating a rotten item: \t"); confiscate = true; } else if (itm.wear_level >= wear_dump_level) { - printf("Confiscating and dumping a worn item.\n"); + printf("Confiscating and dumping a worn item: \t"); confiscate = true; dump = true; } else if (dump_scattered && itm.header.flags.bits.on_ground) { - printf("Confiscating and dumping an untidily placed item.\n"); + printf("Confiscating and dumping litter: \t"); confiscate = true; dump = true; } - + else if (confiscate_all) + { + printf("Confiscating: \t"); + confiscate = true; + } + if (confiscate) { itm.header.flags.bits.owned = 0; if (dump) itm.header.flags.bits.dump = 1; - Items->setItemFlags(curItem, itm.header.flags); + if (!dry_run) + Items->setItemFlags(curItem, itm.header.flags); printf( - "%5d: %08x %08x (%d,%d,%d) #%08x [%d] %s - %s\n", - i, curItem, itm.header.flags.whole, - itm.header.x, itm.header.y, itm.header.z, + "%s (wear %d)", + Items->getItemDescription(curItem, Materials).c_str(), + itm.wear_level + ); + + int32_t owner = Items->getItemOwnerID(curItem); + int32_t owner_index = Creatures->FindIndexById(owner); + std::string info; + + if (owner_index >= 0) + { + DFHack::t_creature temp; + Creatures->ReadCreature(owner_index,temp); + temp.name.first_name[0] = toupper(temp.name.first_name[0]); + info = temp.name.first_name; + if (temp.name.nickname[0]) + info += std::string(" '") + temp.name.nickname + "'"; + info += " "; + info += Tran->TranslateName(temp.name,false); + printf(", owner %s", info.c_str()); + } + + printf("\n"); + +/* printf( + "%5d: %08x %08x (%d,%d,%d) #%08x [%d] %s - %s %s\n", + i, curItem, itm.header.flags.whole, + itm.header.x, itm.header.y, itm.header.z, p->readDWord(curItem), itm.wear_level, Items->getItemClass(itm.matdesc.itemType).c_str(), - Items->getItemDescription(curItem, Materials).c_str() - ); + Items->getItemDescription(curItem, Materials).c_str(), + info.c_str() + );*/ } - } + } #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl;