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;