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 <DFTypes.h>
#include <DFHackAPI.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 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 groups of four bytes, 4 per line
@ -135,12 +136,7 @@ int main (int argc,const char* argv[])
cerr << "DF not found" << endl; cerr << "DF not found" << endl;
return 1; return 1;
} }
DFHack::memory_info * mem = DF.getMemoryInfo();
/*
* Get the object name/ID mapping
*/
vector <string> objecttypes;
DF.getClassIDMapping (objecttypes);
uint32_t numBuildings; uint32_t numBuildings;
if(DF.InitReadBuildings(numBuildings)) if(DF.InitReadBuildings(numBuildings))
@ -152,7 +148,9 @@ int main (int argc,const char* argv[])
DF.ReadBuilding(i, temp); DF.ReadBuilding(i, temp);
if(temp.type != 0xFFFFFFFF) // check if type isn't invalid 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; //cout << buildingtypes[temp.type] << " 0x" << hex << temp.origin << endl;
//hexdump(DF, temp.origin, 16); //hexdump(DF, temp.origin, 16);

@ -10,6 +10,7 @@ using namespace std;
#include <DFTypes.h> #include <DFTypes.h>
#include <DFHackAPI.h> #include <DFHackAPI.h>
#include <DFMemInfo.h>
struct matGlosses struct matGlosses
{ {
@ -20,60 +21,124 @@ struct matGlosses
vector<DFHack::t_matgloss> creatureMat; 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)
if(item.type == 85 || item.type == 113 || item.type == 117) // item_plant or item_thread or item_seeds {
// 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 // item_skin_raw item_bones item_skull item_fish_raw item_pet item_skin_tanned item_shell
return(string(mat.woodMat[item.material.type].id)); 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 else if(itemtype == "item_wood")
return(string(mat.metalMat[item.material.index].id)); {
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 else if(itemtype == "item_bar")
return(string("")); {
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) switch (item.material.type)
{ {
case 0: case DFHack::Mat_Wood:
return(string(mat.woodMat[item.material.index].id)); return mat.woodMat[item.material.index].id;
break;
case 1:
return(string(mat.stoneMat[item.material.index].id));
break; break;
case 2: case DFHack::Mat_Stone:
return(string(mat.metalMat[item.material.index].id)); return mat.stoneMat[item.material.index].id;
break; 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 case DFHack::Mat_Metal:
return(string(mat.plantMat[item.material.index].id)); return mat.metalMat[item.material.index].id;
break; break;
case 3: //case DFHack::Mat_Plant:
case 9: case DFHack::Mat_PlantCloth:
case 10: //return mat.plantMat[item.material.index].id;
case 11: return string(mat.plantMat[item.material.index].id) + " plant";
case 121:
return(string(mat.creatureMat[item.material.index].id));
break; 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: default:
//DF.setCursorCoords(item.x,item.y,item.z); cout << "unknown material hit: " << item.material.type << " " << item.material.index << " " << itemtype << endl;
return(string("")); 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 << 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: "; cout << "Material: ";
string itemType = getMaterialType(item,buildingTypes,mat); string itemType = getMaterialType(item,typeString,mat);
cout << itemType << endl; cout << itemType << endl;
} }
int main () int main ()
{ {
@ -84,7 +149,7 @@ int main ()
cerr << "DF not found" << endl; cerr << "DF not found" << endl;
return 1; return 1;
} }
DF.Suspend(); DFHack::memory_info * mem = DF.getMemoryInfo();
DF.InitViewAndCursor(); DF.InitViewAndCursor();
matGlosses mat; matGlosses mat;
DF.ReadPlantMatgloss(mat.plantMat); DF.ReadPlantMatgloss(mat.plantMat);
@ -93,8 +158,8 @@ int main ()
DF.ReadMetalMatgloss(mat.metalMat); DF.ReadMetalMatgloss(mat.metalMat);
DF.ReadCreatureMatgloss(mat.creatureMat); DF.ReadCreatureMatgloss(mat.creatureMat);
vector <string> objecttypes; // vector <string> objecttypes;
DF.getClassIDMapping(objecttypes); // DF.getClassIDMapping(objecttypes);
uint32_t numItems; uint32_t numItems;
DF.InitReadItems(numItems); DF.InitReadItems(numItems);
@ -133,14 +198,18 @@ int main ()
} }
else if(foundItems.size() == 1) else if(foundItems.size() == 1)
{ {
printItem(foundItems[0], objecttypes ,mat); string itemtype;
mem->resolveClassIDToClassname(foundItems[0].type,itemtype);
printItem(foundItems[0], itemtype ,mat);
} }
else else
{ {
cerr << "Please Select which item you want to display\n"; cerr << "Please Select which item you want to display\n";
string itemtype;
for(uint32_t j = 0; j < foundItems.size(); ++j) 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; uint32_t value;
string input2; string input2;
@ -157,7 +226,8 @@ int main ()
ss.str(input2); ss.str(input2);
ss >> value; ss >> value;
} }
printItem(foundItems[value], objecttypes ,mat); mem->resolveClassIDToClassname(foundItems[value].type,itemtype);
printItem(foundItems[value], itemtype ,mat);
} }
DF.FinishReadItems(); DF.FinishReadItems();
} }

