From 726519e2cab80966f7271e7ddc225d1e7a9b1ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 25 Feb 2010 13:41:57 +0100 Subject: [PATCH] Major memory_info rework. All tags and vtable="" attributes in Memory.xml are now obsolete. tags are still important, but don't need the vtable attrs. Vtables are resolved automatically. All this will be left in Memory.xml until utility authors update to this version or newer. --- examples/buildingsdump.cpp | 12 +- examples/dfitemdump.cpp | 148 ++++++++++++++++------ examples/renamer.cpp | 19 ++- examples/veinlook.cpp | 3 - library/DFHackAPI.cpp | 18 +-- library/DFHackAPI.h | 5 +- library/DFMemInfo.cpp | 231 +++++++++++++++-------------------- library/DFMemInfo.h | 91 ++++++++++++-- library/DFMemInfoManager.cpp | 22 +++- library/DFMemInfoManager.h | 1 + library/DFWindow-linux.cpp | 4 +- library/DFWindow-windows.cpp | 4 +- tools/dfbauxite.cpp | 10 +- tools/itemdesignator.cpp | 33 ++--- 14 files changed, 367 insertions(+), 234 deletions(-) diff --git a/examples/buildingsdump.cpp b/examples/buildingsdump.cpp index 99a0ba3f1..3207d396f 100644 --- a/examples/buildingsdump.cpp +++ b/examples/buildingsdump.cpp @@ -10,6 +10,7 @@ using namespace std; #include #include +#include /* oh. fsck it. I'll do the hexdump now and add the things I found in a research/ folder groups of four bytes, 4 per line @@ -135,12 +136,7 @@ int main (int argc,const char* argv[]) cerr << "DF not found" << endl; return 1; } - - /* - * Get the object name/ID mapping - */ - vector objecttypes; - DF.getClassIDMapping (objecttypes); + DFHack::memory_info * mem = DF.getMemoryInfo(); uint32_t numBuildings; if(DF.InitReadBuildings(numBuildings)) @@ -152,7 +148,9 @@ int main (int argc,const char* argv[]) DF.ReadBuilding(i, temp); if(temp.type != 0xFFFFFFFF) // check if type isn't invalid { - if(objecttypes[temp.type] == argv[1]) + string typestr; + mem->resolveClassIDToClassname(temp.type, typestr); + if(typestr == argv[1]) { //cout << buildingtypes[temp.type] << " 0x" << hex << temp.origin << endl; //hexdump(DF, temp.origin, 16); diff --git a/examples/dfitemdump.cpp b/examples/dfitemdump.cpp index 15ced0c5f..cf20556f1 100644 --- a/examples/dfitemdump.cpp +++ b/examples/dfitemdump.cpp @@ -10,6 +10,7 @@ using namespace std; #include #include +#include struct matGlosses { @@ -20,60 +21,124 @@ struct matGlosses vector creatureMat; }; -string getMaterialType(DFHack::t_item item, const vector & buildingTypes,const matGlosses & mat){ - if(item.type == 85 || item.type == 113 || item.type == 117) // item_plant or item_thread or item_seeds +string getMaterialType(DFHack::t_item item, const string & itemtype,const matGlosses & mat) +{ + // plant thread seeds + if(itemtype == "item_plant" || itemtype == "item_thread" || itemtype == "item_seeds" || itemtype == "item_leaves" ) { - return(string(mat.plantMat[item.material.type].id)); + return mat.plantMat[item.material.type].id; } - else if(item.type == 109 || item.type == 114 || item.type == 115 || item.type == 116 || item.type==128 || item.type == 129|| item.type == 130|| item.type == 131) // item_skin_raw item_bones item_skill item_fish_raw item_pet item_skin_tanned item_shell + else if (itemtype == "item_drink") // drinks must have different offset for materials { - return(string(mat.creatureMat[item.material.type].id)); + return "Booze or something"; } - else if(item.type == 124){ //wood - return(string(mat.woodMat[item.material.type].id)); + // item_skin_raw item_bones item_skull item_fish_raw item_pet item_skin_tanned item_shell + else if(itemtype == "item_skin_raw" || + itemtype == "item_skin_tanned" || + itemtype == "item_fish_raw" || + itemtype == "item_pet" || + itemtype == "item_shell" || + itemtype == "item_horn"|| + itemtype == "item_skull" || + itemtype == "item_bones" || + itemtype == "item_corpse" || + itemtype == "item_meat" + ) + { + return mat.creatureMat[item.material.type].id; } - else if(item.type == 118){ //blocks - return(string(mat.metalMat[item.material.index].id)); + else if(itemtype == "item_wood") + { + return mat.woodMat[item.material.type].id; } - else if(item.type == 86){ // item_glob I don't know what those are in game, just ignore them - return(string("")); + else if(itemtype == "item_bar") + { + return mat.metalMat[item.material.type].id; } - else{ + else + { + /* + Mat_Wood, + Mat_Stone, + Mat_Metal, + Mat_Plant, + Mat_Leather = 10, + Mat_SilkCloth = 11, + Mat_PlantCloth = 12, + Mat_GreenGlass = 13, + Mat_ClearGlass = 14, + Mat_CrystalGlass = 15, + Mat_Ice = 17, + Mat_Charcoal =18, + Mat_Potash = 19, + Mat_Ashes = 20, + Mat_PearlAsh = 21, + Mat_Soap = 24, + */ switch (item.material.type) { - case 0: - return(string(mat.woodMat[item.material.index].id)); - break; - case 1: - return(string(mat.stoneMat[item.material.index].id)); + case DFHack::Mat_Wood: + return mat.woodMat[item.material.index].id; break; - case 2: - return(string(mat.metalMat[item.material.index].id)); + case DFHack::Mat_Stone: + return mat.stoneMat[item.material.index].id; break; - case 12: // don't ask me why this has such a large jump, maybe this is not actually the matType for plants, but they all have this set to 12 - return(string(mat.plantMat[item.material.index].id)); + case DFHack::Mat_Metal: + return mat.metalMat[item.material.index].id; break; - case 3: - case 9: - case 10: - case 11: - case 121: - return(string(mat.creatureMat[item.material.index].id)); + //case DFHack::Mat_Plant: + case DFHack::Mat_PlantCloth: + //return mat.plantMat[item.material.index].id; + return string(mat.plantMat[item.material.index].id) + " plant"; break; + case 3: // bone + return string(mat.creatureMat[item.material.index].id) + " bone"; + case 25: // fat + return string(mat.creatureMat[item.material.index].id) + " fat"; + case 23: // tallow + return string(mat.creatureMat[item.material.index].id) + " tallow"; + case 9: // shell + return string(mat.creatureMat[item.material.index].id) + " shell"; + case DFHack::Mat_Leather: // really a generic creature material. meat for item_food, leather for item_box... + return string(mat.creatureMat[item.material.index].id); + case DFHack::Mat_SilkCloth: + return string(mat.creatureMat[item.material.index].id) + " silk"; + case DFHack::Mat_Soap: + return string(mat.creatureMat[item.material.index].id) + " soap"; + case DFHack::Mat_GreenGlass: + return "Green Glass"; + case DFHack::Mat_ClearGlass: + return "Clear Glass"; + case DFHack::Mat_CrystalGlass: + return "Crystal Glass"; + case DFHack::Mat_Ice: + return "Ice"; + case DFHack::Mat_Charcoal: + return "Charcoal"; + /*case DFHack::Mat_Potash: + return "Potash";*/ + case DFHack::Mat_Ashes: + return "Ashes"; + case DFHack::Mat_PearlAsh: + return "Pearlash"; default: - //DF.setCursorCoords(item.x,item.y,item.z); - return(string("")); + cout << "unknown material hit: " << item.material.type << " " << item.material.index << " " << itemtype << endl; + return "Invalid"; } } + return "Invalid"; } -void printItem(DFHack::t_item item, const vector & buildingTypes,const matGlosses & mat){ +void printItem(DFHack::t_item item, const string & typeString,const matGlosses & mat) +{ cout << dec << "Item at x:" << item.x << " y:" << item.y << " z:" << item.z << endl; - cout << "Type: " << (int) item.type << " " << buildingTypes[item.type] << " Address: " << hex << item.origin << endl; + cout << "Type: " << (int) item.type << " " << typeString << " Address: " << hex << item.origin << endl; cout << "Material: "; - - string itemType = getMaterialType(item,buildingTypes,mat); + + string itemType = getMaterialType(item,typeString,mat); cout << itemType << endl; } + + int main () { @@ -84,7 +149,7 @@ int main () cerr << "DF not found" << endl; return 1; } - DF.Suspend(); + DFHack::memory_info * mem = DF.getMemoryInfo(); DF.InitViewAndCursor(); matGlosses mat; DF.ReadPlantMatgloss(mat.plantMat); @@ -93,8 +158,8 @@ int main () DF.ReadMetalMatgloss(mat.metalMat); DF.ReadCreatureMatgloss(mat.creatureMat); - vector objecttypes; - DF.getClassIDMapping(objecttypes); +// vector objecttypes; +// DF.getClassIDMapping(objecttypes); uint32_t numItems; DF.InitReadItems(numItems); @@ -133,14 +198,18 @@ int main () } else if(foundItems.size() == 1) { - printItem(foundItems[0], objecttypes ,mat); + string itemtype; + mem->resolveClassIDToClassname(foundItems[0].type,itemtype); + printItem(foundItems[0], itemtype ,mat); } else { cerr << "Please Select which item you want to display\n"; + string itemtype; for(uint32_t j = 0; j < foundItems.size(); ++j) { - cerr << j << " " << objecttypes[foundItems[j].type] << endl; + mem->resolveClassIDToClassname(foundItems[j].type,itemtype); + cerr << j << " " << itemtype << endl; } uint32_t value; string input2; @@ -157,7 +226,8 @@ int main () ss.str(input2); ss >> value; } - printItem(foundItems[value], objecttypes ,mat); + mem->resolveClassIDToClassname(foundItems[value].type,itemtype); + printItem(foundItems[value], itemtype ,mat); } DF.FinishReadItems(); } diff --git a/examples/renamer.cpp b/examples/renamer.cpp index 2a374d014..4c8e94290 100644 --- a/examples/renamer.cpp +++ b/examples/renamer.cpp @@ -23,7 +23,6 @@ void print_bits ( T val, std::ostream& out ) val >>= 1; } } -vector objecttypes; map > names; uint32_t numCreatures; vector creaturestypes; @@ -190,8 +189,10 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true) DFHack::t_viewscreen current; DF.Suspend(); DF.ReadViewScreen(current); + string nowScreenState; + DF.getMemoryInfo()->resolveClassIDToClassname(current.type,nowScreenState); int tryCount = 0; - while (((EqualTo && objecttypes[current.type] != screenState) || (!EqualTo && objecttypes[current.type] == screenState)) && tryCount < 50) + while (((EqualTo && nowScreenState != screenState) || (!EqualTo && nowScreenState == screenState)) && tryCount < 50) { DF.Resume(); w->TypeSpecial(DFHack::WAIT,1,100); @@ -200,7 +201,7 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true) tryCount++; } if (tryCount >= 50) { - cerr << "Something went wrong, DF at " << objecttypes[current.type] << endl; + cerr << "Something went wrong, DF at " << nowScreenState << endl; return false; } DF.Resume(); @@ -262,13 +263,16 @@ bool moveToBaseWindow(DFHack::API &DF) DFHack::DFWindow * w = DF.getWindow(); DFHack::t_viewscreen current; DF.ReadViewScreen(current); - while (objecttypes[current.type] != string("viewscreen_dwarfmode")) + string classname; + DF.getMemoryInfo()->resolveClassIDToClassname(current.type,classname); + while (classname != "viewscreen_dwarfmode") { w->TypeSpecial(DFHack::F9); // cancel out of text input in names // DF.TypeSpecial(DFHack::ENTER); // cancel out of text input in hotkeys w->TypeSpecial(DFHack::SPACE); // should move up a level - if (!waitTillScreenState(DF,objecttypes[current.type],false)) return false; // wait until screen changes from current + if (!waitTillScreenState(DF,classname,false)) return false; // wait until screen changes from current DF.ReadViewScreen(current); + DF.getMemoryInfo()->resolveClassIDToClassname(current.type,classname); } if (DF.ReadMenuState() != 0) {// if menu state != 0 then there is a menu, so escape it w->TypeSpecial(DFHack::F9); @@ -311,11 +315,6 @@ int main (void) return 1; } DF.Suspend(); - if (!DF.getClassIDMapping(objecttypes)) - { - cerr << "Can't get type info" << endl; - return 1; - } DFHack::memory_info * mem = DF.getMemoryInfo(); diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index f2886ab54..37fe2ea64 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -316,9 +316,6 @@ main(int argc, char *argv[]) finish(0); } - vector classes; - p->getDescriptor()->getClassIDMapping(classes); - // get region geology if(!DF.ReadGeology( layerassign )) { diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index c0521232b..ab281c97e 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -166,8 +166,12 @@ bool API::InitMap() d->veinvector = d->offset_descriptor->getOffset ("v_vein"); d->veinsize = d->offset_descriptor->getHexValue ("v_vein_size"); - d->vein_ice_vptr = d->offset_descriptor->getClassVPtr("block_square_event_frozen_liquid"); - d->vein_mineral_vptr = d->offset_descriptor->getClassVPtr("block_square_event_mineral"); + // these can fail and will be found when looking at the actual veins later + // basically a cache + d->vein_ice_vptr = 0; + d->offset_descriptor->resolveClassnameToVPtr("block_square_event_frozen_liquid", d->vein_ice_vptr); + d->vein_mineral_vptr = 0; + d->offset_descriptor->resolveClassnameToVPtr("block_square_event_mineral",d->vein_mineral_vptr); // get the map pointer uint32_t x_array_loc = g_pProcess->readDWord (map_offset); @@ -756,7 +760,7 @@ bool API::ReadBuilding (const int32_t &index, t_building & building) // transform int32_t type = -1; - d->offset_descriptor->resolveClassId (temp, type); + d->offset_descriptor->resolveObjectToClassID (temp, type); building.origin = temp; building.vtable = bld_40d.vtable; building.x1 = bld_40d.x1; @@ -1425,7 +1429,7 @@ bool API::getWindowSize (int32_t &width, int32_t &height) height = coords[1]; return true; } - +/* bool API::getClassIDMapping (vector & objecttypes) { if(isAttached()) @@ -1435,7 +1439,7 @@ bool API::getClassIDMapping (vector & objecttypes) } return false; } - +*/ memory_info *API::getMemoryInfo() { return d->offset_descriptor; @@ -1482,7 +1486,7 @@ bool API::ReadItem (const uint32_t &index, t_item & item) // transform int32_t type = -1; - d->offset_descriptor->resolveClassId (temp, type); + d->offset_descriptor->resolveObjectToClassID (temp, type); item.origin = temp; item.vtable = item_40d.vtable; item.x = item_40d.x; @@ -1533,7 +1537,7 @@ bool API::ReadViewScreen (t_viewscreen &screen) screenAddr = g_pProcess->readDWord (nextScreenPtr); nextScreenPtr = g_pProcess->readDWord (nextScreenPtr + 4); } - return d->offset_descriptor->resolveClassId (last, screen.type); + return d->offset_descriptor->resolveObjectToClassID (last, screen.type); } bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes) { diff --git a/library/DFHackAPI.h b/library/DFHackAPI.h index 313c5ec96..3f6e8498b 100644 --- a/library/DFHackAPI.h +++ b/library/DFHackAPI.h @@ -225,10 +225,7 @@ namespace DFHack bool InitReadItems(uint32_t & numitems); bool ReadItem(const uint32_t &index, t_item & item); void FinishReadItems(); - - // wrapper for meminfo method of the same name - bool getClassIDMapping (vector & objecttypes); - + memory_info *getMemoryInfo(); Process * getProcess(); DFWindow * getWindow(); diff --git a/library/DFMemInfo.cpp b/library/DFMemInfo.cpp index 2fe2c5438..e3f6e1520 100644 --- a/library/DFMemInfo.cpp +++ b/library/DFMemInfo.cpp @@ -44,28 +44,6 @@ using namespace boost::multi_index; */ using namespace DFHack; - -/* -* Common data types -*/ -struct t_class -{ - string classname; - uint32_t vtable; - bool is_multiclass; - uint32_t multi_index; - uint32_t assign;// index to typeclass array if multiclass. return value if not. - uint32_t type_offset; // offset of type data for multiclass -}; - -struct t_type -{ - string classname; - uint32_t assign; - uint32_t type; -}; - - /* * Private data */ @@ -83,14 +61,19 @@ class memory_info::Private vector< vector > traits; map labors; - vector classes; - vector > classsubtypes; + // storage for class and multiclass + vector classes; + //vector > classsubtypes; + // cache for faster name lookup, indexed by classID + vector classnames; + int32_t base; uint32_t classindex; string version; OSType OS; }; +// normal constructor memory_info::memory_info() :d(new Private) { @@ -98,6 +81,37 @@ memory_info::memory_info() d->classindex = 0; } +// copy constructor +memory_info::memory_info(const memory_info &old) +:d(new Private) +{ + d->version = old.d->version; + d->OS = old.d->OS; + d->addresses = old.d->addresses; + d->offsets = old.d->offsets; + d->hexvals = old.d->hexvals; + d->strings = old.d->strings; + d->base = old.d->base; + d->classes = old.d->classes; + d->classindex = old.d->classindex; + d->professions = old.d->professions; + d->jobs = old.d->jobs; + d->skills = old.d->skills; + d->traits = old.d->traits; + d->labors = old.d->labors; +} + +// destructor +memory_info::~memory_info() +{ + // delete the vtables + for(int i = 0; i < d->classes.size();i++) + { + delete d->classes[i]; + } + // delete our data + delete d; +} void memory_info::setVersion(const char * v) { @@ -156,29 +170,6 @@ memory_info::OSType memory_info::getOS() const return d->OS; } - -// copy constructor -memory_info::memory_info(const memory_info &old) -:d(new Private) -{ - d->version = old.d->version; - d->OS = old.d->OS; - d->addresses = old.d->addresses; - d->offsets = old.d->offsets; - d->hexvals = old.d->hexvals; - d->strings = old.d->strings; - d->base = old.d->base; - d->classes = old.d->classes; - d->classsubtypes = old.d->classsubtypes; - d->classindex = old.d->classindex; - d->professions = old.d->professions; - d->jobs = old.d->jobs; - d->skills = old.d->skills; - d->traits = old.d->traits; - d->labors = old.d->labors; -} - - uint32_t memory_info::getBase () const { return d->base; @@ -282,151 +273,129 @@ void memory_info::setTrait(const string & key, } // FIXME: next three methods should use some kind of custom container so it doesn't have to search so much. -void memory_info::setClass (const char * name, const char * vtable) +t_class * memory_info::setClass (const char * name, uint32_t vtable, uint32_t typeoffset) { + if(name == 0) + return 0; for (uint32_t i=0; iclasses.size(); i++) { - if(d->classes[i].classname == name) + if(d->classes[i]->classname == name) { - d->classes[i].vtable = strtol(vtable, NULL, 16); - return; + if(vtable != 0) + d->classes[i]->vtable = vtable; + if(typeoffset != 0) + d->classes[i]->type_offset = typeoffset; + return d->classes[i]; } } - t_class cls; - cls.assign = d->classindex; - cls.classname = name; - cls.is_multiclass = false; - cls.type_offset = 0; - d->classindex++; - cls.vtable = strtol(vtable, NULL, 16); - d->classes.push_back(cls); - //cout << "class " << name << ", assign " << cls.assign << ", vtable " << cls.vtable << endl; -} - - -// find old entry by name, rewrite, return its multi index. otherwise make a new one, append an empty vector of t_type to classtypes, return its index. -uint32_t memory_info::setMultiClass (const char * name, const char * vtable, const char * typeoffset) -{ - for (uint32_t i=0; iclasses.size(); i++) - { - if(d->classes[i].classname == name) - { - // vtable and typeoffset can be left out from the xml definition when there's already a named multiclass - if(vtable != NULL) - d->classes[i].vtable = strtol(vtable, NULL, 16); - if(typeoffset != NULL) - d->classes[i].type_offset = strtol(typeoffset, NULL, 16); - return d->classes[i].multi_index; - } - } + t_class *cls = new t_class(); + // get an unique ID and add ourselves to the index + cls->assign = d->classindex; + cls->classname = name; + d->classnames.push_back(name); + + // vtables no longer a requirement + cls->vtable = vtable; + + // multi class yes/no + cls->type_offset = typeoffset; - //FIXME: add checking for vtable and typeoffset here. they HAVE to be valid. maybe change the return value into a bool and pass in multi index by reference? - t_class cls; - cls.assign = d->classindex; - cls.classname = name; - cls.is_multiclass = true; - cls.type_offset = strtol(typeoffset, NULL, 16); - cls.vtable = strtol(vtable, NULL, 16); - cls.multi_index = d->classsubtypes.size(); d->classes.push_back(cls); d->classindex++; - - vector thistypes; - d->classsubtypes.push_back(thistypes); - //cout << "multiclass " << name << ", assign " << cls.assign << ", vtable " << cls.vtable << endl; - return d->classsubtypes.size() - 1; + return cls; + } -void memory_info::setMultiClassChild (uint32_t multi_index, const char * name, const char * type) +void memory_info::setClassChild (t_class * parent, const char * name, const char * type) { - vector & vec = d->classsubtypes[multi_index]; + vector & vec = parent->subs; for (uint32_t i=0; iclassname == name) { - vec[i].type = strtol(type, NULL, 16); + vec[i]->type = strtol(type, NULL, 16); return; } } // new multiclass child - t_type mcc; - mcc.assign = d->classindex; - mcc.classname = name; - mcc.type = strtol(type, NULL, 16); + t_type *mcc = new t_type(d->classindex,strtol(type, NULL, 16),name); + d->classnames.push_back(name); vec.push_back(mcc); d->classindex++; - //cout << " classtype " << name << ", assign " << mcc.assign << ", vtable " << mcc.type << endl; + + cout << " classtype " << name << ", assign " << mcc->assign << ", vtable " << mcc->type << endl; } -bool memory_info::resolveClassId(uint32_t address, int32_t & classid) +bool memory_info::resolveObjectToClassID(const uint32_t address, int32_t & classid) { uint32_t vtable = g_pProcess->readDWord(address); // FIXME: stupid search. we need a better container for(uint32_t i = 0;i< d->classes.size();i++) { - if(d->classes[i].vtable == vtable) // got class + if(d->classes[i]->vtable == vtable) // got class { // if it is a multiclass, try resolving it - if(d->classes[i].is_multiclass) + if(d->classes[i]->type_offset) { - vector & vec = d->classsubtypes[d->classes[i].multi_index]; - uint32_t type = g_pProcess->readWord(address + d->classes[i].type_offset); + vector & vec = d->classes[i]->subs; + uint32_t type = g_pProcess->readWord(address + d->classes[i]->type_offset); //printf ("class %d:%s offset 0x%x\n", i , classes[i].classname.c_str(), classes[i].type_offset); // return typed building if successful for (uint32_t k = 0; k < vec.size();k++) { - if(vec[k].type == type) + if(vec[k]->type == type) { //cout << " multi " << address + classes[i].type_offset << " " << vec[k].classname << endl; - classid = vec[k].assign; + classid = vec[k]->assign; return true; } } } // otherwise return the class we found - classid = d->classes[i].assign; + classid = d->classes[i]->assign; return true; } } - // we failed to find anything that would match - return false; + string classname = g_pProcess->readClassName(vtable); + setClass(classname.c_str(),vtable); + return true; } //ALERT: doesn't care about multiclasses -uint32_t memory_info::getClassVPtr(string classname) +bool memory_info::resolveClassnameToVPtr(const string classname, uint32_t & vptr) { // FIXME: another stupid search. for(uint32_t i = 0;i< d->classes.size();i++) { //if(classes[i].) - if(d->classes[i].classname == classname) // got class + if(d->classes[i]->classname == classname) // got class { - return d->classes[i].vtable; + vptr = d->classes[i]->vtable; + return true; } } // we failed to find anything that would match - return 0; + return false; } -// Flatten vtables into a index<->name mapping -void memory_info::getClassIDMapping(vector & v_ClassID2ObjName) +bool memory_info::resolveClassIDToClassname (const int32_t classID, string & classname) { - for(uint32_t i = 0;i< d->classes.size();i++) + if (classID >=0 && classID < d->classnames.size()) { - v_ClassID2ObjName.push_back(d->classes[i].classname); - if(!d->classes[i].is_multiclass) - { - continue; - } - vector & vec = d->classsubtypes[d->classes[i].multi_index]; - for (uint32_t k = 0; k < vec.size();k++) - { - v_ClassID2ObjName.push_back(vec[k].classname); - } + classname = d->classnames[classID]; + return true; } + return false; +} + + +// return pointer to our internal classID -> className mapping +const vector * memory_info::getClassIDMapping() +{ + return &d->classnames; } @@ -458,10 +427,10 @@ void memory_info::RebaseAll(int32_t new_base) // change all vtable entries by offset void memory_info::RebaseVTable(int32_t offset) { - vector::iterator iter; + vector::iterator iter; for(iter = d->classes.begin(); iter != d->classes.end(); iter++) { - iter->vtable += offset; + (*iter)->vtable += offset; } } @@ -631,6 +600,8 @@ string memory_info::getLabor (const uint32_t laborIdx) } // Reset everything +/* +0xDEADC0DE void memory_info::flush() { d->base = 0; @@ -639,8 +610,8 @@ void memory_info::flush() d->strings.clear(); d->hexvals.clear(); d->classes.clear(); - d->classsubtypes.clear(); d->classindex = 0; d->version = ""; d->OS = OS_BAD; } +*/ \ No newline at end of file diff --git a/library/DFMemInfo.h b/library/DFMemInfo.h index 5a265bd89..2b7146688 100644 --- a/library/DFMemInfo.h +++ b/library/DFMemInfo.h @@ -34,6 +34,51 @@ distribution. namespace DFHack { + /* + * Common data types + */ + struct t_type + { + t_type(uint32_t assign, uint32_t type, string classname) + :classname(classname),assign(assign),type(type){}; + string classname; + uint32_t assign; + uint32_t type; + }; + + struct t_class + { + t_class(const t_class &old) + { + classname = old.classname; + vtable = old.vtable; + assign = old.assign; + type_offset = old.type_offset; + for(int i = 0; i < old.subs.size();i++) + { + t_type * t = new t_type (*old.subs[i]); + subs.push_back(t); + } + } + t_class () + { + vtable = 0; + assign = 0; + type_offset = 0; + } + ~t_class() + { + for(int i = 0; i < subs.size();i++) + { + delete subs[i]; + } + } + string classname; + uint32_t vtable; + uint32_t assign;// index to typeclass array if multiclass. return value if not. + uint32_t type_offset; // offset of type data for multiclass + vector subs; + }; class DFHACK_EXPORT memory_info { @@ -49,7 +94,7 @@ namespace DFHack }; memory_info(); memory_info(const memory_info&); - + ~memory_info(); void RebaseAddresses(const int32_t new_base); void RebaseAll(const int32_t new_base); @@ -102,16 +147,40 @@ namespace DFHack void setLabor(const string &, const string &); void RebaseVTable(const int32_t offset); - void setClass (const char * name, const char * vtable); - uint32_t setMultiClass (const char * name, const char * vtable, const char * typeoffset); - void setMultiClassChild (uint32_t multi_index, const char * name, const char * type); - - // ALERT: uses memory reading directly - bool resolveClassId(const uint32_t address, int32_t & classid); - void getClassIDMapping(vector & v_ClassID2ObjName); - uint32_t getClassVPtr(string classname); - - void flush(); + + t_class * setClass (const char * classname, uint32_t vptr = 0, uint32_t typeoffset = 0); + void setClassChild (t_class * parent, const char * classname, const char * type); + + /* + * Get a classID from an address. The address has to point to the start of a virtual object (one with a virtual base class) + * uses memory reading directly, needs suspend. input = address of the object + * fails if it's unable to read from memory + */ + bool resolveObjectToClassID (const uint32_t address, int32_t & classID); + + /* + * Get a classID from an address. The address has to point to the start of a virtual object (one with a virtual base class) + * can fail if the class is not in the cache + */ + bool resolveClassnameToClassID (const string classname, int32_t & classID); + //bool resolveClassnameToClassID (const char * classname, int32_t & classID); + + /* + * Get a vptr from a classname. Can fail if the type is not in the cache + * limited to normal classes, variable-dependent types will resolve to the base class + */ + bool resolveClassnameToVPtr ( const string classname, uint32_t & vptr ); + //bool resolveClassnameToVPtr ( const char * classname, uint32_t & vptr ); + + /* + * Get a classname from a previous classID. Can fail if the type is not in the cache (you use bogus classID) + */ + bool resolveClassIDToClassname (const int32_t classID, string & classname); + + /* + * Get the internal classID->classname mapping (for speed). DO NOT MANIPULATE THE VECTOR! + */ + const vector * getClassIDMapping(); }; } #endif // MEMINFO_H_INCLUDED diff --git a/library/DFMemInfoManager.cpp b/library/DFMemInfoManager.cpp index beef88934..8e2a685e6 100644 --- a/library/DFMemInfoManager.cpp +++ b/library/DFMemInfoManager.cpp @@ -25,6 +25,16 @@ distribution. #include "DFCommonInternal.h" using namespace DFHack; +MemInfoManager::~MemInfoManager() +{ + // for each in std::vector meminfo;, delete + for(int i = 0; i < meminfo.size();i++) + { + delete meminfo[i]; + } + meminfo.clear(); +} + void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info* mem) { TiXmlElement* pClassEntry; @@ -43,17 +53,23 @@ void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info* mem) string type = pClassEntry->Value(); const char *cstr_name = pClassEntry->Attribute("name"); const char *cstr_vtable = pClassEntry->Attribute("vtable"); + uint32_t vtable = 0; + if(cstr_vtable) + vtable = strtol(cstr_vtable, NULL, 16); // it's a simple class if(type== "class") { - mem->setClass(cstr_name, cstr_vtable); + mem->setClass(cstr_name, vtable); } // it's a multi-type class else if (type == "multiclass") { // get offset of the type variable const char *cstr_typeoffset = pClassEntry->Attribute("typeoffset"); - int mclass = mem->setMultiClass(cstr_name, cstr_vtable, cstr_typeoffset); + uint32_t typeoffset = 0; + if(cstr_typeoffset) + typeoffset = strtol(cstr_typeoffset, NULL, 16); + t_class * mclass = mem->setClass(cstr_name, vtable, typeoffset); // parse class sub-entries pClassSubEntry = pClassEntry->FirstChildElement(); for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement()) @@ -64,7 +80,7 @@ void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info* mem) // type is a value loaded from type offset cstr_name = pClassSubEntry->Attribute("name"); const char *cstr_value = pClassSubEntry->Attribute("type"); - mem->setMultiClassChild(mclass,cstr_name,cstr_value); + mem->setClassChild(mclass,cstr_name,cstr_value); } } } diff --git a/library/DFMemInfoManager.h b/library/DFMemInfoManager.h index be89c57b9..ef5bf0a20 100644 --- a/library/DFMemInfoManager.h +++ b/library/DFMemInfoManager.h @@ -34,6 +34,7 @@ namespace DFHack friend class ProcessEnumerator; public: MemInfoManager(string path_to_xml); + ~MemInfoManager(); // memory info entries loaded from a file bool loadFile( string path_to_xml); bool isInErrorState() const {return error;}; diff --git a/library/DFWindow-linux.cpp b/library/DFWindow-linux.cpp index cf066e9ca..99880da44 100644 --- a/library/DFWindow-linux.cpp +++ b/library/DFWindow-linux.cpp @@ -117,7 +117,9 @@ DFWindow::DFWindow (Process * p) // dtor DFWindow::~DFWindow () -{} +{ + delete d; +} Window DFWindow::Private::EnumerateWindows (Display *display, Window rootWindow, const char *searchString) { diff --git a/library/DFWindow-windows.cpp b/library/DFWindow-windows.cpp index 95d09fa09..1fc100555 100644 --- a/library/DFWindow-windows.cpp +++ b/library/DFWindow-windows.cpp @@ -119,7 +119,9 @@ DFWindow::DFWindow (Process * p) // dtor DFWindow::~DFWindow () -{} +{ + delete d; +} // TODO: also investigate possible problems with UIPI on Vista and 7 void DFWindow::TypeStr (const char *input, int delay, bool useShift) diff --git a/tools/dfbauxite.cpp b/tools/dfbauxite.cpp index a08c01441..d9ff5b3a6 100644 --- a/tools/dfbauxite.cpp +++ b/tools/dfbauxite.cpp @@ -72,9 +72,10 @@ int main () /* * Get the object name/ID mapping */ + /* vector objecttypes; DF.getClassIDMapping (objecttypes); - + */ //FIXME: work on the 'supported features' system required /* * Check availability of required addresses and offsets (doing custom stuff here) @@ -103,10 +104,13 @@ int main () type = -1; // skip things we can't identify - if(!meminfo->resolveClassId (temp, type)) + if(!meminfo->resolveObjectToClassID (temp, type)) + continue; + string classname; + if(!meminfo->resolveClassIDToClassname (type, classname)) continue; - if(objecttypes[type] == "item_trapparts") + if(classname == "item_trapparts") { proc->read (temp + item_material_offset, sizeof (DFHack::t_matglossPair), (uint8_t *) &item_40d_material); diff --git a/tools/itemdesignator.cpp b/tools/itemdesignator.cpp index 59df46131..2d659a436 100644 --- a/tools/itemdesignator.cpp +++ b/tools/itemdesignator.cpp @@ -10,6 +10,7 @@ using namespace std; #include #include +#include struct matGlosses { @@ -20,9 +21,8 @@ struct matGlosses vector creatureMat; }; -string getMaterialType(DFHack::t_item item, const vector & buildingTypes,const matGlosses & mat) +string getMaterialType(DFHack::t_item item, const string & itemtype,const matGlosses & mat) { - string itemtype = buildingTypes[item.type]; // plant thread seeds if(itemtype == "item_plant" || itemtype == "item_thread" || itemtype == "item_seeds" || itemtype == "item_leaves" ) { @@ -128,13 +128,13 @@ string getMaterialType(DFHack::t_item item, const vector & buildingTypes } return "Invalid"; } -void printItem(DFHack::t_item item, const vector & buildingTypes,const matGlosses & mat) +void printItem(DFHack::t_item item, const string & typeString,const matGlosses & mat) { cout << dec << "Item at x:" << item.x << " y:" << item.y << " z:" << item.z << endl; - cout << "Type: " << (int) item.type << " " << buildingTypes[item.type] << " Address: " << hex << item.origin << endl; + cout << "Type: " << (int) item.type << " " << typeString << " Address: " << hex << item.origin << endl; cout << "Material: "; - string itemType = getMaterialType(item,buildingTypes,mat); + string itemType = getMaterialType(item,typeString,mat); cout << itemType << endl; } int main () @@ -150,6 +150,7 @@ int main () cerr << "DF not found" << endl; return 1; } + DFHack::memory_info *mem = DF.getMemoryInfo(); DF.Suspend(); DF.InitViewAndCursor(); matGlosses mat; @@ -159,8 +160,8 @@ int main () DF.ReadMetalMatgloss(mat.metalMat); DF.ReadCreatureMatgloss(mat.creatureMat); - vector objecttypes; - DF.getClassIDMapping(objecttypes); +// vector objecttypes; +// DF.getClassIDMapping(objecttypes); uint32_t numItems; DF.InitReadItems(numItems); map< string, map > > count; @@ -170,24 +171,26 @@ int main () { DFHack::t_item temp; DF.ReadItem(i,temp); - if(temp.type != -1) + if(temp.type != -1) // this should be the case pretty much always { - string material = getMaterialType(temp,objecttypes,mat); + string typestr; + mem->resolveClassIDToClassname(temp.type,typestr); + string material = getMaterialType(temp,typestr,mat); if (material != "Invalid") { - count[objecttypes[temp.type]][material].push_back(i); + count[typestr][material].push_back(i); } else { - if(bad_mat_items.count(objecttypes[temp.type])) + if(bad_mat_items.count(typestr)) { - int tmp = bad_mat_items[objecttypes[temp.type]]; + int tmp = bad_mat_items[typestr]; tmp ++; - bad_mat_items[objecttypes[temp.type]] = tmp; + bad_mat_items[typestr] = tmp; } else { - bad_mat_items[objecttypes[temp.type]] = 1; + bad_mat_items[typestr] = 1; } } } @@ -284,7 +287,7 @@ int main () DF.WriteRaw(temp.origin+12,sizeof(uint32_t),(uint8_t *)&temp.flags.whole); } - DF.FinishReadBuildings(); + DF.FinishReadItems(); DF.Detach(); #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl;