Merge remote branch 'upstream/master'

Conflicts:
	tools/playground/CMakeLists.txt
develop
Raoul XQ 2011-04-12 12:38:49 +02:00
commit 05f33853e1
14 changed files with 681 additions and 437 deletions

@ -1,7 +1,7 @@
<?xml version="1.0"?>
<DFHack>
<Base name="DF40d.xx">
<Offsets>
<Base name="DF40d.xx">
<Offsets>
<Group name="vector" description="An STL vector.">
<HexValue name="sizeof" description="The total size in bytes." />
<Offset name="start" description="The offset where the actual start/end/alloc_end triplet is." />
@ -31,16 +31,16 @@
<Offset name="second_words" description="Array of 7 indexes into the language vectors."/>
</Group>
</Offsets>
</Base>
<Version name="40d" base="DF40d.xx" os="windows">
<MD5 value="2c686c26307dcccd7c36cc79737ebe4f" />
<PETimeStamp value="0x48C330DF" />
<Offsets>
</Base>
<Version name="40d" base="DF40d.xx" os="windows">
<MD5 value="2c686c26307dcccd7c36cc79737ebe4f" />
<PETimeStamp value="0x48C330DF" />
<Offsets>
<Group name="vector">
<HexValue name="sizeof" value="0x10" />
<Offset name="start" value="0x4" />
<!--
Maybe (fits offsets):
Maybe (fits offsets):
Vector layout in MSVC 8:
DWORD Allocator?
DWORD Start
@ -61,8 +61,8 @@
<Offset name="nick" value="0x1C" />
<Offset name="second_words" value="0x38" />
</Group>
</Offsets>
</Version>
</Offsets>
</Version>
<Base name="DF2010">
<Traits>
<Trait name="Nervousness" id="0" level_5="Is a nervous wreck" level_4="Is always tense and jittery" level_3="Is often nervous" level_2="Has a calm demeanor" level_1="Has a very calm demeanor" level_0="Has an incredibly calm demeanor" />
@ -870,7 +870,7 @@
<Offset name="flags2" description="Second set of flags" />
<Offset name="caste" description="Caste of the creature. Same as sex most of the time." />
<Offset name="sex" description="Sex of the creature." />
<Offset name="id" description="Unique ID of the creature, probably index into some global vector.." />
<Offset name="id" description="Unique ID of the creature, seems to be used for binary search in the creature vector." />
<Offset name="civ" description="What civ the creature belongs to." />
<Group name="advanced">
<Offset name="pickup_equipment_bit" description="Setting this makes creatures re-check the status of their equip." />
@ -995,7 +995,9 @@
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
<Offset name="item_wear_accessor" />
<Offset name="item_ref_vector" description="Contains the owner among other things"/>
<Offset name="owner_ref_id_field" description="Creature ID offset in general_ref_unit_itemownerst"/>
</Group>
<Group name="World">
<Address name="current_tick" description="Current time of the year" />
@ -1914,33 +1916,12 @@
<Address name="language_vector" value="0x016e553c"/>
<Address name="translation_vector" value="0x016e551c"/>
</Group>
<!--
<Group name="Vegetation" valid="false">
<Address name="vector"/>
<Offset name="tree_desc_offset" valid="true"/>
</Group>
-->
<Group name="Items" valid="false">
<!-- most of those seem completely unused! -->
<Address name="items_vector" />
List of offsets in the VTable :
<Offset name="item_type_accessor" />
<Offset name="item_subtype_accessor" />
<Offset name="item_subindex_accessor" />
<Offset name="item_index_accessor" />
<Offset name="item_quality_accessor" />
<Offset name="item_improvement_vector" />
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
</Group>
<Group name="Items" valid="false" />
<Group name="World" valid="false">
<Address name="current_tick" description="Current time of the year" />
<Address name="current_year" description="Current year" />
<Address name="current_weather" value="0x14c9bb8" valid="true" />
</Group>
</Offsets>
</Version>
<Version name="v0.31.19 SDL" os="windows" base="v0.31.18 SDL">
@ -1964,10 +1945,6 @@
<Group name="creature">
<Group name="advanced">
<!--
<Offset name="pregnancy" value="0x214" /> maybe?
<Offset name="pregnancy_ptr" value="0x218" /> maybe?
-->
<Offset name="birth_year" value="0x224" />
<Offset name="birth_time" value="0x228" />
<Offset name="inventory_vector" value="0x288" />
@ -1984,15 +1961,6 @@
</Group>
<Group name="job" valid="false">
<Offset name="id" valid="true" />
<Offset name="materials_vector" /> MISSING!
<Offset name="type" /> MISSING!
<Group name="material">
<Offset name="flags" /> MISSING!
<Offset name="maintype" /> MISSING!
<Offset name="sectype1" /> MISSING!
<Offset name="sectype2" /> MISSING!
<Offset name="sectype3" /> MISSING!
</Group>
</Group>
</Group>
<Group name="Maps" valid="true">
@ -2074,22 +2042,6 @@
<Address name="language_vector" value="0x0171ea94"/>
<Address name="translation_vector" value="0x0171eab4"/>
</Group>
<!--
<Group name="Items" valid="false">
<Address name="items_vector" />
List of offsets in the VTable :
<Offset name="item_type_accessor" />
<Offset name="item_subtype_accessor" />
<Offset name="item_subindex_accessor" />
<Offset name="item_index_accessor" />
<Offset name="item_quality_accessor" />
<Offset name="item_improvement_vector" />
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
</Group>
-->
</Offsets>
</Version>
<Version name="v0.31.20 SDL" os="windows" base="v0.31.19 SDL" rebase="0x6000" >
@ -2179,11 +2131,6 @@
</Group>
<Group name="Maps">
<Group name="block">
<!--
<Offset name="vein_vector" value="0x8" />
<Offset name="feature_local" value="0x24" />
<Offset name="feature_global" value="0x28" />
-->
<Offset name="mystery_offset" value="0x2C" />
<Offset name="vegetation_vector" value="0x64" />
<Offset name="type" value="0x7e" />
@ -2948,6 +2895,17 @@
<Address name="control_mode" value="0x8c3de90" />
<Address name="game_mode" value="0x8c3deA0" />
</Group>
<Group name="Items">
<Address name="items_vector" value="0x940b1fc" />
<Offset name="item_type_accessor" value="0x0" />
<Offset name="item_subtype_accessor" value="0x4" />
<Offset name="item_subindex_accessor" value="0x8" />
<Offset name="item_index_accessor" value="0xC" />
<Offset name="item_quality_accessor" value="0x25C" />
<Offset name="item_wear_accessor" value="0xCC" />
<Offset name="item_ref_vector" value="0x24" />
<Offset name="owner_ref_id_field" value="0x4" />
</Group>
</Offsets>
</Version>
</DFHack>

@ -319,6 +319,17 @@ uint32_t OffsetGroup::getAddress (const string & key)
throw Error::MissingMemoryDefinition("address", getFullName() + key);
}
// Get named offset, return bool instead of throwing exceptions
bool OffsetGroup::getSafeAddress (const string & key, uint32_t & out)
{
uint32_Iter iter = OGd->addresses.find(key);
if(iter != OGd->addresses.end() && (*iter).second.first == IS_VALID)
{
out = (*iter).second.second;
return true;
}
return false;
}
// Get named offset
int32_t OffsetGroup::getOffset (const string & key)
@ -335,6 +346,18 @@ int32_t OffsetGroup::getOffset (const string & key)
throw Error::MissingMemoryDefinition("offset", getFullName() + key);
}
// Get named offset, return bool instead of throwing exceptions
bool OffsetGroup::getSafeOffset (const string & key, int32_t & out)
{
int32_Iter iter = OGd->offsets.find(key);
if(iter != OGd->offsets.end() && (*iter).second.first == IS_VALID)
{
out = (*iter).second.second;
return true;
}
return false;
}
// Get named numerical value
uint32_t OffsetGroup::getHexValue (const string & key)

@ -37,9 +37,9 @@ extern "C" {
DFHACK_EXPORT int Items_Start(DFHackObject* items);
DFHACK_EXPORT int Items_Finish(DFHackObject* items);
DFHACK_EXPORT char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObject* mats);
DFHACK_EXPORT char* Items_getItemDescription(DFHackObject* items, dfh_item* item, DFHackObject* mats);
DFHACK_EXPORT char* Items_getItemClass(DFHackObject* items, int32_t index);
DFHACK_EXPORT int Items_getItemData(DFHackObject* items, uint32_t itemptr, t_item* item);
DFHACK_EXPORT int Items_getItemData(DFHackObject* items, uint32_t itemptr, dfh_item* item);
#ifdef __cplusplus
}

@ -106,73 +106,6 @@ struct t_name
bool has_name;
};
//raw
struct t_item_df40d
{
uint32_t vtable;
uint16_t x;
uint16_t y;
uint16_t z;
uint32_t flags;
uint32_t unk1;
uint32_t unk2;
uint32_t ID;
// not complete
};
//From http://dwarffortresswiki.net/index.php/User:Rick/Memory_research
//They all seem to be valid on 40d as well
struct naked_itemflags
{
unsigned int on_ground : 1; // Item on ground
unsigned int in_job : 1; // item currently being used in a job
unsigned int in_inventory : 1; // Item in a creatures inventory
unsigned int u_ngrd1 : 1; // only occurs when not on ground, unknown function
unsigned int in_workshop : 1; // Item is in a workshops inventory
unsigned int u_ngrd2 : 1; // only occurs when not on ground, unknown function
unsigned int u_ngrd3 : 1; // only occurs when not on ground, unknown function
unsigned int rotten : 1; // Item is rotten
unsigned int unk1 : 1; // unknown function
unsigned int u_ngrd4 : 1; // only occurs when not on ground, unknown function
unsigned int unk2 : 1; // unknown function
unsigned int u_ngrd5 : 1; // only occurs when not on ground, unknown function
unsigned int unk3 : 1; // unknown function
unsigned int u_ngrd6 : 1; // only occurs when not on ground, unknown function
unsigned int narrow : 1; // Item is narrow
unsigned int u_ngrd7 : 1; // only occurs when not on ground, unknown function
unsigned int worn : 1; // item shows wear
unsigned int unk4 : 1; // unknown function
unsigned int u_ngrd8 : 1; // only occurs when not on ground, unknown function
unsigned int forbid : 1; // designate forbid item
unsigned int unk5 : 1; // unknown function
unsigned int dump : 1; // designate dump item
unsigned int on_fire: 1; //indicates if item is on fire, Will Set Item On Fire if Set!
unsigned int melt : 1; // designate melt item, if item cannot be melted, does nothing it seems
// 0100 0000 - 8000 0000
unsigned int hidden : 1; // designate hide item
unsigned int u_ngrd9 : 1; // only occurs when not on ground, unknown function
unsigned int unk6 : 1; // unknown function
unsigned int unk7 : 1; // unknown function
unsigned int unk8 : 1; // unknown function
unsigned int unk9 : 1; // unknown function
unsigned int unk10 : 1; // unknown function
unsigned int unk11 : 1; // unknown function
};
union t_itemflags
{
uint32_t whole;
naked_itemflags bits;
};
struct t_note
{
char symbol;
@ -197,7 +130,7 @@ struct t_settlement
int16_t local_y1;
int16_t local_y2;
};
struct t_attrib
{
uint32_t level;

@ -77,6 +77,9 @@ namespace DFHack
std::string getString (const std::string & key);
OffsetGroup * getGroup ( const std::string & name );
bool getSafeOffset (const std::string & key, int32_t & out);
bool getSafeAddress (const std::string & key, uint32_t & out);
void setOffset (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setOffsetValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
void setAddress (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);

@ -321,6 +321,8 @@ namespace DFHack
bool ReadInventoryIdx(const uint32_t index, std::vector<uint32_t> & item);
bool ReadInventoryPtr(const uint32_t index, std::vector<uint32_t> & item);
int32_t FindIndexById(int32_t id);
/* Getters */
uint32_t GetDwarfRaceIndex ( void );
int32_t GetDwarfCivId ( void );

@ -3,23 +3,105 @@
#define CL_MOD_ITEMS
/*
* Creatures
* Items!
*/
#include "dfhack/DFExport.h"
#include "dfhack/DFModule.h"
#include "dfhack/DFTypes.h"
namespace DFHack
{
class Context;
class DFContextShared;
//From http://dwarffortresswiki.net/index.php/User:Rick/Memory_research
//They all seem to be valid on 40d as well
union t_itemflags
{
uint32_t whole;
struct
{
unsigned int on_ground : 1; // 0000 0001 Item on ground
unsigned int in_job : 1; // 0000 0002 Item currently being used in a job
unsigned int u_ngrd1 : 1; // 0000 0004 unknown, unseen
unsigned int in_inventory : 1; // 0000 0008 Item in a creature or workshop inventory
unsigned int u_ngrd2 : 1; // 0000 0010 unknown, lost (artifact)?, unseen
unsigned int in_building : 1; // 0000 0020 Part of a building (including mechanisms, bodies in coffins)
unsigned int u_ngrd3 : 1; // 0000 0040 unknown, unseen
unsigned int dead_dwarf : 1; // 0000 0080 Dwarf's dead body or body part
unsigned int rotten : 1; // 0000 0100 Rotten food
unsigned int spider_web : 1; // 0000 0200 Thread in spider web
unsigned int construction : 1; // 0000 0400 Material used in construction
unsigned int u_ngrd5 : 1; // 0000 0800 unknown, unseen
unsigned int unk3 : 1; // 0000 1000 unknown, unseen
unsigned int u_ngrd6 : 1; // 0000 2000 unknown, unseen
unsigned int foreign : 1; // 0000 4000 Item is imported
unsigned int u_ngrd7 : 1; // 0000 8000 unknown, unseen
unsigned int owned : 1; // 0001 0000 Item is owned by a dwarf
unsigned int unk4 : 1; // 0002 0000 unknown, unseen
unsigned int artifact1 : 1; // 0004 0000 Artifact ?
unsigned int forbid : 1; // 0008 0000 Forbidden item
unsigned int unk5 : 1; // 0010 0000 unknown, unseen
unsigned int dump : 1; // 0020 0000 Designated for dumping
unsigned int on_fire: 1; // 0040 0000 Indicates if item is on fire, Will Set Item On Fire if Set!
unsigned int melt : 1; // 0080 0000 Designated for melting, if applicable
// 0100 0000 - 8000 0000
unsigned int hidden : 1; // 0100 0000 Hidden item
unsigned int in_chest : 1; // 0200 0000 Stored in chest/part of well?
unsigned int unk6 : 1; // 0400 0000 unknown, unseen
unsigned int artifact2 : 1; // 0800 0000 Artifact ?
unsigned int unk8 : 1; // 1000 0000 unknown, unseen
unsigned int unk9 : 1; // 2000 0000 unknown, set when viewing details
unsigned int unk10 : 1; // 4000 0000 unknown, unseen
unsigned int unk11 : 1; // 8000 0000 unknown, unseen
};
};
struct t_item
{
uint32_t vtable;
int16_t x;
int16_t y;
int16_t z;
t_itemflags flags;
};
struct dfh_item
{
t_item base;
t_material matdesc;
int32_t quantity;
int32_t quality;
int16_t wear_level;
uint32_t origin;
};
/*
//raw
struct t_item_df40d
{
uint32_t vtable;
uint16_t x;
uint16_t y;
uint16_t z;
uint32_t flags;
uint32_t unk1;
uint32_t unk2;
uint32_t ID;
// not complete
};
*/
struct t_improvement
{
t_material matdesc;
@ -33,9 +115,16 @@ public:
~Items();
bool Start();
bool Finish();
std::string getItemDescription(uint32_t itemptr, Materials * Materials);
/// get a string describing an item
std::string getItemDescription(const dfh_item & item, Materials * Materials);
/// get a short name for an item
std::string getItemClass(int32_t index);
bool getItemData(uint32_t itemptr, t_item & item);
/// read an item, including the extra attributes
bool readItem(uint32_t itemptr, dfh_item & item);
/// write item base (position and flags only = t_item part of dfh_item)
bool writeItem(const dfh_item & item);
/// who owns this item we already read?
int32_t getItemOwnerID(const dfh_item & item);
private:
class Private;
Private* d;

@ -106,6 +106,8 @@ struct Creatures::Private
uint32_t creature_module;
uint32_t dwarf_race_index_addr;
uint32_t dwarf_civ_id_addr;
bool IdMapReady;
std::map<int32_t, int32_t> IdMap;
DfVector <uint32_t> *p_cre;
DFContextShared *d;
Process *owner;
@ -123,6 +125,7 @@ Creatures::Creatures(DFContextShared* _d)
d->owner = _d->p;
d->Inited = false;
d->Started = false;
d->IdMapReady = false;
d->p_cre = NULL;
d->d->InitReadNames(); // throws on error
VersionInfo * minfo = d->d->offset_descriptor;
@ -228,6 +231,7 @@ bool Creatures::Start( uint32_t &numcreatures )
d->p_cre = new DfVector <uint32_t> (d->owner, d->creatures.vector);
d->Started = true;
numcreatures = d->p_cre->size();
d->IdMapReady = false;
return true;
}
return false;
@ -407,6 +411,35 @@ int32_t Creatures::ReadCreatureInBox (int32_t index, t_creature & furball,
return -1;
}
int32_t Creatures::FindIndexById(int32_t creature_id)
{
if (!d->Started || !d->Ft_basic)
return -1;
if (!d->IdMapReady)
{
d->IdMap.clear();
Process * p = d->owner;
Private::t_offsets &offs = d->creatures;
uint32_t size = d->p_cre->size();
for (uint32_t index = 0; index < size; index++)
{
uint32_t temp = d->p_cre->at(index);
int32_t id = p->readDWord (temp + offs.id_offset);
d->IdMap[id] = index;
}
}
std::map<int32_t,int32_t>::iterator it;
it = d->IdMap.find(creature_id);
if(it == d->IdMap.end())
return -1;
else
return it->second;
}
bool Creatures::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS])
{
if(!d->Started || !d->Ft_advanced) return false;

@ -51,13 +51,19 @@ enum accessor_type {ACCESSOR_CONSTANT, ACCESSOR_INDIRECT, ACCESSOR_DOUBLE_INDIRE
/* this is used to store data about the way accessors work */
class DFHACK_EXPORT Accessor
{
public:
enum DataWidth {
Data32 = 0,
DataSigned16,
DataUnsigned16
};
private:
accessor_type type;
int32_t constant;
uint32_t offset1;
uint32_t offset2;
int32_t offset1;
int32_t offset2;
Process * p;
uint32_t dataWidth;
DataWidth dataWidth;
public:
Accessor(uint32_t function, Process * p);
Accessor(accessor_type type, int32_t constant, uint32_t offset1, uint32_t offset2, uint32_t dataWidth, Process * p);
@ -84,100 +90,154 @@ private:
Accessor * ASubIndex;
Accessor * AIndex;
Accessor * AQuality;
Accessor * AWear;
Process * p;
bool hasDecoration;
public:
ItemDesc(uint32_t VTable, Process * p);
bool getItem(uint32_t itemptr, t_item & item);
bool readItem(uint32_t itemptr, dfh_item & item);
std::string className;
uint32_t vtable;
uint32_t mainType;
std::vector<ItemImprovementDesc> improvement;
};
inline bool do_match(uint32_t &ptr, uint64_t val, int size, uint64_t mask, uint64_t check)
{
if ((val & mask) == check) {
ptr += size;
return true;
}
return false;
}
static bool match_MEM_ACCESS(uint32_t &ptr, uint64_t v, int isize, int in_reg, int &out_reg, int &offset)
{
// ESP & EBP are hairy
if (in_reg == 4 || in_reg == 5)
return false;
if ((v & 7) != in_reg)
return false;
out_reg = (v>>3) & 7;
switch ((v>>6)&3) {
case 0: // MOV REG2, [REG]
offset = 0;
ptr += isize+1;
return true;
case 1: // MOV REG2, [REG+offset8]
offset = (signed char)(v >> 8);
ptr += isize+2;
return true;
case 2: // MOV REG2, [REG+offset32]
offset = (signed int)(v >> 8);
ptr += isize+5;
return true;
default:
return false;
}
}
static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, int &offset, Accessor::DataWidth &size)
{
int prefix = 0;
size = Accessor::Data32;
if ((v & 0xFF) == 0x8B) { // MOV
v >>= 8;
prefix = 1;
}
else if ((v & 0xFFFF) == 0x8B66) { // MOV 16-bit
v >>= 16;
prefix = 2;
size = Accessor::DataUnsigned16;
}
else if ((v & 0xFFFF) == 0xBF0F) { // MOVSX
v >>= 16;
prefix = 2;
size = Accessor::DataSigned16;
}
else if ((v & 0xFFFF) == 0xB70F) { // MOVZ
v >>= 16;
prefix = 2;
size = Accessor::DataUnsigned16;
}
else
return false;
return match_MEM_ACCESS(ptr, v, prefix, in_reg, out_reg, offset);
}
// FIXME: this is crazy
Accessor::Accessor(uint32_t function, Process *p)
{
this->p = p;
this->constant = 0;
this->offset1 = 0;
this->offset2 = 0;
this->type = ACCESSOR_CONSTANT;
this->dataWidth = 2;
uint64_t funcText = p->readQuad(function);
if( funcText == 0xCCCCCCCCCCC3C033LL )
if(!p)
{
this->constant = 0;
return;
}
if( funcText == 0xCCCCCCCCC3FFC883LL )
{
/* or eax,-1; ret; */
this->constant = -1;
return;
}
if( (funcText&0xFFFFFFFFFF0000FFLL) == 0xCCCCC300000000B8LL )
{
/* mov eax, xx; ret; */
this->constant = (funcText>>8) & 0xffff;
return;
}
if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC300000000818B66LL )
uint32_t ptr = function;
int data_reg = -1;
uint64_t v = p->readQuad(ptr);
if (do_match(ptr, v, 2, 0xFFFF, 0xC033) ||
do_match(ptr, v, 2, 0xFFFF, 0xC031)) // XOR EAX, EAX
{
/* mov ax, [ecx+xx]; ret; */
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>24) & 0xffff;
return;
data_reg = 0;
this->constant = 0;
}
if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
else if (do_match(ptr, v, 3, 0xFFFFFF, 0xFFC883)) // OR EAX, -1
{
/* mov ax, [ecx+xx]; ret; (shorter instruction)*/
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>24) & 0xff;
return;
data_reg = 0;
this->constant = -1;
}
if( (funcText&0x00000000FF00FFFFLL) == 0x00000000C300418BLL )
else if (do_match(ptr, v, 5, 0xFF, 0xB8)) // MOV EAX,imm
{
/* mov eax, [ecx+xx]; ret; */
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>16) & 0xff;
this->dataWidth = 4;
return;
data_reg = 0;
this->constant = (v>>8) & 0xFFFFFFFF;
}
if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL )
else
{
uint64_t funcText2 = p->readQuad(function+8);
if( (funcText2&0xFFFFFFFFFFFF00FFLL) == 0xCCCCCCCCCCC30040LL )
DataWidth xsize;
int ptr_reg = 1, tmp; // ECX
// MOV REG,[ESP+4]
if (do_match(ptr, v, 4, 0xFFFFC7FFU, 0x0424448B))
{
this->type = ACCESSOR_DOUBLE_INDIRECT;
this->offset1 = (funcText>>16) & 0xffff;
this->offset2 = (funcText2>>8) & 0xff;
return;
ptr_reg = (v>>11)&7;
v = p->readQuad(ptr);
}
if (match_MOV_MEM(ptr, v, ptr_reg, tmp, this->offset1, xsize)) {
data_reg = tmp;
this->type = ACCESSOR_INDIRECT;
this->dataWidth = xsize;
if (xsize == Data32)
{
v = p->readQuad(ptr);
if (match_MOV_MEM(ptr, v, data_reg, tmp, this->offset2, xsize)) {
data_reg = tmp;
this->type = ACCESSOR_DOUBLE_INDIRECT;
this->dataWidth = xsize;
}
}
}
}
if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL )
{
/* movsx eax, word ptr [ecx+xx]; ret */
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>24) & 0xffff;
return;
}
if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL )
{
/* movsx eax, word ptr [ecx+xx]; ret (shorter opcode)*/
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>24) & 0xff;
v = p->readQuad(ptr);
if (data_reg == 0 && do_match(ptr, v, 1, 0xFF, 0xC3)) // RET
return;
}
if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL )
else
{
/* mov eax, [ecx+xx]; ret; */
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>16) & 0xffff;
this->dataWidth = 4;
return;
this->type = ACCESSOR_CONSTANT;
this->constant = 0;
printf("bad accessor @0x%x\n", function);
}
printf("bad accessor @0x%x\n", function);
}
bool Accessor::isConstant()
@ -190,29 +250,26 @@ bool Accessor::isConstant()
int32_t Accessor::getValue(uint32_t objectPtr)
{
int32_t offset = this->offset1;
switch(this->type)
{
case ACCESSOR_CONSTANT:
return this->constant;
break;
case ACCESSOR_INDIRECT:
switch(this->dataWidth)
{
case 2:
return (int16_t) p->readWord(objectPtr + this->offset1);
case 4:
return p->readDWord(objectPtr + this->offset1);
default:
return -1;
}
break;
case ACCESSOR_DOUBLE_INDIRECT:
objectPtr = p->readDWord(objectPtr + this->offset1);
offset = this->offset2;
// fallthrough
case ACCESSOR_INDIRECT:
switch(this->dataWidth)
{
case 2:
return (int16_t) p->readWord(p->readDWord(objectPtr + this->offset1) + this->offset2);
case 4:
return p->readDWord(p->readDWord(objectPtr + this->offset1) + this->offset2);
case Data32:
return p->readDWord(objectPtr + offset);
case DataSigned16:
return (int16_t) p->readWord(objectPtr + offset);
case DataUnsigned16:
return (uint16_t) p->readWord(objectPtr + offset);
default:
return -1;
}
@ -222,41 +279,65 @@ int32_t Accessor::getValue(uint32_t objectPtr)
}
}
// FIXME: turn into a proper factory with caching
Accessor * buildAccessor (OffsetGroup * I, Process * p, const char * name, uint32_t vtable)
{
int32_t offset;
if(I->getSafeOffset("item_type_accessor",offset))
return new Accessor( p->readDWord( vtable + offset ), p);
else
{
fprintf(stderr,"Missing offset for item accessor \"%s\"\n", name);
return new Accessor(-1,0); // dummy accessor. always returns -1
}
}
ItemDesc::ItemDesc(uint32_t VTable, Process *p)
{
int32_t funcOffsetA, funcOffsetB, funcOffsetC, funcOffsetD, funcOffsetQuality, funcOffsetWear;
OffsetGroup * Items = p->getDescriptor()->getGroup("Items");
uint32_t funcOffsetA = Items->getOffset("item_type_accessor");
uint32_t funcOffsetB = Items->getOffset("item_subtype_accessor");
uint32_t funcOffsetC = Items->getOffset("item_subindex_accessor");
uint32_t funcOffsetD = Items->getOffset("item_index_accessor");
uint32_t funcOffsetQuality = Items->getOffset("item_quality_accessor");
/*
* FIXME: and what about types, different sets of methods depending on class?
* what about more complex things than constants and integers?
* If this is to be generally useful, it needs much more power.
*/
AMainType = buildAccessor(Items, p, "item_type_accessor", VTable);
ASubType = buildAccessor(Items, p, "item_subtype_accessor", VTable);
ASubIndex = buildAccessor(Items, p, "item_subindex_accessor", VTable);
AIndex = buildAccessor(Items, p, "item_index_accessor", VTable);
AQuality = buildAccessor(Items, p, "item_quality_accessor", VTable);
AWear = buildAccessor(Items, p, "item_wear_accessor", VTable);
this->vtable = VTable;
this->p = p;
this->className = p->readClassName(VTable).substr(5);
this->className.resize(this->className.size()-2);
this->AMainType = new Accessor( p->readDWord( VTable + funcOffsetA ), p);
this->ASubType = new Accessor( p->readDWord( VTable + funcOffsetB ), p);
this->ASubIndex = new Accessor( p->readDWord( VTable + funcOffsetC ), p);
this->AIndex = new Accessor( p->readDWord( VTable + funcOffsetD ), p);
this->AQuality = new Accessor( p->readDWord( VTable + funcOffsetQuality ), p);
this->hasDecoration = false;
if(this->AMainType->isConstant())
this->mainType = this->AMainType->getValue(0);
if(AMainType->isConstant())
mainType = this->AMainType->getValue(0);
else
{
fprintf(stderr, "Bad item main type at function %p\n", (void*) p->readDWord( VTable + funcOffsetA ));
this->mainType = 0;
mainType = 0;
}
}
bool ItemDesc::getItem(uint32_t itemptr, DFHack::t_item &item)
bool ItemDesc::readItem(uint32_t itemptr, DFHack::dfh_item &item)
{
item.matdesc.itemType = this->AMainType->getValue(itemptr);
item.matdesc.subType = this->ASubType->getValue(itemptr);
item.matdesc.subIndex = this->ASubIndex->getValue(itemptr);
item.matdesc.index = this->AIndex->getValue(itemptr);
item.quality = this->AQuality->getValue(itemptr);
p->read(itemptr, sizeof(t_item), (uint8_t*)&item.base);
item.matdesc.itemType = AMainType->getValue(itemptr);
item.matdesc.subType = ASubType->getValue(itemptr);
item.matdesc.subIndex = ASubIndex->getValue(itemptr);
item.matdesc.index = AIndex->getValue(itemptr);
item.quality = AQuality->getValue(itemptr);
item.quantity = 1; /* TODO */
item.origin = itemptr;
// FIXME: use templates. seriously.
// Note: this accessor returns a 32-bit value with the higher
// half sometimes containing garbage, so the cast is essential:
item.wear_level = (int16_t)this->AWear->getValue(itemptr);
return true;
}
@ -267,6 +348,9 @@ class Items::Private
Process * owner;
std::map<int32_t, ItemDesc *> descType;
std::map<uint32_t, ItemDesc *> descVTable;
uint32_t refVectorOffset;
uint32_t refIDOffset;
uint32_t ownerRefVTable;
};
Items::Items(DFContextShared * d_)
@ -274,6 +358,7 @@ Items::Items(DFContextShared * d_)
d = new Private;
d->d = d_;
d->owner = d_->p;
d->ownerRefVTable = d->refVectorOffset = d->refIDOffset = 0;
}
bool Items::Start()
@ -301,7 +386,7 @@ Items::~Items()
delete d;
}
bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item)
bool Items::readItem(uint32_t itemptr, DFHack::dfh_item &item)
{
std::map<uint32_t, ItemDesc *>::iterator it;
Process * p = d->owner;
@ -318,7 +403,57 @@ bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item)
else
desc = it->second;
return desc->getItem(itemptr, item);
return desc->readItem(itemptr, item);
}
bool Items::writeItem(const DFHack::dfh_item &item)
{
if(item.origin)
{
d->owner->write(item.origin, sizeof(t_item),(uint8_t *)&(item.base));
return true;
}
return false;
}
/*
void Items::setItemFlags(uint32_t itemptr, t_itemflags new_flags)
{
d->owner->writeDWord(itemptr + 0x0C, new_flags.whole);
}
*/
int32_t Items::getItemOwnerID(const DFHack::dfh_item &item)
{
if (!d->refVectorOffset)
{
OffsetGroup * Items = d->owner->getDescriptor()->getGroup("Items");
d->refVectorOffset = Items->getOffset("item_ref_vector");
d->refIDOffset = Items->getOffset("owner_ref_id_field");
}
DFHack::DfVector<uint32_t> p_refs(d->owner, item.origin + d->refVectorOffset);
uint32_t size = p_refs.size();
for (uint32_t i=0;i<size;i++)
{
uint32_t curRef = p_refs[i];
uint32_t vtbl = d->owner->readDWord(curRef);
if (!d->ownerRefVTable)
{
std::string className = d->owner->readClassName(vtbl);
if (className == "general_ref_unit_itemownerst")
d->ownerRefVTable = vtbl;
else
continue;
}
else if (d->ownerRefVTable != vtbl)
continue;
return d->owner->readDWord(curRef + d->refIDOffset);
}
return -1;
}
std::string Items::getItemClass(int32_t index)
@ -348,8 +483,9 @@ std::string Items::getItemClass(int32_t index)
return out;
}
std::string Items::getItemDescription(uint32_t itemptr, Materials * Materials)
std::string Items::getItemDescription(const dfh_item & item, Materials * Materials)
{
/*
DFHack::t_item item;
std::string out;
@ -368,128 +504,7 @@ std::string Items::getItemDescription(uint32_t itemptr, Materials * Materials)
out.append(Materials->getDescription(item.matdesc));
out.append(" ");
out.append(this->getItemClass(item.matdesc.itemType));
return out;
}
// The OLD items code follows (40d era)
// TODO: merge with the current Items module
/*
bool API::InitReadItems(uint32_t & numitems)
{
try
{
int items = d->offset_descriptor->getAddress ("items");
d->item_material_offset = d->offset_descriptor->getOffset ("item_materials");
d->p_itm = new DfVector (d->p, items);
d->itemsInited = true;
numitems = d->p_itm->getSize();
return true;
}
catch (Error::AllMemdef&)
{
d->itemsInited = false;
numitems = 0;
throw;
}
}
bool API::getItemIndexesInBox(vector<uint32_t> &indexes,
const uint16_t x1, const uint16_t y1, const uint16_t z1,
const uint16_t x2, const uint16_t y2, const uint16_t z2)
{
if(!d->itemsInited) return false;
indexes.clear();
uint32_t size = d->p_itm->getSize();
struct temp2{
uint16_t coords[3];
uint32_t flags;
};
temp2 temp2;
for(uint32_t i =0;i<size;i++){
uint32_t temp = d->p_itm->at(i);
d->p->read(temp+sizeof(uint32_t),5 * sizeof(uint16_t), (uint8_t *) &temp2);
if(temp2.flags & (1 << 0)){
if (temp2.coords[0] >= x1 && temp2.coords[0] < x2)
{
if (temp2.coords[1] >= y1 && temp2.coords[1] < y2)
{
if (temp2.coords[2] >= z1 && temp2.coords[2] < z2)
{
indexes.push_back(i);
}
}
}
}
}
return true;
}
bool API::ReadItem (const uint32_t index, t_item & item)
{
if (!d->itemsInited) return false;
t_item_df40d item_40d;
// read pointer from vector at position
uint32_t temp = d->p_itm->at (index);
//read building from memory
d->p->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d);
// transform
int32_t type = -1;
d->offset_descriptor->resolveObjectToClassID (temp, type);
item.origin = temp;
item.vtable = item_40d.vtable;
item.x = item_40d.x;
item.y = item_40d.y;
item.z = item_40d.z;
item.type = type;
item.ID = item_40d.ID;
item.flags.whole = item_40d.flags;
//TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68
d->p->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material);
//for(int i = 0; i < 0xCC; i++){ // used for item research
// uint8_t byte = MreadByte(temp+i);
// item.bytes.push_back(byte);
//}
return true;
}
void API::FinishReadItems()
{
if(d->p_itm)
{
delete d->p_itm;
d->p_itm = NULL;
}
d->itemsInited = false;
}
*/
/*
bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
{
memory_info * minfo = d->offset_descriptor;
int matgloss_address = minfo->getAddress("matgloss");
int matgloss_skip = minfo->getHexValue("matgloss_skip");
int item_type_name_offset = minfo->getOffset("item_type_name");
for(int i = 8;i<20;i++)
{
DfVector p_temp (d->p, matgloss_address + i*matgloss_skip);
vector< t_itemType > typesForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
t_itemType currType;
uint32_t temp = *(uint32_t *) p_temp[j];
// Mread(temp+40,sizeof(name),(uint8_t *) name);
d->p->readSTLString(temp+4,currType.id,128);
d->p->readSTLString(temp+item_type_name_offset,currType.name,128);
//stringsForVec.push_back(string(name));
typesForVec.push_back(currType);
}
itemTypes.push_back(typesForVec);
}
return true;
*/
//return out;
return getItemClass(item.matdesc.itemType);
}
*/

@ -54,11 +54,11 @@ int Items_Finish(DFHackObject* items)
//FIXME: beware of bad null-termination! I haven't tested anything here, but it seems that it could be corrupting or truncating strings.
char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObject* mats)
char* Items_getItemDescription(DFHackObject* items, dfh_item * item, DFHackObject* mats)
{
if(items != NULL && mats != NULL)
{
std::string desc = ((DFHack::Items*)items)->getItemDescription(itemptr, (DFHack::Materials*)mats);
std::string desc = ((DFHack::Items*)items)->getItemDescription(*item, (DFHack::Materials*)mats);
if(desc.size() > 0)
{
@ -112,11 +112,11 @@ char* Items_getItemClass(DFHackObject* items, int32_t index)
return NULL;
}
int Items_getItemData(DFHackObject* items, uint32_t itemptr, t_item* item)
int Items_getItemData(DFHackObject* items, uint32_t itemptr, dfh_item* item)
{
if(items != NULL)
{
return ((DFHack::Items*)items)->getItemData(itemptr, *item);
return ((DFHack::Items*)items)->readItem(itemptr, *item);
}
return -1;

@ -544,50 +544,50 @@ std::string Materials::getDescription(t_material & mat)
//type of material only so we know which vector to retrieve
std::string Materials::getType(t_material & mat)
{
if((mat.subIndex<419) || (mat.subIndex>618))
{
if((mat.subIndex<19) || (mat.subIndex>218))
{
if(mat.subIndex)
{
if(mat.subIndex>0x292)
{
return "unknown";
}
else
{
if(mat.subIndex>=this->other.size())
{
if(mat.subIndex<0)
return "any";
if(mat.subIndex>=this->raceEx.size())
return "unknown";
return "racex";
}
else
{
if (mat.index==-1)
return "other";
else
return "other derivate";
}
}
}
else
return "inorganic";
}
else
{
if (mat.index>=this->raceEx.size())
return "unknown";
return "racex extract";
}
}
else
{
return "organic";
}
if((mat.subIndex<419) || (mat.subIndex>618))
{
if((mat.subIndex<19) || (mat.subIndex>218))
{
if(mat.subIndex)
{
if(mat.subIndex>0x292)
{
return "unknown";
}
else
{
if(mat.subIndex>=this->other.size())
{
if(mat.subIndex<0)
return "any";
if(mat.subIndex>=this->raceEx.size())
return "unknown";
return "racex";
}
else
{
if (mat.index==-1)
return "other";
else
return "other derivate";
}
}
}
else
return "inorganic";
}
else
{
if (mat.index>=this->raceEx.size())
return "unknown";
return "racex extract";
}
}
else
{
return "organic";
}
}

@ -1,28 +1,19 @@
/*
* dumps vtables, items types and class name for all items in game
* best used this way : ./dfitemdump | sort -ug
* Simple, pretty item dump example.
*/
// THIS IS NOT A GOOD EXAMPLE!
// ... just look at all the magic numbers.
// I'm not fixing it though.
// ~px
#include <stdio.h>
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <climits>
#include <vector>
#include <cstring>
using namespace std;
#include <DFHack.h>
#include <dfhack/DFVector.h>
DFHack::Materials * Materials;
DFHack::Items * Items;
int main ()
{
DFHack::Process * p;
@ -42,17 +33,36 @@ int main ()
#endif
return 1;
}
DFHack::Materials * Materials = DF->getMaterials();
Materials->ReadAllMaterials();
DFHack::Items * Items = DF->getItems();
Items->Start();
DFHack::VersionInfo * mem = DF->getMemoryInfo();
Materials = DF->getMaterials();
Materials->ReadAllMaterials();
p = DF->getProcess();
// FIXME: tools should never be exposed to DFHack internals!
DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
DFHack::DfVector <uint32_t> p_items (p, itemGroup->getAddress("items_vector"));
uint32_t size = p_items.size();
Items = DF->getItems();
for(int i = 0; i < size; i++)
{
DFHack::dfh_item itm;
memset(&itm, 0, sizeof(DFHack::dfh_item));
Items->readItem(p_items[i],itm);
printf(
"%5d: %08x %08x (%d,%d,%d) #%08x [%d] %s - %s\n",
i, itm.origin, itm.base.flags.whole,
itm.base.x, itm.base.y, itm.base.z,
itm.base.vtable,
itm.wear_level,
Items->getItemClass(itm.matdesc.itemType).c_str(),
Items->getItemDescription(itm, Materials).c_str()
);
}
/*
printf("type\tvtable\tname\tquality\tdecorate\n");
for (i=0;i<size;i++)
{
@ -78,9 +88,9 @@ int main ()
uint32_t quality = 0;
bool hasDecorations;
string desc = p->readClassName(vtable);
DFHack::t_item itm;
DFHack::dfh_item itm;
Items->getItemData(p_items[i], itm);
Items->readItem(p_items[i], itm);
if ( (funct0&0xFFFFFFFFFF000000LL) != 0xCCCCC30000000000LL )
{
@ -226,7 +236,7 @@ int main ()
}
printf("\n");
}
*/
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();

@ -86,6 +86,8 @@ DFHACK_TOOL(dfhellhole hellhole.cpp)
# Allows mass-modify, esp. for all immigrants
DFHACK_TOOL(dfskillmodify skillmodify.cpp)
DFHACK_TOOL(dfcleanowned cleanowned.cpp)
# this needs the C bindings
IF(BUILD_DFHACK_C_BINDINGS)
# The C bindings won't be real C bindings until this compiles.

@ -0,0 +1,176 @@
/*
* Confiscates and dumps garbage owned by dwarfs.
*/
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <climits>
#include <vector>
using namespace std;
#include <DFHack.h>
#include <dfhack/DFVector.h>
#include <dfhack/DFTypes.h>
int main (int argc, char *argv[])
{
bool dump_scattered = false;
bool confiscate_all = false;
bool dry_run = false;
int wear_dump_level = 65536;
for(int i = 1; i < argc; i++)
{
char *arg = argv[i];
if (arg[0] != '-')
continue;
for (; *arg; arg++) {
switch (arg[0]) {
case 'd':
dry_run = true;
break;
case 'l':
dump_scattered = true;
break;
case 'a':
confiscate_all = true;
break;
case 'x':
wear_dump_level = 1;
break;
case 'X':
wear_dump_level = 2;
break;
}
}
}
DFHack::Process * p;
unsigned int i,j;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF;
try
{
DF = DFMgr.getSingleContext();
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::VersionInfo * mem = DF->getMemoryInfo();
DFHack::Materials *Materials = DF->getMaterials();
DFHack::Items *Items = DF->getItems();
DFHack::Creatures *Creatures = DF->getCreatures();
DFHack::Translation *Tran = DF->getTranslation();
Materials->ReadAllMaterials();
uint32_t num_creatures;
Creatures->Start(num_creatures);
Tran->Start();
p = DF->getProcess();
DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
unsigned vector_addr = itemGroup->getAddress("items_vector");
DFHack::DfVector <uint32_t> p_items (p, vector_addr);
uint32_t size = p_items.size();
printf("Found total %d items.\n", size);
for (i=0;i<size;i++)
{
uint32_t curItem = p_items[i];
DFHack::dfh_item itm;
Items->readItem(curItem, itm);
if (!itm.base.flags.owned)
continue;
bool confiscate = false;
bool dump = false;
if (itm.base.flags.rotten)
{
printf("Confiscating a rotten item: \t");
confiscate = true;
}
else if (itm.wear_level >= wear_dump_level)
{
printf("Confiscating and dumping a worn item: \t");
confiscate = true;
dump = true;
}
else if (dump_scattered && itm.base.flags.on_ground)
{
printf("Confiscating and dumping litter: \t");
confiscate = true;
dump = true;
}
else if (confiscate_all)
{
printf("Confiscating: \t");
confiscate = true;
}
if (confiscate)
{
itm.base.flags.owned = 0;
if (dump)
itm.base.flags.dump = 1;
if (!dry_run)
Items->writeItem(itm);
printf(
"%s (wear %d)",
Items->getItemDescription(itm, Materials).c_str(),
itm.wear_level
);
int32_t owner = Items->getItemOwnerID(itm);
int32_t owner_index = Creatures->FindIndexById(owner);
std::string info;
if (owner_index >= 0)
{
DFHack::t_creature temp;
Creatures->ReadCreature(owner_index,temp);
temp.name.first_name[0] = toupper(temp.name.first_name[0]);
info = temp.name.first_name;
if (temp.name.nickname[0])
info += std::string(" '") + temp.name.nickname + "'";
info += " ";
info += Tran->TranslateName(temp.name,false);
printf(", owner %s", info.c_str());
}
printf("\n");
/*
printf(
"%5d: %08x %08x (%d,%d,%d) #%08x [%d] %s - %s %s\n",
i, itm.origin, itm.base.flags.whole,
itm.base.x, itm.base.y, itm.base.z,
itm.base.vtable,
itm.wear_level,
Items->getItemClass(itm.matdesc.itemType).c_str(),
Items->getItemDescription(itm, Materials).c_str(),
info.c_str()
);
*/
}
}
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}