@ -23,7 +23,6 @@ void print_bits ( T val, std::ostream& out )
val >>= 1; val >>= 1;
} }
} }
vector <string> objecttypes;
map<string, vector<string> > names; map<string, vector<string> > names;
uint32_t numCreatures; uint32_t numCreatures;
vector<DFHack::t_matgloss> creaturestypes; vector<DFHack::t_matgloss> creaturestypes;
@ -190,8 +189,10 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
DFHack::t_viewscreen current; DFHack::t_viewscreen current;
DF.Suspend(); DF.Suspend();
DF.ReadViewScreen(current); DF.ReadViewScreen(current);
string nowScreenState;
DF.getMemoryInfo()->resolveClassIDToClassname(current.type,nowScreenState);
int tryCount = 0; 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(); DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100); w->TypeSpecial(DFHack::WAIT,1,100);
@ -200,7 +201,7 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
tryCount++; tryCount++;
} }
if (tryCount >= 50) { if (tryCount >= 50) {
cerr << "Something went wrong, DF at " << objecttypes[current.type] << endl; cerr << "Something went wrong, DF at " << nowScreenState << endl;
return false; return false;
} }
DF.Resume(); DF.Resume();
@ -262,13 +263,16 @@ bool moveToBaseWindow(DFHack::API &DF)
DFHack::DFWindow * w = DF.getWindow(); DFHack::DFWindow * w = DF.getWindow();
DFHack::t_viewscreen current; DFHack::t_viewscreen current;
DF.ReadViewScreen(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 w->TypeSpecial(DFHack::F9); // cancel out of text input in names
// DF.TypeSpecial(DFHack::ENTER); // cancel out of text input in hotkeys // DF.TypeSpecial(DFHack::ENTER); // cancel out of text input in hotkeys
w->TypeSpecial(DFHack::SPACE); // should move up a level 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.ReadViewScreen(current);
DF.getMemoryInfo()->resolveClassIDToClassname(current.type,classname);
} }
if (DF.ReadMenuState() != 0) {// if menu state != 0 then there is a menu, so escape it if (DF.ReadMenuState() != 0) {// if menu state != 0 then there is a menu, so escape it
w->TypeSpecial(DFHack::F9); w->TypeSpecial(DFHack::F9);
@ -311,11 +315,6 @@ int main (void)
return 1; return 1;
} }
DF.Suspend(); DF.Suspend();
if (!DF.getClassIDMapping(objecttypes))
{
cerr << "Can't get type info" << endl;
return 1;
}
DFHack::memory_info * mem = DF.getMemoryInfo(); DFHack::memory_info * mem = DF.getMemoryInfo();

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

