Merge branch 'master', remote branch 'peterix/master'
commit
e9a7026342
@ -1,6 +1,6 @@
|
||||
mkdir build-real
|
||||
cd build-real
|
||||
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release --trace > trace-stdout.txt 2> trace-stderr.txt
|
||||
mingw32-make 2> log.txt
|
||||
pause
|
||||
mkdir build-real
|
||||
cd build-real
|
||||
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release --trace > trace-stdout.txt 2> trace-stderr.txt
|
||||
mingw32-make 2> log.txt
|
||||
pause
|
||||
dir file.xxx
|
@ -1,4 +1,4 @@
|
||||
mkdir build-real
|
||||
cd build-real
|
||||
cmake ..\.. -G"Visual Studio 10"
|
||||
mkdir build-real
|
||||
cd build-real
|
||||
cmake ..\.. -G"Visual Studio 10"
|
||||
pause
|
File diff suppressed because it is too large
Load Diff
@ -1,778 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "Internal.h"
|
||||
#include "dfhack/DFMemInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
|
||||
//Inital amount of space in levels vector (since we usually know the number, efficent!)
|
||||
#define NUM_RESERVE_LVLS 20
|
||||
#define NUM_RESERVE_MOODS 6
|
||||
using namespace DFHack;
|
||||
|
||||
/*
|
||||
* Common data types
|
||||
*/
|
||||
namespace DFHack
|
||||
{
|
||||
struct t_type
|
||||
{
|
||||
t_type(uint32_t assign, uint32_t type, std::string classname)
|
||||
:classname(classname),assign(assign),type(type){};
|
||||
std::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(uint32_t 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(uint32_t i = 0; i < subs.size();i++)
|
||||
{
|
||||
delete subs[i];
|
||||
}
|
||||
subs.clear();
|
||||
}
|
||||
std::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
|
||||
std::vector<t_type *> subs;
|
||||
};
|
||||
}
|
||||
/*
|
||||
* Private data
|
||||
*/
|
||||
class memory_info::Private
|
||||
{
|
||||
public:
|
||||
map <string, uint32_t> addresses;
|
||||
map <string, int32_t> offsets;
|
||||
map <string, uint32_t> hexvals;
|
||||
map <string, string> strings;
|
||||
|
||||
vector<string> professions;
|
||||
vector<string> jobs;
|
||||
vector<string> skills;
|
||||
vector<DFHack::t_level> levels;
|
||||
vector< vector<string> > traits;
|
||||
vector<string> moods;
|
||||
map <uint32_t, string> labors;
|
||||
|
||||
// storage for class and multiclass
|
||||
vector<t_class *> classes;
|
||||
|
||||
// cache for faster name lookup, indexed by classID
|
||||
vector<string> classnames;
|
||||
// map between vptr and class id, needs further type id lookup for multi-classes, not inherited
|
||||
map<uint32_t, t_class *> classIDs;
|
||||
|
||||
// index for the next added class
|
||||
uint32_t classindex;
|
||||
|
||||
int32_t base;
|
||||
Process * p; // the process this belongs to
|
||||
|
||||
string version;
|
||||
OSType OS;
|
||||
};
|
||||
|
||||
// normal constructor
|
||||
memory_info::memory_info()
|
||||
:d(new Private)
|
||||
{
|
||||
d->base = 0;
|
||||
d->p = 0;
|
||||
d->classindex = 0;
|
||||
d->levels.reserve(NUM_RESERVE_LVLS);
|
||||
d->moods.reserve(NUM_RESERVE_MOODS);
|
||||
}
|
||||
|
||||
// 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;
|
||||
for(uint32_t i = 0; i < old.d->classes.size(); i++)
|
||||
{
|
||||
t_class * copy = new t_class(*old.d->classes[i]);
|
||||
d->classes.push_back(copy);
|
||||
}
|
||||
d->classnames = old.d->classnames;
|
||||
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;
|
||||
d->levels = old.d->levels;
|
||||
d->moods = old.d->moods;
|
||||
}
|
||||
void memory_info::setParentProcess(Process * _p)
|
||||
{
|
||||
d->p = _p;
|
||||
}
|
||||
|
||||
// destructor
|
||||
memory_info::~memory_info()
|
||||
{
|
||||
// delete the vtables
|
||||
for(uint32_t i = 0; i < d->classes.size();i++)
|
||||
{
|
||||
delete d->classes[i];
|
||||
}
|
||||
// delete our data
|
||||
delete d;
|
||||
}
|
||||
|
||||
void memory_info::setVersion(const char * v)
|
||||
{
|
||||
d->version = v;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setVersion(const string &v)
|
||||
{
|
||||
d->version = v;
|
||||
}
|
||||
|
||||
|
||||
string memory_info::getVersion()
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setOS(const char *os)
|
||||
{
|
||||
string oss = os;
|
||||
if(oss == "windows")
|
||||
d->OS = OS_WINDOWS;
|
||||
else if(oss == "linux")
|
||||
d->OS = OS_LINUX;
|
||||
else
|
||||
d->OS = OS_BAD;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setOS(const string &os)
|
||||
{
|
||||
if(os == "windows")
|
||||
d->OS = OS_WINDOWS;
|
||||
else if(os == "linux")
|
||||
d->OS = OS_LINUX;
|
||||
else
|
||||
d->OS = OS_BAD;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setOS(OSType os)
|
||||
{
|
||||
if(os >= OS_WINDOWS && os < OS_BAD)
|
||||
{
|
||||
d->OS = os;
|
||||
return;
|
||||
}
|
||||
d->OS = OS_BAD;
|
||||
}
|
||||
|
||||
|
||||
memory_info::OSType memory_info::getOS() const
|
||||
{
|
||||
return d->OS;
|
||||
}
|
||||
|
||||
uint32_t memory_info::getBase () const
|
||||
{
|
||||
return d->base;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setBase (const string &s)
|
||||
{
|
||||
d->base = strtol(s.c_str(), NULL, 16);
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setBase (const uint32_t b)
|
||||
{
|
||||
d->base = b;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setOffset (const string & key, const string & value)
|
||||
{
|
||||
int32_t offset = strtol(value.c_str(), NULL, 16);
|
||||
d->offsets[key] = offset;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setAddress (const string & key, const string & value)
|
||||
{
|
||||
uint32_t address = strtol(value.c_str(), NULL, 16);
|
||||
d->addresses[key] = address;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setHexValue (const string & key, const string & value)
|
||||
{
|
||||
uint32_t hexval = strtol(value.c_str(), NULL, 16);
|
||||
d->hexvals[key] = hexval;
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setString (const string & key, const string & value)
|
||||
{
|
||||
d->strings[key] = value;
|
||||
}
|
||||
|
||||
void memory_info::setLabor(const string & key, const string & value)
|
||||
{
|
||||
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
|
||||
d->labors[keyInt] = value;
|
||||
}
|
||||
|
||||
void memory_info::setProfession (const string & key, const string & value)
|
||||
{
|
||||
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
|
||||
if(d->professions.size() <= keyInt)
|
||||
{
|
||||
d->professions.resize(keyInt+1,"");
|
||||
}
|
||||
d->professions[keyInt] = value;
|
||||
}
|
||||
|
||||
void memory_info::setJob (const string & key, const string & value)
|
||||
{
|
||||
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
|
||||
if(d->jobs.size() <= keyInt)
|
||||
{
|
||||
d->jobs.resize(keyInt+1);
|
||||
}
|
||||
d->jobs[keyInt] = value;
|
||||
}
|
||||
|
||||
void memory_info::setSkill (const string & key, const string & value)
|
||||
{
|
||||
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
|
||||
if(d->skills.size() <= keyInt){
|
||||
d->skills.resize(keyInt+1);
|
||||
}
|
||||
d->skills[keyInt] = value;
|
||||
}
|
||||
|
||||
void memory_info::setLevel(const std::string &nLevel,
|
||||
const std::string &nName,
|
||||
const std::string &nXp)
|
||||
{
|
||||
uint32_t keyInt = strtol(nLevel.c_str(), NULL, 10);
|
||||
|
||||
if(d->levels.size() <= keyInt)
|
||||
d->levels.resize(keyInt+1);
|
||||
|
||||
d->levels[keyInt].level = keyInt;
|
||||
d->levels[keyInt].name = nName;
|
||||
d->levels[keyInt].xpNxtLvl = strtol(nXp.c_str(), NULL, 10);
|
||||
}
|
||||
|
||||
void memory_info::setMood(const std::string &id, const std::string &mood)
|
||||
{
|
||||
uint32_t keyInt = strtol(id.c_str(), NULL, 10);
|
||||
|
||||
if(d->moods.size() <= keyInt)
|
||||
d->moods.resize(keyInt+1);
|
||||
|
||||
d->moods[keyInt] = mood;
|
||||
}
|
||||
|
||||
void memory_info::setTrait(const string & key,
|
||||
const string & value,
|
||||
const string & zero,
|
||||
const string & one,
|
||||
const string & two,
|
||||
const string & three,
|
||||
const string & four,
|
||||
const string & five)
|
||||
{
|
||||
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
|
||||
if(d->traits.size() <= keyInt)
|
||||
{
|
||||
d->traits.resize(keyInt+1);
|
||||
}
|
||||
d->traits[keyInt].push_back(zero);
|
||||
d->traits[keyInt].push_back(one);
|
||||
d->traits[keyInt].push_back(two);
|
||||
d->traits[keyInt].push_back(three);
|
||||
d->traits[keyInt].push_back(four);
|
||||
d->traits[keyInt].push_back(five);
|
||||
d->traits[keyInt].push_back(value);
|
||||
}
|
||||
|
||||
// FIXME: next three methods should use some kind of custom container so it doesn't have to search so much.
|
||||
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(vtable != 0)
|
||||
d->classes[i]->vtable = vtable;
|
||||
if(typeoffset != 0)
|
||||
d->classes[i]->type_offset = typeoffset;
|
||||
return d->classes[i];
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
d->classes.push_back(cls);
|
||||
d->classindex++;
|
||||
return cls;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void memory_info::setClassChild (t_class * parent, const char * name, const char * type)
|
||||
{
|
||||
vector <t_type *>& vec = parent->subs;
|
||||
for (uint32_t i=0; i<vec.size(); i++)
|
||||
{
|
||||
if(vec[i]->classname == name)
|
||||
{
|
||||
vec[i]->type = strtol(type, NULL, 16);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// new multiclass child
|
||||
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;
|
||||
}
|
||||
|
||||
// FIXME: stupid. we need a better container
|
||||
bool memory_info::resolveObjectToClassID(const uint32_t address, int32_t & classid)
|
||||
{
|
||||
uint32_t vtable = d->p->readDWord(address);
|
||||
// try to find the vtable in our cache
|
||||
map<uint32_t, t_class *>::iterator it;
|
||||
it = d->classIDs.find(vtable);
|
||||
t_class * cl;
|
||||
|
||||
// class found in cache?
|
||||
if(it != d->classIDs.end())
|
||||
{
|
||||
cl = (*it).second;
|
||||
}
|
||||
else// couldn't find?
|
||||
{
|
||||
// we set up the class for the first time
|
||||
string classname = d->p->readClassName(vtable);
|
||||
d->classIDs[vtable] = cl = setClass(classname.c_str(),vtable);
|
||||
}
|
||||
// and isn't a multi-class
|
||||
if(!cl->type_offset)
|
||||
{
|
||||
// return
|
||||
classid = cl->assign;
|
||||
return true;
|
||||
}
|
||||
// and is a multiclass
|
||||
else
|
||||
{
|
||||
// find the type
|
||||
vector <t_type*>& vec = cl->subs;
|
||||
uint32_t type = d->p->readWord(address + cl->type_offset);
|
||||
// return typed building if successful
|
||||
//FIXME: the vector should map directly to the type IDs here, so we don't have to mess with O(n) search
|
||||
for (uint32_t k = 0; k < vec.size();k++)
|
||||
{
|
||||
if(vec[k]->type == type)
|
||||
{
|
||||
//cout << " multi " << address + classes[i].type_offset << " " << vec[k].classname << endl;
|
||||
classid = vec[k]->assign;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// couldn't find the type... now what do we do here? throw?
|
||||
// this is a case where it might be a good idea, because it uncovers some deeper problems
|
||||
// we return the parent class instead, it doesn't change the API semantics and sort-of makes sense
|
||||
classid = cl->assign;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//ALERT: doesn't care about multiclasses
|
||||
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
|
||||
{
|
||||
vptr = d->classes[i]->vtable;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// we failed to find anything that would match
|
||||
return false;
|
||||
}
|
||||
|
||||
bool memory_info::resolveClassnameToClassID (const string classname, int32_t & classID)
|
||||
{
|
||||
// FIXME: another stupid search.
|
||||
classID = -1;
|
||||
for(uint32_t i = 0;i< d->classnames.size();i++)
|
||||
{
|
||||
if(d->classnames[i] == classname)
|
||||
{
|
||||
classID = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// we failed to find anything that would match
|
||||
return false;
|
||||
}
|
||||
|
||||
bool memory_info::resolveClassIDToClassname (const int32_t classID, string & classname)
|
||||
{
|
||||
if (classID >=0 && (uint32_t)classID < d->classnames.size())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// change base of all addresses
|
||||
void memory_info::RebaseAddresses(const int32_t new_base)
|
||||
{
|
||||
map<string, uint32_t>::iterator iter;
|
||||
int32_t rebase = - (int32_t)d->base + new_base;
|
||||
for(iter = d->addresses.begin(); iter != d->addresses.end(); iter++)
|
||||
{
|
||||
d->addresses[iter->first] = iter->second + rebase;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// change base of all addresses *and* vtable entries
|
||||
void memory_info::RebaseAll(int32_t new_base)
|
||||
{
|
||||
map<string, uint32_t>::iterator iter;
|
||||
int32_t rebase = - (int32_t)d->base + new_base;
|
||||
for(iter = d->addresses.begin(); iter != d->addresses.end(); iter++)
|
||||
{
|
||||
d->addresses[iter->first] = iter->second + rebase;
|
||||
}
|
||||
RebaseVTable(rebase);
|
||||
}
|
||||
|
||||
|
||||
// change all vtable entries by offset
|
||||
void memory_info::RebaseVTable(int32_t offset)
|
||||
{
|
||||
vector<t_class *>::iterator iter;
|
||||
for(iter = d->classes.begin(); iter != d->classes.end(); iter++)
|
||||
{
|
||||
(*iter)->vtable += offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Get named address
|
||||
uint32_t memory_info::getAddress (const char *key)
|
||||
{
|
||||
map <string, uint32_t>::iterator iter = d->addresses.find(key);
|
||||
|
||||
if(iter != d->addresses.end())
|
||||
{
|
||||
return (*iter).second;
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("address", key);
|
||||
}
|
||||
|
||||
|
||||
// Get named offset
|
||||
int32_t memory_info::getOffset (const char *key)
|
||||
{
|
||||
map <string, int32_t>::iterator iter = d->offsets.find(key);
|
||||
if(iter != d->offsets.end())
|
||||
{
|
||||
return (*iter).second;
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("offset", key);
|
||||
}
|
||||
|
||||
// Get named numerical value
|
||||
uint32_t memory_info::getHexValue (const char *key)
|
||||
{
|
||||
map <string, uint32_t>::iterator iter = d->hexvals.find(key);
|
||||
if(iter != d->hexvals.end())
|
||||
{
|
||||
return (*iter).second;
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("hexvalue", key);
|
||||
}
|
||||
|
||||
|
||||
// Get named address
|
||||
uint32_t memory_info::getAddress (const string &key)
|
||||
{
|
||||
map <string, uint32_t>::iterator iter = d->addresses.find(key);
|
||||
|
||||
if(iter != d->addresses.end())
|
||||
{
|
||||
return (*iter).second;
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("address", key.c_str());
|
||||
}
|
||||
|
||||
|
||||
// Get named offset
|
||||
int32_t memory_info::getOffset (const string &key)
|
||||
{
|
||||
map <string, int32_t>::iterator iter = d->offsets.find(key);
|
||||
if(iter != d->offsets.end())
|
||||
{
|
||||
return (*iter).second;
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("offset", key.c_str());
|
||||
}
|
||||
|
||||
// Get named numerical value
|
||||
uint32_t memory_info::getHexValue (const string &key)
|
||||
{
|
||||
map <string, uint32_t>::iterator iter = d->hexvals.find(key);
|
||||
if(iter != d->hexvals.end())
|
||||
{
|
||||
return (*iter).second;
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("hexvalue", key.c_str());
|
||||
}
|
||||
|
||||
// Get named string
|
||||
std::string memory_info::getString (const string &key)
|
||||
{
|
||||
map <string, string>::iterator iter = d->strings.find(key);
|
||||
if(iter != d->strings.end())
|
||||
{
|
||||
return (*iter).second;
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("string", key.c_str());
|
||||
}
|
||||
|
||||
// Get Profession
|
||||
string memory_info::getProfession (const uint32_t key) const
|
||||
{
|
||||
if(d->professions.size() > key)
|
||||
{
|
||||
return d->professions[key];
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("profession", key);
|
||||
}
|
||||
|
||||
// Get Job
|
||||
string memory_info::getJob (const uint32_t key) const
|
||||
{
|
||||
if(d->jobs.size() > key)
|
||||
|
||||
{
|
||||
return d->jobs[key];
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("job", key);
|
||||
}
|
||||
|
||||
string memory_info::getSkill (const uint32_t key) const
|
||||
{
|
||||
if(d->skills.size() > key)
|
||||
{
|
||||
return d->skills[key];
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("skill", key);
|
||||
}
|
||||
|
||||
DFHack::t_level memory_info::getLevelInfo(const uint32_t level) const
|
||||
{
|
||||
if(d->levels.size() > level)
|
||||
{
|
||||
return d->levels[level];
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("Level", level);
|
||||
}
|
||||
|
||||
// FIXME: ugly hack that needs to die
|
||||
int absolute (int number)
|
||||
{
|
||||
if (number < 0)
|
||||
return -number;
|
||||
return number;
|
||||
}
|
||||
|
||||
string memory_info::getTrait (const uint32_t traitIdx, const uint32_t traitValue) const
|
||||
{
|
||||
if(d->traits.size() > traitIdx)
|
||||
{
|
||||
int diff = absolute(traitValue-50);
|
||||
if(diff < 10)
|
||||
{
|
||||
return string("");
|
||||
}
|
||||
if (traitValue >= 91)
|
||||
return d->traits[traitIdx][5];
|
||||
else if (traitValue >= 76)
|
||||
return d->traits[traitIdx][4];
|
||||
else if (traitValue >= 61)
|
||||
return d->traits[traitIdx][3];
|
||||
else if (traitValue >= 25)
|
||||
return d->traits[traitIdx][2];
|
||||
else if (traitValue >= 10)
|
||||
return d->traits[traitIdx][1];
|
||||
else
|
||||
return d->traits[traitIdx][0];
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("trait", traitIdx);
|
||||
}
|
||||
|
||||
string memory_info::getTraitName(const uint32_t traitIdx) const
|
||||
{
|
||||
if(d->traits.size() > traitIdx)
|
||||
{
|
||||
return d->traits[traitIdx][d->traits[traitIdx].size()-1];
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("traitname", traitIdx);
|
||||
}
|
||||
|
||||
std::vector< std::vector<std::string> > const& memory_info::getAllTraits()
|
||||
{
|
||||
return d->traits;
|
||||
}
|
||||
|
||||
string memory_info::getLabor (const uint32_t laborIdx)
|
||||
{
|
||||
if(d->labors.count(laborIdx))
|
||||
{
|
||||
return d->labors[laborIdx];
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("labor", laborIdx);
|
||||
}
|
||||
|
||||
std::string memory_info::getMood(const uint32_t moodID)
|
||||
{
|
||||
if(d->moods.size() > moodID)
|
||||
{
|
||||
return d->moods[moodID];
|
||||
}
|
||||
throw Error::MissingMemoryDefinition("Mood", moodID);
|
||||
}
|
||||
|
||||
std::string memory_info::PrintOffsets()
|
||||
{
|
||||
ostringstream ss;
|
||||
ss << "<Version name=\"" << getVersion() << "\">" << endl;
|
||||
switch (getOS())
|
||||
{
|
||||
case OS_LINUX:
|
||||
ss << "<MD5 value=\"" << getString("md5") << "\" />" << endl;
|
||||
break;
|
||||
case OS_WINDOWS:
|
||||
ss << "<PETimeStamp value=\"" << hex << "0x" << getHexValue("pe_timestamp") << "\" />" << endl;
|
||||
ss << "<MD5 value=\"" << getString("md5") << "\" />" << endl;
|
||||
break;
|
||||
default:
|
||||
ss << " UNKNOWN" << endl;
|
||||
}
|
||||
ss << "<Offsets>" << endl;
|
||||
map<string,uint32_t>::const_iterator iter;
|
||||
for(iter = d->addresses.begin(); iter != d->addresses.end(); iter++)
|
||||
{
|
||||
ss << " <Address name=\"" << (*iter).first << "\" value=\"" << hex << "0x" << (*iter).second << "\" />" << endl;
|
||||
}
|
||||
map<string,int32_t>::const_iterator iter2;
|
||||
for(iter2 = d->offsets.begin(); iter2 != d->offsets.end(); iter2++)
|
||||
{
|
||||
ss << " <Offset name=\"" << (*iter2).first << "\" value=\"" << hex << "0x" << (*iter2).second <<"\" />" << endl;
|
||||
}
|
||||
for(iter = d->hexvals.begin(); iter != d->hexvals.end(); iter++)
|
||||
{
|
||||
ss << " <HexValue name=\"" << (*iter).first << "\" value=\"" << hex << "0x" << (*iter).second <<"\" />" << endl;
|
||||
}
|
||||
map<string,string>::const_iterator iter3;
|
||||
for(iter3 = d->strings.begin(); iter3 != d->strings.end(); iter3++)
|
||||
{
|
||||
ss << " <String name=\"" << (*iter3).first << "\" value=\"" << (*iter3).second <<"\" />" << endl;
|
||||
}
|
||||
ss << "</Offsets>" << endl;
|
||||
ss << "</Version>" << endl;
|
||||
return ss.str();
|
||||
}
|
@ -1,297 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "Internal.h"
|
||||
#include "DFMemInfoManager.h"
|
||||
|
||||
#include "dfhack/DFMemInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
MemInfoManager::~MemInfoManager()
|
||||
{
|
||||
// for each in std::vector<memory_info*> meminfo;, delete
|
||||
for(uint32_t i = 0; i < meminfo.size();i++)
|
||||
{
|
||||
delete meminfo[i];
|
||||
}
|
||||
meminfo.clear();
|
||||
}
|
||||
|
||||
void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info* mem)
|
||||
{
|
||||
TiXmlElement* pClassEntry;
|
||||
TiXmlElement* pClassSubEntry;
|
||||
// check for rebase, do rebase if check positive
|
||||
const char * rebase = vtable->Attribute("rebase");
|
||||
if(rebase)
|
||||
{
|
||||
int32_t rebase_offset = strtol(rebase, NULL, 16);
|
||||
mem->RebaseVTable(rebase_offset);
|
||||
}
|
||||
// parse vtable entries
|
||||
pClassEntry = vtable->FirstChildElement();
|
||||
for(;pClassEntry;pClassEntry=pClassEntry->NextSiblingElement())
|
||||
{
|
||||
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, vtable);
|
||||
}
|
||||
// it's a multi-type class
|
||||
else if (type == "multiclass")
|
||||
{
|
||||
// get offset of the type variable
|
||||
const char *cstr_typeoffset = pClassEntry->Attribute("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())
|
||||
{
|
||||
type = pClassSubEntry->Value();
|
||||
if(type== "class")
|
||||
{
|
||||
// type is a value loaded from type offset
|
||||
cstr_name = pClassSubEntry->Attribute("name");
|
||||
const char *cstr_value = pClassSubEntry->Attribute("type");
|
||||
mem->setClassChild(mclass,cstr_name,cstr_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MemInfoManager::ParseEntry (TiXmlElement* entry, memory_info* mem, map <string ,TiXmlElement *>& knownEntries)
|
||||
{
|
||||
TiXmlElement* pMemEntry;
|
||||
const char *cstr_version = entry->Attribute("version");
|
||||
const char *cstr_os = entry->Attribute("os");
|
||||
const char *cstr_base = entry->Attribute("base");
|
||||
const char *cstr_rebase = entry->Attribute("rebase");
|
||||
if(cstr_base)
|
||||
{
|
||||
string base = cstr_base;
|
||||
ParseEntry(knownEntries[base], mem, knownEntries);
|
||||
}
|
||||
|
||||
if (!cstr_version)
|
||||
throw Error::MemoryXmlBadAttribute("version");
|
||||
if (!cstr_os)
|
||||
throw Error::MemoryXmlBadAttribute("os");
|
||||
|
||||
string os = cstr_os;
|
||||
mem->setVersion(cstr_version);
|
||||
mem->setOS(cstr_os);
|
||||
|
||||
// offset inherited addresses by 'rebase'.
|
||||
int32_t rebase = 0;
|
||||
if(cstr_rebase)
|
||||
{
|
||||
rebase = mem->getBase() + strtol(cstr_rebase, NULL, 16);
|
||||
mem->RebaseAddresses(rebase);
|
||||
}
|
||||
|
||||
//set base to default, we're overwriting this because the previous rebase could cause havoc on Vista/7
|
||||
if(os == "windows")
|
||||
{
|
||||
// set default image base. this is fixed for base relocation later
|
||||
mem->setBase(0x400000);
|
||||
}
|
||||
else if(os == "linux")
|
||||
{
|
||||
// this is wrong... I'm not going to do base image relocation on linux though.
|
||||
// users are free to use a sane kernel that doesn't do this kind of **** by default
|
||||
mem->setBase(0x0);
|
||||
}
|
||||
else if ( os == "all")
|
||||
{
|
||||
// yay
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error::MemoryXmlBadAttribute("os");
|
||||
}
|
||||
|
||||
// process additional entries
|
||||
//cout << "Entry " << cstr_version << " " << cstr_os << endl;
|
||||
pMemEntry = entry->FirstChildElement()->ToElement();
|
||||
for(;pMemEntry;pMemEntry=pMemEntry->NextSiblingElement())
|
||||
{
|
||||
// only elements get processed
|
||||
const char *cstr_type = pMemEntry->Value();
|
||||
const char *cstr_name = pMemEntry->Attribute("name");
|
||||
const char *cstr_value = pMemEntry->GetText();
|
||||
|
||||
if(!cstr_value)
|
||||
cstr_value = pMemEntry->Attribute("id");
|
||||
|
||||
// check for missing parts
|
||||
string type, name, value;
|
||||
type = cstr_type;
|
||||
if(type == "VTable")
|
||||
{
|
||||
ParseVTable(pMemEntry, mem);
|
||||
continue;
|
||||
}
|
||||
if(!(cstr_name && cstr_value))
|
||||
{
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(cstr_version);
|
||||
}
|
||||
name = cstr_name;
|
||||
value = cstr_value;
|
||||
if (type == "HexValue")
|
||||
{
|
||||
mem->setHexValue(name, value);
|
||||
}
|
||||
else if (type == "Address")
|
||||
{
|
||||
mem->setAddress(name, value);
|
||||
}
|
||||
else if (type == "Offset")
|
||||
{
|
||||
mem->setOffset(name, value);
|
||||
}
|
||||
else if (type == "String")
|
||||
{
|
||||
mem->setString(name, value);
|
||||
}
|
||||
else if (type == "Profession")
|
||||
{
|
||||
mem->setProfession(value,name);
|
||||
}
|
||||
else if (type == "Job")
|
||||
{
|
||||
mem->setJob(value,name);
|
||||
}
|
||||
else if (type == "Skill")
|
||||
{
|
||||
mem->setSkill(value,name);
|
||||
}
|
||||
else if (type == "Trait")
|
||||
{
|
||||
mem->setTrait(value, name,pMemEntry->Attribute("level_0"),pMemEntry->Attribute("level_1"),pMemEntry->Attribute("level_2"),pMemEntry->Attribute("level_3"),pMemEntry->Attribute("level_4"),pMemEntry->Attribute("level_5"));
|
||||
}
|
||||
else if (type == "Labor")
|
||||
{
|
||||
mem->setLabor(value,name);
|
||||
}
|
||||
else if (type == "Level")
|
||||
{
|
||||
mem->setLevel(value, name, pMemEntry->Attribute("xpNxtLvl"));
|
||||
}
|
||||
else if (type == "Mood")
|
||||
{
|
||||
mem->setMood(value, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error::MemoryXmlUnknownType(type.c_str());
|
||||
}
|
||||
} // for
|
||||
} // method
|
||||
|
||||
MemInfoManager::MemInfoManager(string path_to_xml)
|
||||
{
|
||||
error = false;
|
||||
loadFile(path_to_xml);
|
||||
}
|
||||
|
||||
// load the XML file with offsets
|
||||
bool MemInfoManager::loadFile(string path_to_xml)
|
||||
{
|
||||
TiXmlDocument doc( path_to_xml.c_str() );
|
||||
//bool loadOkay = doc.LoadFile();
|
||||
if (!doc.LoadFile())
|
||||
{
|
||||
error = true;
|
||||
throw Error::MemoryXmlParse(doc.ErrorDesc(), doc.ErrorId(), doc.ErrorRow(), doc.ErrorCol());
|
||||
}
|
||||
TiXmlHandle hDoc(&doc);
|
||||
TiXmlElement* pElem;
|
||||
TiXmlHandle hRoot(0);
|
||||
memory_info mem;
|
||||
|
||||
// block: name
|
||||
{
|
||||
pElem=hDoc.FirstChildElement().Element();
|
||||
// should always have a valid root but handle gracefully if it does
|
||||
if (!pElem)
|
||||
{
|
||||
error = true;
|
||||
throw Error::MemoryXmlNoRoot();
|
||||
}
|
||||
string m_name=pElem->Value();
|
||||
if(m_name != "DFExtractor")
|
||||
{
|
||||
error = true;
|
||||
throw Error::MemoryXmlNoDFExtractor(m_name.c_str());
|
||||
}
|
||||
// save this for later
|
||||
hRoot=TiXmlHandle(pElem);
|
||||
}
|
||||
// transform elements
|
||||
{
|
||||
// trash existing list
|
||||
for(uint32_t i = 0; i < meminfo.size(); i++)
|
||||
{
|
||||
delete meminfo[i];
|
||||
}
|
||||
meminfo.clear();
|
||||
TiXmlElement* pMemInfo=hRoot.FirstChild( "MemoryDescriptors" ).FirstChild( "Entry" ).Element();
|
||||
map <string ,TiXmlElement *> map_pNamedEntries;
|
||||
vector <TiXmlElement *> v_pEntries;
|
||||
for( ; pMemInfo; pMemInfo=pMemInfo->NextSiblingElement("Entry"))
|
||||
{
|
||||
v_pEntries.push_back(pMemInfo);
|
||||
const char *id = pMemInfo->Attribute("id");
|
||||
if(id)
|
||||
{
|
||||
string str_id = id;
|
||||
map_pNamedEntries[str_id] = pMemInfo;
|
||||
}
|
||||
}
|
||||
for(uint32_t i = 0; i< v_pEntries.size();i++)
|
||||
{
|
||||
memory_info *mem = new memory_info();
|
||||
//FIXME: add a set of entries processed in a step of this cycle, use it to check for infinite loops
|
||||
/* recursive */ParseEntry( v_pEntries[i] , mem , map_pNamedEntries);
|
||||
meminfo.push_back(mem);
|
||||
}
|
||||
// process found things here
|
||||
}
|
||||
error = false;
|
||||
return true;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,630 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "Internal.h"
|
||||
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
VersionInfoFactory::~VersionInfoFactory()
|
||||
{
|
||||
// for each stored version, delete
|
||||
for(uint32_t i = 0; i < versions.size();i++)
|
||||
{
|
||||
delete versions[i];
|
||||
}
|
||||
versions.clear();
|
||||
}
|
||||
|
||||
void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
|
||||
{
|
||||
TiXmlElement* pClassEntry;
|
||||
TiXmlElement* pClassSubEntry;
|
||||
/*
|
||||
// check for rebase, do rebase if check positive
|
||||
const char * rebase = vtable->Attribute("rebase");
|
||||
if(rebase)
|
||||
{
|
||||
int32_t rebase_offset = strtol(rebase, NULL, 16);
|
||||
mem->RebaseVTable(rebase_offset);
|
||||
}
|
||||
*/
|
||||
// parse vtable entries
|
||||
pClassEntry = vtable->FirstChildElement();
|
||||
for(;pClassEntry;pClassEntry=pClassEntry->NextSiblingElement())
|
||||
{
|
||||
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, vtable);
|
||||
}
|
||||
// it's a multi-type class
|
||||
else if (type == "multiclass")
|
||||
{
|
||||
// get offset of the type variable
|
||||
const char *cstr_typeoffset = pClassEntry->Attribute("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())
|
||||
{
|
||||
type = pClassSubEntry->Value();
|
||||
if(type== "class")
|
||||
{
|
||||
// type is a value loaded from type offset
|
||||
cstr_name = pClassSubEntry->Attribute("name");
|
||||
const char *cstr_value = pClassSubEntry->Attribute("type");
|
||||
mem->setClassChild(mclass,cstr_name,cstr_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: this is ripe for replacement with a more generic approach
|
||||
void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target, bool initial)
|
||||
{
|
||||
// we parse the groups iteratively instead of recursively
|
||||
// breadcrubs acts like a makeshift stack
|
||||
// first pair entry stores the current element of that level
|
||||
// second pair entry the group object from OffsetGroup
|
||||
typedef pair < TiXmlElement *, OffsetGroup * > groupPair;
|
||||
vector< groupPair > breadcrumbs;
|
||||
{
|
||||
TiXmlElement* pEntry;
|
||||
// we get the <Offsets>, look at the children
|
||||
pEntry = parent->FirstChildElement();
|
||||
if(!pEntry)
|
||||
return;
|
||||
|
||||
OffsetGroup * currentGroup = reinterpret_cast<OffsetGroup *> (target);
|
||||
breadcrumbs.push_back(groupPair(pEntry,currentGroup));
|
||||
}
|
||||
|
||||
// work variables
|
||||
OffsetGroup * currentGroup = 0;
|
||||
TiXmlElement * currentElem = 0;
|
||||
//cerr << "<Offsets>"<< endl;
|
||||
while(1)
|
||||
{
|
||||
// get current work variables
|
||||
currentElem = breadcrumbs.back().first;
|
||||
currentGroup = breadcrumbs.back().second;
|
||||
|
||||
// we reached the end of the current group?
|
||||
if(!currentElem)
|
||||
{
|
||||
// go one level up
|
||||
breadcrumbs.pop_back();
|
||||
// exit if no more work
|
||||
if(breadcrumbs.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
//cerr << "</group>" << endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(!currentGroup)
|
||||
{
|
||||
groupPair & gp = breadcrumbs.back();
|
||||
gp.first = gp.first->NextSiblingElement();
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip non-elements
|
||||
if (currentElem->Type() != TiXmlNode::ELEMENT)
|
||||
{
|
||||
groupPair & gp = breadcrumbs.back();
|
||||
gp.first = gp.first->NextSiblingElement();
|
||||
continue;
|
||||
}
|
||||
|
||||
// we have a valid current element and current group
|
||||
// get properties
|
||||
string type = currentElem->Value();
|
||||
std::transform(type.begin(), type.end(), type.begin(), ::tolower);
|
||||
const char *cstr_name = currentElem->Attribute("name");
|
||||
if(!cstr_name)
|
||||
{
|
||||
// ERROR, missing attribute
|
||||
}
|
||||
|
||||
// evaluate elements
|
||||
const char *cstr_value = currentElem->Attribute("value");
|
||||
if(type == "group")
|
||||
{
|
||||
// FIXME: possibly use setGroup always, with the initial flag as parameter?
|
||||
// create or get group
|
||||
OffsetGroup * og;
|
||||
if(initial)
|
||||
og = currentGroup->createGroup(cstr_name);
|
||||
else
|
||||
og = currentGroup->getGroup(cstr_name);
|
||||
//cerr << "<group name=\"" << cstr_name << "\">" << endl;
|
||||
// advance this level to the next element
|
||||
groupPair & gp = breadcrumbs.back();
|
||||
gp.first = currentElem->NextSiblingElement();
|
||||
|
||||
if(!og)
|
||||
{
|
||||
string fullname = currentGroup->getFullName() + cstr_name;
|
||||
throw Error::MissingMemoryDefinition("group", fullname);
|
||||
}
|
||||
|
||||
// add a new level that will be processed next
|
||||
breadcrumbs.push_back(groupPair(currentElem->FirstChildElement(), og));
|
||||
continue;
|
||||
}
|
||||
else if(type == "address")
|
||||
{
|
||||
if(initial)
|
||||
{
|
||||
currentGroup->createAddress(cstr_name);
|
||||
}
|
||||
else if(cstr_value)
|
||||
{
|
||||
currentGroup->setAddress(cstr_name, cstr_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ERROR, missing attribute
|
||||
}
|
||||
}
|
||||
else if(type == "offset")
|
||||
{
|
||||
if(initial)
|
||||
{
|
||||
currentGroup->createOffset(cstr_name);
|
||||
}
|
||||
else if(cstr_value)
|
||||
{
|
||||
currentGroup->setOffset(cstr_name, cstr_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ERROR, missing attribute
|
||||
}
|
||||
}
|
||||
else if(type == "string")
|
||||
{
|
||||
if(initial)
|
||||
{
|
||||
currentGroup->createString(cstr_name);
|
||||
}
|
||||
else if(cstr_value)
|
||||
{
|
||||
currentGroup->setString(cstr_name, cstr_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ERROR, missing attribute
|
||||
}
|
||||
}
|
||||
else if(type == "hexvalue")
|
||||
{
|
||||
if(initial)
|
||||
{
|
||||
currentGroup->createHexValue(cstr_name);
|
||||
}
|
||||
else if(cstr_value)
|
||||
{
|
||||
currentGroup->setHexValue(cstr_name, cstr_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ERROR, missing attribute
|
||||
}
|
||||
}
|
||||
|
||||
// advance to next element
|
||||
groupPair & gp = breadcrumbs.back();
|
||||
gp.first = currentElem->NextSiblingElement();
|
||||
continue;
|
||||
}
|
||||
//cerr << "</Offsets>"<< endl;
|
||||
}
|
||||
|
||||
void VersionInfoFactory::ParseBase (TiXmlElement* entry, VersionInfo* mem)
|
||||
{
|
||||
TiXmlElement* pElement;
|
||||
TiXmlElement* pElement2nd;
|
||||
const char *cstr_version = entry->Attribute("name");
|
||||
|
||||
if (!cstr_version)
|
||||
throw Error::MemoryXmlBadAttribute("name");
|
||||
|
||||
mem->setVersion(cstr_version);
|
||||
mem->setOS(VersionInfo::OS_BAD);
|
||||
|
||||
// process additional entries
|
||||
pElement = entry->FirstChildElement()->ToElement();
|
||||
for(;pElement;pElement=pElement->NextSiblingElement())
|
||||
{
|
||||
// only elements get processed
|
||||
const char *cstr_type = pElement->Value();
|
||||
std::string type = cstr_type;
|
||||
if(type == "VTable")
|
||||
{
|
||||
ParseVTable(pElement, mem);
|
||||
continue;
|
||||
}
|
||||
else if(type == "Offsets")
|
||||
{
|
||||
// we don't care about the descriptions here, do nothing
|
||||
ParseOffsets(pElement, mem, true);
|
||||
continue;
|
||||
}
|
||||
else if (type == "Professions")
|
||||
{
|
||||
pElement2nd = pElement->FirstChildElement("Profession");
|
||||
for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Profession"))
|
||||
{
|
||||
const char * id = pElement2nd->Attribute("id");
|
||||
const char * name = pElement2nd->Attribute("name");
|
||||
// FIXME: missing some attributes here
|
||||
if(id && name)
|
||||
{
|
||||
mem->setProfession(id,name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: this is crap, doesn't tell anything about the error
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "Jobs")
|
||||
{
|
||||
pElement2nd = pElement->FirstChildElement("Job");
|
||||
for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Job"))
|
||||
{
|
||||
const char * id = pElement2nd->Attribute("id");
|
||||
const char * name = pElement2nd->Attribute("name");
|
||||
if(id && name)
|
||||
{
|
||||
mem->setJob(id,name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: this is crap, doesn't tell anything about the error
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "Skills")
|
||||
{
|
||||
pElement2nd = pElement->FirstChildElement("Skill");
|
||||
for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Skill"))
|
||||
{
|
||||
const char * id = pElement2nd->Attribute("id");
|
||||
const char * name = pElement2nd->Attribute("name");
|
||||
if(id && name)
|
||||
{
|
||||
mem->setSkill(id,name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: this is crap, doesn't tell anything about the error
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "Traits")
|
||||
{
|
||||
pElement2nd = pElement->FirstChildElement("Trait");
|
||||
for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Trait"))
|
||||
{
|
||||
const char * id = pElement2nd->Attribute("id");
|
||||
const char * name = pElement2nd->Attribute("name");
|
||||
const char * lvl0 = pElement2nd->Attribute("level_0");
|
||||
const char * lvl1 = pElement2nd->Attribute("level_1");
|
||||
const char * lvl2 = pElement2nd->Attribute("level_2");
|
||||
const char * lvl3 = pElement2nd->Attribute("level_3");
|
||||
const char * lvl4 = pElement2nd->Attribute("level_4");
|
||||
const char * lvl5 = pElement2nd->Attribute("level_5");
|
||||
if(id && name && lvl0 && lvl1 && lvl2 && lvl3 && lvl4 && lvl5)
|
||||
{
|
||||
mem->setTrait(id, name, lvl0, lvl1, lvl2, lvl3, lvl4, lvl5);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: this is crap, doesn't tell anything about the error
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "Labors")
|
||||
{
|
||||
pElement2nd = pElement->FirstChildElement("Labor");
|
||||
for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Labor"))
|
||||
{
|
||||
const char * id = pElement2nd->Attribute("id");
|
||||
const char * name = pElement2nd->Attribute("name");
|
||||
if(id && name)
|
||||
{
|
||||
mem->setLabor(id,name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: this is crap, doesn't tell anything about the error
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "Levels")
|
||||
{
|
||||
pElement2nd = pElement->FirstChildElement("Level");
|
||||
for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Level"))
|
||||
{
|
||||
const char * id = pElement2nd->Attribute("id");
|
||||
const char * name = pElement2nd->Attribute("name");
|
||||
const char * nextlvl = pElement2nd->Attribute("xpNxtLvl");
|
||||
if(id && name && nextlvl)
|
||||
{
|
||||
mem->setLevel(id, name, nextlvl);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: this is crap, doesn't tell anything about the error
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "Moods")
|
||||
{
|
||||
pElement2nd = pElement->FirstChildElement("Mood");
|
||||
for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Mood"))
|
||||
{
|
||||
const char * id = pElement2nd->Attribute("id");
|
||||
const char * name = pElement2nd->Attribute("name");
|
||||
if(id && name)
|
||||
{
|
||||
mem->setMood(id, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: this is crap, doesn't tell anything about the error
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME: only log, not hard error
|
||||
//throw Error::MemoryXmlUnknownType(type.c_str());
|
||||
}
|
||||
} // for
|
||||
} // method
|
||||
|
||||
void VersionInfoFactory::EvalVersion(string base, VersionInfo * mem)
|
||||
{
|
||||
if(knownVersions.find(base) != knownVersions.end())
|
||||
{
|
||||
v_descr & desc = knownVersions[base];
|
||||
if (!desc.second)
|
||||
{
|
||||
VersionInfo * newmem = new VersionInfo();
|
||||
ParseVersion(desc.first, newmem);
|
||||
desc.second = newmem;
|
||||
}
|
||||
mem->copy(desc.second);
|
||||
}
|
||||
}
|
||||
|
||||
void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
|
||||
{
|
||||
TiXmlElement* pMemEntry;
|
||||
const char *cstr_name = entry->Attribute("name");
|
||||
const char *cstr_os = entry->Attribute("os");
|
||||
const char *cstr_base = entry->Attribute("base");
|
||||
const char *cstr_rebase = entry->Attribute("rebase");
|
||||
if(cstr_base)
|
||||
{
|
||||
string base = cstr_base;
|
||||
EvalVersion(base, mem);
|
||||
}
|
||||
|
||||
if (!cstr_name)
|
||||
throw Error::MemoryXmlBadAttribute("name");
|
||||
if (!cstr_os)
|
||||
throw Error::MemoryXmlBadAttribute("os");
|
||||
|
||||
string os = cstr_os;
|
||||
mem->setVersion(cstr_name);
|
||||
mem->setOS(cstr_os);
|
||||
|
||||
// offset inherited addresses by 'rebase'.
|
||||
int32_t rebase = 0;
|
||||
if(cstr_rebase)
|
||||
{
|
||||
rebase = mem->getBase() + strtol(cstr_rebase, NULL, 16);
|
||||
mem->RebaseAddresses(rebase);
|
||||
}
|
||||
|
||||
//set base to default, we're overwriting this because the previous rebase could cause havoc on Vista/7
|
||||
if(os == "windows")
|
||||
{
|
||||
// set default image base. this is fixed for base relocation later
|
||||
mem->setBase(0x400000);
|
||||
}
|
||||
else if(os == "linux")
|
||||
{
|
||||
// this is wrong... I'm not going to do base image relocation on linux though.
|
||||
// users are free to use a sane kernel that doesn't do this kind of **** by default
|
||||
mem->setBase(0x0);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error::MemoryXmlBadAttribute("os");
|
||||
}
|
||||
|
||||
// process additional entries
|
||||
//cout << "Entry " << cstr_version << " " << cstr_os << endl;
|
||||
pMemEntry = entry->FirstChildElement()->ToElement();
|
||||
for(;pMemEntry;pMemEntry=pMemEntry->NextSiblingElement())
|
||||
{
|
||||
string type, name, value;
|
||||
const char *cstr_type = pMemEntry->Value();
|
||||
type = cstr_type;
|
||||
// check for missing parts
|
||||
if(type == "VTable")
|
||||
{
|
||||
ParseVTable(pMemEntry, mem);
|
||||
continue;
|
||||
}
|
||||
else if(type == "Offsets")
|
||||
{
|
||||
ParseOffsets(pMemEntry, mem);
|
||||
continue;
|
||||
}
|
||||
else if (type == "MD5")
|
||||
{
|
||||
const char *cstr_value = pMemEntry->Attribute("value");
|
||||
if(!cstr_value)
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(cstr_name);
|
||||
mem->setMD5(cstr_value);
|
||||
}
|
||||
else if (type == "PETimeStamp")
|
||||
{
|
||||
const char *cstr_value = pMemEntry->Attribute("value");
|
||||
if(!cstr_value)
|
||||
throw Error::MemoryXmlUnderspecifiedEntry(cstr_name);
|
||||
mem->setPE(strtol(cstr_value, 0, 16));
|
||||
}
|
||||
} // for
|
||||
} // method
|
||||
|
||||
VersionInfoFactory::VersionInfoFactory(string path_to_xml)
|
||||
{
|
||||
error = false;
|
||||
loadFile(path_to_xml);
|
||||
}
|
||||
|
||||
// load the XML file with offsets
|
||||
bool VersionInfoFactory::loadFile(string path_to_xml)
|
||||
{
|
||||
TiXmlDocument doc( path_to_xml.c_str() );
|
||||
//bool loadOkay = doc.LoadFile();
|
||||
if (!doc.LoadFile())
|
||||
{
|
||||
error = true;
|
||||
throw Error::MemoryXmlParse(doc.ErrorDesc(), doc.ErrorId(), doc.ErrorRow(), doc.ErrorCol());
|
||||
}
|
||||
TiXmlHandle hDoc(&doc);
|
||||
TiXmlElement* pElem;
|
||||
TiXmlHandle hRoot(0);
|
||||
VersionInfo *mem;
|
||||
|
||||
// block: name
|
||||
{
|
||||
pElem=hDoc.FirstChildElement().Element();
|
||||
// should always have a valid root but handle gracefully if it does
|
||||
if (!pElem)
|
||||
{
|
||||
error = true;
|
||||
throw Error::MemoryXmlNoRoot();
|
||||
}
|
||||
string m_name=pElem->Value();
|
||||
if(m_name != "DFHack")
|
||||
{
|
||||
error = true;
|
||||
throw Error::MemoryXmlNoRoot();
|
||||
}
|
||||
// save this for later
|
||||
hRoot=TiXmlHandle(pElem);
|
||||
}
|
||||
// transform elements
|
||||
{
|
||||
// trash existing list
|
||||
for(uint32_t i = 0; i < versions.size(); i++)
|
||||
{
|
||||
delete versions[i];
|
||||
}
|
||||
versions.clear();
|
||||
|
||||
// For each base version
|
||||
TiXmlElement* pMemInfo=hRoot.FirstChild( "Base" ).Element();
|
||||
map <string ,TiXmlElement *> map_pNamedEntries;
|
||||
vector <string> v_sEntries;
|
||||
for( ; pMemInfo; pMemInfo=pMemInfo->NextSiblingElement("Base"))
|
||||
{
|
||||
const char *name = pMemInfo->Attribute("name");
|
||||
if(name)
|
||||
{
|
||||
string str_name = name;
|
||||
VersionInfo *base = new VersionInfo();
|
||||
mem = new VersionInfo();
|
||||
ParseBase( pMemInfo , mem );
|
||||
knownVersions[str_name] = v_descr (pMemInfo, mem);
|
||||
}
|
||||
}
|
||||
|
||||
// For each derivative version
|
||||
pMemInfo=hRoot.FirstChild( "Version" ).Element();
|
||||
for( ; pMemInfo; pMemInfo=pMemInfo->NextSiblingElement("Version"))
|
||||
{
|
||||
const char *name = pMemInfo->Attribute("name");
|
||||
if(name)
|
||||
{
|
||||
string str_name = name;
|
||||
knownVersions[str_name] = v_descr (pMemInfo, NULL);
|
||||
v_sEntries.push_back(str_name);
|
||||
}
|
||||
}
|
||||
// Parse the versions
|
||||
for(uint32_t i = 0; i< v_sEntries.size();i++)
|
||||
{
|
||||
//FIXME: add a set of entries processed in a step of this cycle, use it to check for infinite loops
|
||||
string & name = v_sEntries[i];
|
||||
v_descr & desc = knownVersions[name];
|
||||
if(!desc.second)
|
||||
{
|
||||
VersionInfo *version = new VersionInfo();
|
||||
ParseVersion( desc.first , version );
|
||||
versions.push_back(version);
|
||||
}
|
||||
}
|
||||
|
||||
// process found things here
|
||||
}
|
||||
error = false;
|
||||
return true;
|
||||
}
|
@ -0,0 +1,449 @@
|
||||
// Console version of DF copy paste, proof of concept
|
||||
// By belal
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
|
||||
#define DFHACK_WANT_MISCUTILS
|
||||
#define DFHACK_WANT_TILETYPES
|
||||
#include <DFHack.h>
|
||||
#include "dfhack/modules/WindowIO.h"
|
||||
|
||||
using namespace DFHack;
|
||||
//bool waitTillCursorState(DFHack::Context *DF, bool On);
|
||||
//bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z);
|
||||
|
||||
//change this if you are having problems getting correct results, lower if you would like to go faster
|
||||
//const int WAIT_AMT = 25;
|
||||
|
||||
void sort(uint32_t &a,uint32_t &b)
|
||||
{
|
||||
if(a > b){
|
||||
uint32_t c = b;
|
||||
b = a;
|
||||
a = c;
|
||||
}
|
||||
}
|
||||
void sort(int32_t &a,int32_t &b)
|
||||
{
|
||||
if(a > b){
|
||||
int16_t c = b;
|
||||
b = a;
|
||||
a = c;
|
||||
}
|
||||
}
|
||||
void printVecOfVec(ostream &out, vector<vector<vector<string> > >vec,char sep){
|
||||
for(int k=0;k<vec.size();k++){
|
||||
for(int i =0;i<vec[k].size();i++){
|
||||
for(int j=0;j<vec[k][i].size();j++){
|
||||
out << vec[k][i][j];
|
||||
if(j==vec[k][i].size()-1)
|
||||
{
|
||||
out << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << sep;
|
||||
}
|
||||
}
|
||||
}
|
||||
out << "#<\n";
|
||||
}
|
||||
}
|
||||
int main (int numargs, const char ** args)
|
||||
{
|
||||
map<string, string> buildCommands;
|
||||
buildCommands["building_stockpilest"]="";
|
||||
buildCommands["building_zonest"]="";
|
||||
buildCommands["building_construction_blueprintst"]="";
|
||||
buildCommands["building_wagonst"]="";
|
||||
buildCommands["building_armor_standst"]="a";
|
||||
buildCommands["building_bedst"]="b";
|
||||
buildCommands["building_seatst"]="c";
|
||||
buildCommands["building_burial_receptaclest"]="n";
|
||||
buildCommands["building_doorst"]="d";
|
||||
buildCommands["building_floodgatest"]="x";
|
||||
buildCommands["building_floor_hatchst"]="H";
|
||||
buildCommands["building_wall_gratest"]="W";
|
||||
buildCommands["building_floor_gratest"]="G";
|
||||
buildCommands["building_vertical_barsst"]="B";
|
||||
buildCommands["building_floor_barsst"]="alt-b";
|
||||
buildCommands["building_cabinetst"]="f";
|
||||
buildCommands["building_containerst"]="h";
|
||||
buildCommands["building_shopst"]="";
|
||||
buildCommands["building_workshopst"]="";
|
||||
buildCommands["building_alchemists_laboratoryst"]="wa";
|
||||
buildCommands["building_carpenters_workshopst"]="wc";
|
||||
buildCommands["building_farmers_workshopst"]="ww";
|
||||
buildCommands["building_masons_workshopst"]="wm";
|
||||
buildCommands["building_craftdwarfs_workshopst"]="wr";
|
||||
buildCommands["building_jewelers_workshopst"]="wj";
|
||||
buildCommands["building_metalsmiths_workshopst"]="wf";
|
||||
buildCommands["building_magma_forgest"]="";
|
||||
buildCommands["building_bowyers_workshopst"]="wb";
|
||||
buildCommands["building_mechanics_workshopst"]="wt";
|
||||
buildCommands["building_siege_workshopst"]="ws";
|
||||
buildCommands["building_butchers_shopst"]="wU";
|
||||
buildCommands["building_leather_worksst"]="we";
|
||||
buildCommands["building_tanners_shopst"]="wn";
|
||||
buildCommands["building_clothiers_shopst"]="wk";
|
||||
buildCommands["building_fisheryst"]="wh";
|
||||
buildCommands["building_stillst"]="wl";
|
||||
buildCommands["building_loomst"]="wo";
|
||||
buildCommands["building_quernst"]="wq";
|
||||
buildCommands["building_kennelsst"]="k";
|
||||
buildCommands["building_kitchenst"]="wz";
|
||||
buildCommands["building_asheryst"]="wy";
|
||||
buildCommands["building_dyers_shopst"]="wd";
|
||||
buildCommands["building_millstonest"]="wM";
|
||||
buildCommands["building_farm_plotst"]="p";
|
||||
buildCommands["building_weapon_rackst"]="r";
|
||||
buildCommands["building_statuest"]="s";
|
||||
buildCommands["building_tablest"]="t";
|
||||
buildCommands["building_paved_roadst"]="o";
|
||||
buildCommands["building_bridgest"]="g";
|
||||
buildCommands["building_wellst"]="l";
|
||||
buildCommands["building_siege enginest"]="i";
|
||||
buildCommands["building_catapultst"]="ic";
|
||||
buildCommands["building_ballistast"]="ib";
|
||||
buildCommands["building_furnacest"]="";
|
||||
buildCommands["building_wood_furnacest"]="ew";
|
||||
buildCommands["building_smelterst"]="es";
|
||||
buildCommands["building_glass_furnacest"]="ek";
|
||||
buildCommands["building_kilnst"]="ek";
|
||||
buildCommands["building_magma_smelterst"]="es";
|
||||
buildCommands["building_magma_glass_furnacest"]="ek";
|
||||
buildCommands["building_magma_kilnst"]="ek";
|
||||
buildCommands["building_glass_windowst"]="y";
|
||||
buildCommands["building_gem_windowst"]="Y";
|
||||
buildCommands["building_tradedepotst"]="D";
|
||||
buildCommands["building_mechanismst"]="";
|
||||
buildCommands["building_leverst"]="Tl";
|
||||
buildCommands["building_pressure_platest"]="Tp";
|
||||
buildCommands["building_cage_trapst"]="Tc";
|
||||
buildCommands["building_stonefall_trapst"]="Ts";
|
||||
buildCommands["building_weapon_trapst"]="Tw";
|
||||
buildCommands["building_spikest"]="";
|
||||
buildCommands["building_animal_trapst"]="m";
|
||||
buildCommands["building_screw_pumpst"]="Ms";
|
||||
buildCommands["building_water_wheelst"]="Mw";
|
||||
buildCommands["building_windmillst"]="Mm";
|
||||
buildCommands["building_gear_assemblyst"]="Mg";
|
||||
buildCommands["building_horizontal_axlest"]="Mh";
|
||||
buildCommands["building_vertical_axlest"]="Mv";
|
||||
buildCommands["building_supportst"]="S";
|
||||
buildCommands["building_cagest"]="j";
|
||||
buildCommands["building_archery_targetst"]="A";
|
||||
buildCommands["building_restraintst"]="v";
|
||||
|
||||
DFHack::ContextManager DFMgr("Memory.xml");
|
||||
DFHack::Context *DF = DFMgr.getSingleContext();
|
||||
|
||||
try
|
||||
{
|
||||
DF->Attach();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
#ifndef LINUX_BUILD
|
||||
cin.ignore();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
DFHack::Position *Pos = DF->getPosition();
|
||||
DFHack::VersionInfo* mem = DF->getMemoryInfo();
|
||||
DFHack::Process * p = DF->getProcess();
|
||||
OffsetGroup * OG_Maps = mem->getGroup("Maps");
|
||||
OffsetGroup * OG_MapBlock = OG_Maps->getGroup("block");
|
||||
OffsetGroup * OG_LocalFt = OG_Maps->getGroup("features")->getGroup("local");
|
||||
uint32_t designations = OG_MapBlock->getOffset("designation");
|
||||
uint32_t block_feature1 = OG_MapBlock->getOffset("feature_local");
|
||||
uint32_t block_feature2 = OG_MapBlock->getOffset("feature_global");
|
||||
uint32_t region_x_offset = OG_Maps->getAddress("region_x");
|
||||
uint32_t region_y_offset = OG_Maps->getAddress("region_y");
|
||||
uint32_t region_z_offset = OG_Maps->getAddress("region_z");
|
||||
uint32_t feature1_start_ptr = OG_LocalFt->getAddress("start_ptr");
|
||||
int32_t regionX, regionY, regionZ;
|
||||
|
||||
// read position of the region inside DF world
|
||||
p->readDWord (region_x_offset, (uint32_t &)regionX);
|
||||
p->readDWord (region_y_offset, (uint32_t &)regionY);
|
||||
p->readDWord (region_z_offset, (uint32_t &)regionZ);
|
||||
while(1){
|
||||
int32_t cx1,cy1,cz1;
|
||||
cx1 = -30000;
|
||||
while(cx1 == -30000){
|
||||
DF->ForceResume();
|
||||
cout << "Set cursor at first position, then press any key";
|
||||
cin.ignore();
|
||||
DF->Suspend();
|
||||
Pos->getCursorCoords(cx1,cy1,cz1);
|
||||
}
|
||||
|
||||
uint32_t tx1,ty1,tz1;
|
||||
tx1 = cx1/16;
|
||||
ty1 = cy1/16;
|
||||
tz1 = cz1;
|
||||
|
||||
int32_t cx2,cy2,cz2;
|
||||
cx2 = -30000;
|
||||
while(cx2 == -30000){
|
||||
DF->Resume();
|
||||
cout << "Set cursor at second position, then press any key";
|
||||
cin.ignore();
|
||||
DF->Suspend();
|
||||
Pos->getCursorCoords(cx2,cy2,cz2);
|
||||
}
|
||||
uint32_t tx2,ty2,tz2;
|
||||
tx2 = cx2/16;
|
||||
ty2 = cy2/16;
|
||||
tz2 = cz2;
|
||||
sort(tx1,tx2);
|
||||
sort(ty1,ty2);
|
||||
sort(tz1,tz2);
|
||||
sort(cx1,cx2);
|
||||
sort(cy1,cy2);
|
||||
sort(cz1,cz2);
|
||||
|
||||
vector <vector<vector<string> > >dig(cz2-cz1+1,vector<vector<string> >(cy2-cy1+1,vector<string>(cx2-cx1+1)));
|
||||
vector <vector<vector<string> > >build(cz2-cz1+1,vector<vector<string> >(cy2-cy1+1,vector<string>(cx2-cx1+1)));
|
||||
mapblock40d block;
|
||||
DFHack::Maps *Maps = DF->getMaps();
|
||||
Maps->Start();
|
||||
for(uint32_t y = ty1;y<=ty2;y++)
|
||||
{
|
||||
for(uint32_t x = tx1;x<=tx2;x++)
|
||||
{
|
||||
for(uint32_t z = tz1;z<=tz2;z++)
|
||||
{
|
||||
if(Maps->isValidBlock(x,y,z))
|
||||
{
|
||||
if(Maps->ReadBlock40d(x,y,z,&block))
|
||||
{
|
||||
int ystart,yend,xstart,xend;
|
||||
ystart=xstart=0;
|
||||
yend=xend=15;
|
||||
if(y == ty2)
|
||||
{
|
||||
yend = cy2 % 16;
|
||||
}
|
||||
if(y == ty1)
|
||||
{
|
||||
ystart = cy1 % 16;
|
||||
}
|
||||
if(x == tx2)
|
||||
{
|
||||
xend = cx2 % 16;
|
||||
}
|
||||
if(x == tx1)
|
||||
{
|
||||
xstart = cx1 % 16;
|
||||
}
|
||||
int zidx = z-tz1;
|
||||
for(int yy = ystart; yy <= yend;yy++)
|
||||
{
|
||||
int yidx = yy+(16*(y-ty1)-(cy1%16));
|
||||
for(int xx = xstart; xx <= xend;xx++)
|
||||
{
|
||||
int xidx = xx+(16*(x-tx1)-(cx1%16));
|
||||
if(DFHack::isOpenTerrain(block.tiletypes[xx][yy]) || DFHack::isFloorTerrain(block.tiletypes[xx][yy])) {dig[zidx][yidx][xidx] = "d";}
|
||||
else if(DFHack::STAIR_DOWN == DFHack::tileTypeTable[block.tiletypes[xx][yy]].c){ dig [zidx][yidx][xidx] = "j"; build [zidx][yidx][xidx] = "Cd";}
|
||||
else if(DFHack::STAIR_UP == DFHack::tileTypeTable[block.tiletypes[xx][yy]].c){ dig [zidx][yidx][xidx] = "u"; build [zidx][yidx][xidx] = "Cu";}
|
||||
else if(DFHack::STAIR_UPDOWN == DFHack::tileTypeTable[block.tiletypes[xx][yy]].c){ dig [zidx][yidx][xidx] = "i"; build [zidx][yidx][xidx] = "Cx";}
|
||||
else if(DFHack::isRampTerrain(block.tiletypes[xx][yy])){dig [zidx][yidx][xidx] = "r";build [zidx][yidx][xidx] = "Cr";}
|
||||
else if(DFHack::isWallTerrain(block.tiletypes[xx][yy])){build [zidx][yidx][xidx] = "Cw";}
|
||||
}
|
||||
yidx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DFHack::Buildings * Bld = DF->getBuildings();
|
||||
std::map <uint32_t, std::string> custom_workshop_types;
|
||||
uint32_t numBuildings;
|
||||
if(Bld->Start(numBuildings))
|
||||
{
|
||||
Bld->ReadCustomWorkshopTypes(custom_workshop_types);
|
||||
for(uint32_t i = 0; i < numBuildings; i++)
|
||||
{
|
||||
DFHack::t_building temp;
|
||||
Bld->Read(i, temp);
|
||||
if(temp.type != 0xFFFFFFFF) // check if type isn't invalid
|
||||
{
|
||||
std::string typestr;
|
||||
mem->resolveClassIDToClassname(temp.type, typestr);
|
||||
if(temp.z == cz1 && cx1 <= temp.x1 && cx2 >= temp.x2 && cy1 <= temp.y1 && cy2 >= temp.y2)
|
||||
{
|
||||
string currStr = build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1];
|
||||
stringstream stream;
|
||||
string newStr = buildCommands[typestr];
|
||||
if(temp.x1 != temp.x2)
|
||||
{
|
||||
stream << "(" << temp.x2-temp.x1+1 << "x" << temp.y2-temp.y1+1 << ")";
|
||||
newStr += stream.str();
|
||||
}
|
||||
build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1] = newStr + currStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for testing purposes
|
||||
//ofstream outfile("test.txt");
|
||||
// printVecOfVec(outfile, dig,'\t');
|
||||
// outfile << endl;
|
||||
// printVecOfVec(outfile, build,'\t');
|
||||
// outfile << endl;
|
||||
// outfile.close();
|
||||
|
||||
int32_t cx3,cy3,cz3,cx4,cy4,cz4;
|
||||
uint32_t tx3,ty3,tz3,tx4,ty4,tz4;
|
||||
char result;
|
||||
while(1){
|
||||
cx3 = -30000;
|
||||
while(cx3 == -30000){
|
||||
DF->Resume();
|
||||
cout << "Set cursor at new position, then press any key:";
|
||||
result = cin.get();
|
||||
DF->Suspend();
|
||||
Pos->getCursorCoords(cx3,cy3,cz3);
|
||||
}
|
||||
if(result == 'q'){
|
||||
break;
|
||||
}
|
||||
cx4 = cx3+cx2-cx1;
|
||||
cy4 = cy3+cy2-cy1;
|
||||
cz4 = cz3+cz2-cz1;
|
||||
tx3=cx3/16;
|
||||
ty3=cy3/16;
|
||||
tz3=cz3;
|
||||
tx4=cx4/16;
|
||||
ty4=cy4/16;
|
||||
tz4=cz4;
|
||||
DFHack::WindowIO * Win = DF->getWindowIO();
|
||||
designations40d designationBlock;
|
||||
for(uint32_t y = ty3;y<=ty4;y++)
|
||||
{
|
||||
for(uint32_t x = tx3;x<=tx4;x++)
|
||||
{
|
||||
for(uint32_t z = tz3;z<=tz4;z++)
|
||||
{
|
||||
Maps->Start();
|
||||
Maps->ReadBlock40d(x,y,z,&block);
|
||||
Maps->ReadDesignations(x,y,z,&designationBlock);
|
||||
int ystart,yend,xstart,xend;
|
||||
ystart=xstart=0;
|
||||
yend=xend=15;
|
||||
if(y == ty4){
|
||||
yend = cy4 % 16;
|
||||
}
|
||||
if(y == ty3){
|
||||
ystart = cy3 % 16;
|
||||
}
|
||||
if(x == tx4){
|
||||
xend = cx4 % 16;
|
||||
}
|
||||
if(x == tx3){
|
||||
xstart = cx3 % 16;
|
||||
}
|
||||
int zidx = z-tz3;
|
||||
for(int yy = ystart; yy <= yend;yy++){
|
||||
int yidx = yy+(16*(y-ty3)-(cy3%16));
|
||||
for(int xx = xstart; xx <= xend;xx++){
|
||||
int xidx = xx+(16*(x-tx3)-(cx3%16));
|
||||
if(dig[zidx][yidx][xidx] != ""){
|
||||
char test = dig[zidx][yidx][xidx].c_str()[0];
|
||||
switch (test){
|
||||
case 'd':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_default;
|
||||
break;
|
||||
case 'i':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_ud_stair;
|
||||
break;
|
||||
case 'u':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_u_stair;
|
||||
break;
|
||||
case 'j':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_d_stair;
|
||||
break;
|
||||
case 'r':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_ramp;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
yidx++;
|
||||
}
|
||||
Maps->Start();
|
||||
Maps->WriteDesignations(x,y,z,&designationBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DF->Detach();
|
||||
#ifndef LINUX_BUILD
|
||||
std::cout << "Done. Press any key to continue" << std::endl;
|
||||
cin.ignore();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
bool waitTillCursorState(DFHack::Context *DF, bool On)
|
||||
{
|
||||
DFHack::WindowIO * w = DF->getWindowIO();
|
||||
DFHack::Position * p = DF->getPosition();
|
||||
int32_t x,y,z;
|
||||
int tryCount = 0;
|
||||
DF->Suspend();
|
||||
bool cursorResult = p->getCursorCoords(x,y,z);
|
||||
while(tryCount < 50 && On && !cursorResult || !On && cursorResult)
|
||||
{
|
||||
DF->Resume();
|
||||
w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT);
|
||||
tryCount++;
|
||||
DF->Suspend();
|
||||
cursorResult = p->getCursorCoords(x,y,z);
|
||||
}
|
||||
if(tryCount >= 50)
|
||||
{
|
||||
cerr << "Something went wrong, cursor at x: " << x << " y: " << y << " z: " << z << endl;
|
||||
return false;
|
||||
}
|
||||
DF->Resume();
|
||||
return true;
|
||||
}
|
||||
bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z)
|
||||
{
|
||||
DFHack::WindowIO * w = DF->getWindowIO();
|
||||
DFHack::Position * p = DF->getPosition();
|
||||
int32_t x2,y2,z2;
|
||||
int tryCount = 0;
|
||||
DF->Suspend();
|
||||
bool cursorResult = p->getCursorCoords(x2,y2,z2);
|
||||
while(tryCount < 50 && (x != x2 || y != y2 || z != z2))
|
||||
{
|
||||
DF->Resume();
|
||||
w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT);
|
||||
tryCount++;
|
||||
DF->Suspend();
|
||||
cursorResult = p->getCursorCoords(x2,y2,z2);
|
||||
}
|
||||
if(tryCount >= 50)
|
||||
{
|
||||
cerr << "Something went wrong, cursor at x: " << x2 << " y: " << y2 << " z: " << z2 << endl;
|
||||
return false;
|
||||
}
|
||||
DF->Resume();
|
||||
return true;
|
||||
}*/
|
@ -0,0 +1,98 @@
|
||||
// Just show some position data
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
|
||||
#define DFHACK_WANT_MISCUTILS
|
||||
#define DFHACK_WANT_TILETYPES
|
||||
#include <DFHack.h>
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
void printWeather(DFHack::WeatherType current)
|
||||
{
|
||||
switch (current)
|
||||
{
|
||||
case CLEAR:
|
||||
cout << "The sky is clear." << endl;
|
||||
cout << "Options:" << endl;
|
||||
cout << "'r' to make it rain." << endl;
|
||||
cout << "'s' to make it snow." << endl;
|
||||
break;
|
||||
case RAINING:
|
||||
cout << "It is raining." << endl;
|
||||
cout << "Options:" << endl;
|
||||
cout << "'c' to clear the sky." << endl;
|
||||
cout << "'s' to make it snow." << endl;
|
||||
break;
|
||||
case SNOWING:
|
||||
cout << "It is snowing." << endl;
|
||||
cout << "Options:" << endl;
|
||||
cout << "'c' to clear the sky." << endl;
|
||||
cout << "'r' to make it rain." << endl;
|
||||
break;
|
||||
}
|
||||
cout << "'q' to quit." << endl;
|
||||
cout << "anything else to refresh" << endl;
|
||||
cout << ">";
|
||||
}
|
||||
|
||||
using namespace DFHack;
|
||||
int main (int numargs, const char ** args)
|
||||
{
|
||||
DFHack::ContextManager DFMgr("Memory.xml");
|
||||
DFHack::Context *DF = DFMgr.getSingleContext();
|
||||
|
||||
try
|
||||
{
|
||||
DF->Attach();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
#ifndef LINUX_BUILD
|
||||
cin.ignore();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
World *W = DF->getWorld();
|
||||
W->Start();
|
||||
bool end = false;
|
||||
while(!end)
|
||||
{
|
||||
WeatherType current = (WeatherType) W->ReadCurrentWeather();
|
||||
DF->Resume();
|
||||
string command = "";
|
||||
printWeather(current);
|
||||
getline(cin, command);
|
||||
DF->Suspend();
|
||||
if(command == "c")
|
||||
{
|
||||
W->SetCurrentWeather(CLEAR);
|
||||
}
|
||||
else if(command == "r")
|
||||
{
|
||||
W->SetCurrentWeather(RAINING);
|
||||
}
|
||||
else if(command == "s")
|
||||
{
|
||||
W->SetCurrentWeather(SNOWING);
|
||||
}
|
||||
else if(command == "q")
|
||||
{
|
||||
end = true;
|
||||
}
|
||||
}
|
||||
#ifndef LINUX_BUILD
|
||||
std::cout << "Done. Press any key to continue" << std::endl;
|
||||
cin.ignore();
|
||||
#endif
|
||||
DF->Detach();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue