Major memory_info rework.

All <class> tags and vtable="" attributes in Memory.xml are now obsolete.
<multiclass> 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.
develop
Petr Mrázek 2010-02-25 13:41:57 +01:00
parent b60ef9f70f
commit 726519e2ca
14 changed files with 367 additions and 234 deletions

@ -10,6 +10,7 @@ using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
#include <DFMemInfo.h>
/*
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 <string> 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);

@ -10,6 +10,7 @@ using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
#include <DFMemInfo.h>
struct matGlosses
{
@ -20,60 +21,124 @@ struct matGlosses
vector<DFHack::t_matgloss> creatureMat;
};
string getMaterialType(DFHack::t_item item, const vector<string> & 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));
case DFHack::Mat_Wood:
return mat.woodMat[item.material.index].id;
break;
case 1:
return(string(mat.stoneMat[item.material.index].id));
case DFHack::Mat_Stone:
return mat.stoneMat[item.material.index].id;
break;
case 2:
return(string(mat.metalMat[item.material.index].id));
case DFHack::Mat_Metal:
return mat.metalMat[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));
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<string> & 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 <string> objecttypes;
DF.getClassIDMapping(objecttypes);
// vector <string> 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();
}

@ -23,7 +23,6 @@ void print_bits ( T val, std::ostream& out )
val >>= 1;
}
}
vector <string> objecttypes;
map<string, vector<string> > names;
uint32_t numCreatures;
vector<DFHack::t_matgloss> 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();

@ -316,9 +316,6 @@ main(int argc, char *argv[])
finish(0);
}
vector <string> classes;
p->getDescriptor()->getClassIDMapping(classes);
// get region geology
if(!DF.ReadGeology( layerassign ))
{

@ -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 <string>& objecttypes)
{
if(isAttached())
@ -1435,7 +1439,7 @@ bool API::getClassIDMapping (vector <string>& 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)
{

@ -226,9 +226,6 @@ namespace DFHack
bool ReadItem(const uint32_t &index, t_item & item);
void FinishReadItems();
// wrapper for meminfo method of the same name
bool getClassIDMapping (vector <string>& objecttypes);
memory_info *getMemoryInfo();
Process * getProcess();
DFWindow * getWindow();

@ -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<string> > traits;
map <uint32_t, string> labors;
vector<t_class> classes;
vector<vector<t_type> > classsubtypes;
// storage for class and multiclass
vector<t_class *> classes;
//vector<vector<t_type> > classsubtypes;
// cache for faster name lookup, indexed by classID
vector<string> 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; i<d->classes.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;
}
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;
// 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; i<d->classes.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;
}
}
// 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++;
return cls;
vector<t_type> thistypes;
d->classsubtypes.push_back(thistypes);
//cout << "multiclass " << name << ", assign " << cls.assign << ", vtable " << cls.vtable << endl;
return d->classsubtypes.size() - 1;
}
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 <t_type>& vec = d->classsubtypes[multi_index];
vector <t_type *>& vec = parent->subs;
for (uint32_t i=0; i<vec.size(); i++)
{
if(vec[i].classname == name)
if(vec[i]->classname == 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 <t_type>& vec = d->classsubtypes[d->classes[i].multi_index];
uint32_t type = g_pProcess->readWord(address + d->classes[i].type_offset);
vector <t_type*>& 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<string> & 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 <t_type>& 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<string> * 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<t_class>::iterator iter;
vector<t_class *>::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;
}
*/

@ -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<t_type *> 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<string> & 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<string> * getClassIDMapping();
};
}
#endif // MEMINFO_H_INCLUDED

@ -25,6 +25,16 @@ distribution.
#include "DFCommonInternal.h"
using namespace DFHack;
MemInfoManager::~MemInfoManager()
{
// for each in std::vector<memory_info*> 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);
}
}
}

@ -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;};

@ -117,7 +117,9 @@ DFWindow::DFWindow (Process * p)
// dtor
DFWindow::~DFWindow ()
{}
{
delete d;
}
Window DFWindow::Private::EnumerateWindows (Display *display, Window rootWindow, const char *searchString)
{

@ -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)

@ -72,9 +72,10 @@ int main ()
/*
* Get the object name/ID mapping
*/
/*
vector <string> 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);

@ -10,6 +10,7 @@ using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
#include <DFMemInfo.h>
struct matGlosses
{
@ -20,9 +21,8 @@ struct matGlosses
vector<DFHack::t_matgloss> creatureMat;
};
string getMaterialType(DFHack::t_item item, const vector<string> & 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<string> & buildingTypes
}
return "Invalid";
}
void printItem(DFHack::t_item item, const vector<string> & 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 <string> objecttypes;
DF.getClassIDMapping(objecttypes);
// vector <string> objecttypes;
// DF.getClassIDMapping(objecttypes);
uint32_t numItems;
DF.InitReadItems(numItems);
map< string, map<string,vector<uint32_t> > > 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;