@ -166,8 +166,12 @@ bool API::InitMap()
d->veinvector = d->offset_descriptor->getOffset ("v_vein"); d->veinvector = d->offset_descriptor->getOffset ("v_vein");
d->veinsize = d->offset_descriptor->getHexValue ("v_vein_size"); d->veinsize = d->offset_descriptor->getHexValue ("v_vein_size");
d->vein_ice_vptr = d->offset_descriptor->getClassVPtr("block_square_event_frozen_liquid"); // these can fail and will be found when looking at the actual veins later
d->vein_mineral_vptr = d->offset_descriptor->getClassVPtr("block_square_event_mineral"); // 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 // get the map pointer
uint32_t x_array_loc = g_pProcess->readDWord (map_offset); 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 // transform
int32_t type = -1; int32_t type = -1;
d->offset_descriptor->resolveClassId (temp, type); d->offset_descriptor->resolveObjectToClassID (temp, type);
building.origin = temp; building.origin = temp;
building.vtable = bld_40d.vtable; building.vtable = bld_40d.vtable;
building.x1 = bld_40d.x1; building.x1 = bld_40d.x1;
@ -1425,7 +1429,7 @@ bool API::getWindowSize (int32_t &width, int32_t &height)
height = coords[1]; height = coords[1];
return true; return true;
} }
/*
bool API::getClassIDMapping (vector <string>& objecttypes) bool API::getClassIDMapping (vector <string>& objecttypes)
{ {
if(isAttached()) if(isAttached())
@ -1435,7 +1439,7 @@ bool API::getClassIDMapping (vector <string>& objecttypes)
} }
return false; return false;
} }
*/
memory_info *API::getMemoryInfo() memory_info *API::getMemoryInfo()
{ {
return d->offset_descriptor; return d->offset_descriptor;
@ -1482,7 +1486,7 @@ bool API::ReadItem (const uint32_t &index, t_item & item)
// transform // transform
int32_t type = -1; int32_t type = -1;
d->offset_descriptor->resolveClassId (temp, type); d->offset_descriptor->resolveObjectToClassID (temp, type);
item.origin = temp; item.origin = temp;
item.vtable = item_40d.vtable; item.vtable = item_40d.vtable;
item.x = item_40d.x; item.x = item_40d.x;
@ -1533,7 +1537,7 @@ bool API::ReadViewScreen (t_viewscreen &screen)
screenAddr = g_pProcess->readDWord (nextScreenPtr); screenAddr = g_pProcess->readDWord (nextScreenPtr);
nextScreenPtr = g_pProcess->readDWord (nextScreenPtr + 4); 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) bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
{ {

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

@ -44,28 +44,6 @@ using namespace boost::multi_index;
*/ */
using namespace DFHack; 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 * Private data
*/ */
@ -83,14 +61,19 @@ class memory_info::Private
vector< vector<string> > traits; vector< vector<string> > traits;
map <uint32_t, string> labors; map <uint32_t, string> labors;
vector<t_class> classes; // storage for class and multiclass
vector<vector<t_type> > classsubtypes; vector<t_class *> classes;
//vector<vector<t_type> > classsubtypes;
// cache for faster name lookup, indexed by classID
vector<string> classnames;
int32_t base; int32_t base;
uint32_t classindex; uint32_t classindex;
string version; string version;
OSType OS; OSType OS;
}; };
// normal constructor
memory_info::memory_info() memory_info::memory_info()
:d(new Private) :d(new Private)
{ {
@ -98,6 +81,37 @@ memory_info::memory_info()
d->classindex = 0; 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) void memory_info::setVersion(const char * v)
{ {
@ -156,29 +170,6 @@ memory_info::OSType memory_info::getOS() const
return d->OS; 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 uint32_t memory_info::getBase () const
{ {
return d->base; 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. // 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++) 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); if(vtable != 0)
return; d->classes[i]->vtable = vtable;
if(typeoffset != 0)
d->classes[i]->type_offset = typeoffset;
return d->classes[i];
} }
} }
t_class cls; t_class *cls = new t_class();
cls.assign = d->classindex; // get an unique ID and add ourselves to the index
cls.classname = name; cls->assign = d->classindex;
cls.is_multiclass = false; cls->classname = name;
cls.type_offset = 0; d->classnames.push_back(name);
d->classindex++;
cls.vtable = strtol(vtable, NULL, 16); // vtables no longer a requirement
d->classes.push_back(cls); cls->vtable = vtable;
//cout << "class " << name << ", assign " << cls.assign << ", vtable " << cls.vtable << endl;
} // multi class yes/no
cls->type_offset = typeoffset;
// 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;
}
}
//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->classes.push_back(cls);
d->classindex++; 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++) 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; return;
} }
} }
// new multiclass child // new multiclass child
t_type mcc; t_type *mcc = new t_type(d->classindex,strtol(type, NULL, 16),name);
mcc.assign = d->classindex; d->classnames.push_back(name);
mcc.classname = name;
mcc.type = strtol(type, NULL, 16);
vec.push_back(mcc); vec.push_back(mcc);
d->classindex++; 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); uint32_t vtable = g_pProcess->readDWord(address);
// FIXME: stupid search. we need a better container // FIXME: stupid search. we need a better container
for(uint32_t i = 0;i< d->classes.size();i++) 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 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]; vector <t_type*>& vec = d->classes[i]->subs;
uint32_t type = g_pProcess->readWord(address + d->classes[i].type_offset); 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); //printf ("class %d:%s offset 0x%x\n", i , classes[i].classname.c_str(), classes[i].type_offset);
// return typed building if successful // return typed building if successful
for (uint32_t k = 0; k < vec.size();k++) 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; //cout << " multi " << address + classes[i].type_offset << " " << vec[k].classname << endl;
classid = vec[k].assign; classid = vec[k]->assign;
return true; return true;
} }
} }
} }
// otherwise return the class we found // otherwise return the class we found
classid = d->classes[i].assign; classid = d->classes[i]->assign;
return true; return true;
} }
} }
// we failed to find anything that would match string classname = g_pProcess->readClassName(vtable);
return false; setClass(classname.c_str(),vtable);
return true;
} }
//ALERT: doesn't care about multiclasses //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. // FIXME: another stupid search.
for(uint32_t i = 0;i< d->classes.size();i++) for(uint32_t i = 0;i< d->classes.size();i++)
{ {
//if(classes[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 // we failed to find anything that would match
return 0; return false;
} }
// Flatten vtables into a index<->name mapping bool memory_info::resolveClassIDToClassname (const int32_t classID, string & classname)
void memory_info::getClassIDMapping(vector<string> & v_ClassID2ObjName)
{ {
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); classname = d->classnames[classID];
if(!d->classes[i].is_multiclass) return true;
{
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);
}
} }
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 // change all vtable entries by offset
void memory_info::RebaseVTable(int32_t 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++) 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 // Reset everything
/*
0xDEADC0DE
void memory_info::flush() void memory_info::flush()
{ {
d->base = 0; d->base = 0;
@ -639,8 +610,8 @@ void memory_info::flush()
d->strings.clear(); d->strings.clear();
d->hexvals.clear(); d->hexvals.clear();
d->classes.clear(); d->classes.clear();
d->classsubtypes.clear();
d->classindex = 0; d->classindex = 0;
d->version = ""; d->version = "";
d->OS = OS_BAD; d->OS = OS_BAD;
} }
*/

@ -34,6 +34,51 @@ distribution.
namespace DFHack 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 class DFHACK_EXPORT memory_info
{ {
@ -49,7 +94,7 @@ namespace DFHack
}; };
memory_info(); memory_info();
memory_info(const memory_info&); memory_info(const memory_info&);
~memory_info();
void RebaseAddresses(const int32_t new_base); void RebaseAddresses(const int32_t new_base);
void RebaseAll(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 setLabor(const string &, const string &);
void RebaseVTable(const int32_t offset); 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); t_class * setClass (const char * classname, uint32_t vptr = 0, uint32_t typeoffset = 0);
void setMultiClassChild (uint32_t multi_index, const char * name, const char * type); void setClassChild (t_class * parent, const char * classname, const char * type);
// ALERT: uses memory reading directly /*
bool resolveClassId(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)
void getClassIDMapping(vector<string> & v_ClassID2ObjName); * uses memory reading directly, needs suspend. input = address of the object
uint32_t getClassVPtr(string classname); * fails if it's unable to read from memory
*/
void flush(); 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 #endif // MEMINFO_H_INCLUDED

@ -25,6 +25,16 @@ distribution.
#include "DFCommonInternal.h" #include "DFCommonInternal.h"
using namespace DFHack; 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) void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info* mem)
{ {
TiXmlElement* pClassEntry; TiXmlElement* pClassEntry;
@ -43,17 +53,23 @@ void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info* mem)
string type = pClassEntry->Value(); string type = pClassEntry->Value();
const char *cstr_name = pClassEntry->Attribute("name"); const char *cstr_name = pClassEntry->Attribute("name");
const char *cstr_vtable = pClassEntry->Attribute("vtable"); 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 // it's a simple class
if(type== "class") if(type== "class")
{ {
mem->setClass(cstr_name, cstr_vtable); mem->setClass(cstr_name, vtable);
} }
// it's a multi-type class // it's a multi-type class
else if (type == "multiclass") else if (type == "multiclass")
{ {
// get offset of the type variable // get offset of the type variable
const char *cstr_typeoffset = pClassEntry->Attribute("typeoffset"); 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 // parse class sub-entries
pClassSubEntry = pClassEntry->FirstChildElement(); pClassSubEntry = pClassEntry->FirstChildElement();
for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement()) 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 // type is a value loaded from type offset
cstr_name = pClassSubEntry->Attribute("name"); cstr_name = pClassSubEntry->Attribute("name");
const char *cstr_value = pClassSubEntry->Attribute("type"); 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; friend class ProcessEnumerator;
public: public:
MemInfoManager(string path_to_xml); MemInfoManager(string path_to_xml);
~MemInfoManager();
// memory info entries loaded from a file // memory info entries loaded from a file
bool loadFile( string path_to_xml); bool loadFile( string path_to_xml);
bool isInErrorState() const {return error;}; bool isInErrorState() const {return error;};

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

@ -119,7 +119,9 @@ DFWindow::DFWindow (Process * p)
// dtor // dtor
DFWindow::~DFWindow () DFWindow::~DFWindow ()
{} {
delete d;
}
// TODO: also investigate possible problems with UIPI on Vista and 7 // TODO: also investigate possible problems with UIPI on Vista and 7
void DFWindow::TypeStr (const char *input, int delay, bool useShift) void DFWindow::TypeStr (const char *input, int delay, bool useShift)

@ -72,9 +72,10 @@ int main ()
/* /*
* Get the object name/ID mapping * Get the object name/ID mapping
*/ */
/*
vector <string> objecttypes; vector <string> objecttypes;
DF.getClassIDMapping (objecttypes); DF.getClassIDMapping (objecttypes);
*/
//FIXME: work on the 'supported features' system required //FIXME: work on the 'supported features' system required
/* /*
* Check availability of required addresses and offsets (doing custom stuff here) * Check availability of required addresses and offsets (doing custom stuff here)
@ -103,10 +104,13 @@ int main ()
type = -1; type = -1;
// skip things we can't identify // 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; 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); 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 <DFTypes.h>
#include <DFHackAPI.h> #include <DFHackAPI.h>
#include <DFMemInfo.h>
struct matGlosses struct matGlosses
{ {
@ -20,9 +21,8 @@ struct matGlosses
vector<DFHack::t_matgloss> creatureMat; 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 // plant thread seeds
if(itemtype == "item_plant" || itemtype == "item_thread" || itemtype == "item_seeds" || itemtype == "item_leaves" ) 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"; 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 << 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: "; cout << "Material: ";
string itemType = getMaterialType(item,buildingTypes,mat); string itemType = getMaterialType(item,typeString,mat);
cout << itemType << endl; cout << itemType << endl;
} }
int main () int main ()
@ -150,6 +150,7 @@ int main ()
cerr << "DF not found" << endl; cerr << "DF not found" << endl;
return 1; return 1;
} }
DFHack::memory_info *mem = DF.getMemoryInfo();
DF.Suspend(); DF.Suspend();
DF.InitViewAndCursor(); DF.InitViewAndCursor();
matGlosses mat; matGlosses mat;
@ -159,8 +160,8 @@ int main ()
DF.ReadMetalMatgloss(mat.metalMat); DF.ReadMetalMatgloss(mat.metalMat);
DF.ReadCreatureMatgloss(mat.creatureMat); DF.ReadCreatureMatgloss(mat.creatureMat);
vector <string> objecttypes; // vector <string> objecttypes;
DF.getClassIDMapping(objecttypes); // DF.getClassIDMapping(objecttypes);
uint32_t numItems; uint32_t numItems;
DF.InitReadItems(numItems); DF.InitReadItems(numItems);
map< string, map<string,vector<uint32_t> > > count; map< string, map<string,vector<uint32_t> > > count;
@ -170,24 +171,26 @@ int main ()
{ {
DFHack::t_item temp; DFHack::t_item temp;
DF.ReadItem(i,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") if (material != "Invalid")
{ {
count[objecttypes[temp.type]][material].push_back(i); count[typestr][material].push_back(i);
} }
else 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 ++; tmp ++;
bad_mat_items[objecttypes[temp.type]] = tmp; bad_mat_items[typestr] = tmp;
} }
else 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.WriteRaw(temp.origin+12,sizeof(uint32_t),(uint8_t *)&temp.flags.whole);
} }
DF.FinishReadBuildings(); DF.FinishReadItems();
DF.Detach(); DF.Detach();
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl; cout << "Done. Press any key to continue" << endl;