Global, local feature reading in Maps

develop
Petr Mrázek 2010-04-24 01:15:15 +02:00
parent 9bd7a6ea9b
commit 8156469825
5 changed files with 311 additions and 49 deletions

@ -12,6 +12,36 @@ namespace DFHack
T Y P E S
***************************************************************************/
enum e_feature
{
feature_Adamantine_Tube,
feature_Underworld,
// add stuff here, don't reorder or delete
feature_Other = 10000,
};
union planecoord
{
uint32_t xy;
struct
{
uint16_t x;
uint16_t y;
} dim;
bool operator<(const planecoord &other) const
{
if(other.xy < xy) return true;
return false;
}
};
struct t_feature
{
e_feature type;
int16_t main_material;
int32_t sub_material;
bool discovered; // maybe, placeholder. should work for rivers in adventure mode
uint32_t origin;
};
struct t_vein
{
uint32_t vtable;
@ -210,6 +240,8 @@ namespace DFHack
biome_indices40d biome_indices;
uint32_t origin; // the address where it came from
t_blockflags blockflags;
int16_t global_feature;
int16_t local_feature;
} mapblock40d;
/***************************************************************************
@ -259,7 +291,14 @@ namespace DFHack
}
*/
bool ReadGeology( std::vector < std::vector <uint16_t> >& assign );
vector <t_feature> global_features;
// map between feature address and the read object
map <uint32_t, t_feature> local_feature_store;
// map between mangled coords and pointer to feature
bool ReadGlobalFeatures( std::vector <t_feature> & features);
bool ReadLocalFeatures( std::map <planecoord, std::vector<t_feature *> > & local_features );
/*
* BLOCK DATA
*/

@ -54,9 +54,136 @@ struct Maps::Private
Process * owner;
bool Inited;
bool Started;
vector <t_feature> global_features;
// map between feature address and the read object
map <uint32_t, t_feature> local_feature_store;
// map between mangled coords and pointer to feature
map <planecoord, vector<t_feature *> > local_features;
vector<uint16_t> v_geology[eBiomeCount];
};
bool Maps::ReadLocalFeatures( std::map <planecoord, std::vector<t_feature *> > & local_features )
{
Process * p = d->owner;
memory_info * mem = p->getDescriptor();
// deref pointer to the humongo-structure
uint32_t base = p->readDWord(mem->getAddress("local_feature_start_ptr"));
uint32_t sizeof_vec = mem->getHexValue("sizeof_vector");
const uint32_t sizeof_elem = 16;
const uint32_t offset_elem = 4;
local_features.clear();
for(uint blockX = 0; blockX < d->x_block_count; blockX ++)
for(uint blockY = 0; blockY < d->x_block_count; blockY ++)
{
//uint64_t block48_x = blockX / 3 + d->regionX;
//uint16_t region_x_plus8 = ( block48_x + 8 ) / 16;
// region X coord offset by 8 big blocks (48x48 tiles)
uint16_t region_x_plus8 = ( blockX / 3 + d->regionX + 8 ) / 16;
// plain region Y coord
uint64_t region_y_local = ( blockY / 3 + d->regionY ) / 16;
// this is just a few pointers to arrays of 16B (4 DWORD) structs
uint32_t array_elem = p->readDWord(base + (region_x_plus8 / 16) * 4);
// 16B structs, second DWORD of the struct is a pointer
uint32_t wtf = p->readDWord(array_elem + ( sizeof_elem * (region_y_local/16)) + offset_elem);
if(wtf)
{
// wtf + sizeof(vector<ptr>) * crap;
uint32_t feat_vector = wtf + sizeof_vec * (16 * (region_x_plus8 % 16) + (region_y_local % 16));
DfVector<uint32_t> p_features(p, feat_vector);
uint size = p_features.size();
planecoord pc;
pc.dim.x = blockX;
pc.dim.y = blockY;
std::vector<t_feature *> tempvec;
for(uint i = 0; i < size; i++)
{
uint32_t cur_ptr = p_features[i];
map <uint32_t, t_feature>::iterator it;
it = d->local_feature_store.find(cur_ptr);
// do we already have the feature?
if(it != d->local_feature_store.end())
{
// push pointer to existing feature
tempvec.push_back(&((*it).second));
}
// no?
else
{
// create, add to store
t_feature tftemp;
tftemp.discovered = p->readDWord(cur_ptr + 4);
tftemp.origin = cur_ptr;
string name = p->readClassName(p->readDWord( cur_ptr ));
if(name == "feature_init_deep_special_tubest")
{
tftemp.main_material = p->readWord( cur_ptr + 0x30 );
tftemp.sub_material = p->readDWord( cur_ptr + 0x34 );
tftemp.type = feature_Adamantine_Tube;
}
else
{
tftemp.main_material = -1;
tftemp.sub_material = -1;
tftemp.type = feature_Other;
}
d->local_feature_store[cur_ptr] = tftemp;
// push pointer
tempvec.push_back(&(d->local_feature_store[cur_ptr]));
}
}
local_features[pc] = tempvec;
}
}
return true;
}
bool Maps::ReadGlobalFeatures( std::vector <t_feature> & features)
{
Process * p = d->owner;
memory_info * mem = p->getDescriptor();
uint32_t global_feature_vector = mem->getAddress("global_feature_vector");
uint32_t global_feature_funcptr = mem->getOffset("global_feature_funcptr_");
DfVector<uint32_t> p_features (p,global_feature_vector);
features.clear();
uint size = p_features.size();
features.reserve(size);
for(uint i = 0; i < size; i++)
{
t_feature temp;
uint32_t feat_ptr = p->readDWord(p_features[i] + global_feature_funcptr );
temp.origin = feat_ptr;
temp.discovered = p->readDWord( feat_ptr + 4 ); // maybe, placeholder
// FIXME: use the memory_info cache mechanisms
string name = p->readClassName(p->readDWord( feat_ptr));
if(name == "feature_init_underworld_from_layerst")
{
temp.main_material = p->readWord( feat_ptr + 0x34 );
temp.sub_material = p->readDWord( feat_ptr + 0x38 );
temp.type = feature_Underworld;
}
else
{
temp.main_material = -1;
temp.sub_material = -1;
temp.type = feature_Other;
}
features.push_back(temp);
}
return true;
}
Maps::Maps(APIPrivate* _d)
{
d = new Private;
@ -77,8 +204,28 @@ Maps::Maps(APIPrivate* _d)
off.occupancy_offset = mem->getOffset("map_data_occupancy");
off.biome_stuffs = mem->getOffset ("map_data_biome_stuffs");
off.veinvector = mem->getOffset ("map_data_vein_vector");
off.local_feature_offset = mem->getOffset ("map_data_feature_local");
off.global_feature_offset = mem->getOffset ("map_data_feature_global");
off.temperature1_offset = mem->getOffset ("map_data_temperature1_offset");
off.temperature2_offset = mem->getOffset ("map_data_temperature2_offset");
off.region_x_offset = mem->getAddress ("region_x");
off.region_y_offset = mem->getAddress ("region_y");
off.region_z_offset = mem->getAddress ("region_z");
off.world_regions = mem->getAddress ("ptr2_region_array");
off.region_size = mem->getHexValue ("region_size");
off.region_geo_index_offset = mem->getOffset ("region_geo_index_off");
off.geolayer_geoblock_offset = mem->getOffset ("geolayer_geoblock_offset");
off.world_geoblocks_vector = mem->getAddress ("geoblock_vector");
off.type_inside_geolayer = mem->getOffset ("type_inside_geolayer");
off.world_size_x = mem->getAddress ("world_size_x");
off.world_size_y = mem->getAddress ("world_size_y");
// these can fail and will be found when looking at the actual veins later
// basically a cache
@ -138,6 +285,11 @@ bool Maps::Start()
//return false;
}
// read position of the region inside DF world
p->readDWord (off.region_x_offset, d->regionX);
p->readDWord (off.region_y_offset, d->regionY);
p->readDWord (off.region_z_offset, d->regionZ);
// alloc array for pointers to all blocks
d->block = new uint32_t[mx*my*mz];
uint32_t *temp_x = new uint32_t[mx];
@ -219,6 +371,8 @@ bool Maps::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer
p->read (addr + d->offsets.designation_offset, sizeof (buffer->designation), (uint8_t *) buffer->designation);
p->read (addr + d->offsets.occupancy_offset, sizeof (buffer->occupancy), (uint8_t *) buffer->occupancy);
p->read (addr + d->offsets.biome_stuffs, sizeof (biome_indices40d), (uint8_t *) buffer->biome_indices);
p->readWord(addr + d->offsets.global_feature_offset, (uint16_t&) buffer->global_feature);
p->readWord(addr + d->offsets.local_feature_offset, (uint16_t&)buffer->local_feature);
buffer->origin = addr;
uint32_t addr_of_struct = p->readDWord(addr);
buffer->blockflags.whole = p->readDWord(addr_of_struct);
@ -557,45 +711,26 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
memory_info * minfo = d->d->offset_descriptor;
Process *p = d->owner;
// get needed addresses and offsets. Now this is what I call crazy.
int region_x_offset = minfo->getAddress ("region_x");
int region_y_offset = minfo->getAddress ("region_y");
int region_z_offset = minfo->getAddress ("region_z");
int world_regions = minfo->getAddress ("ptr2_region_array");
int region_size = minfo->getHexValue ("region_size");
int region_geo_index_offset = minfo->getOffset ("region_geo_index_off");
int world_geoblocks_vector = minfo->getAddress ("geoblock_vector");
int world_size_x = minfo->getAddress ("world_size_x");
int world_size_y = minfo->getAddress ("world_size_y");
int geolayer_geoblock_offset = minfo->getOffset ("geolayer_geoblock_offset");
int type_inside_geolayer = minfo->getOffset ("type_inside_geolayer");
uint32_t regionX, regionY, regionZ;
uint16_t worldSizeX, worldSizeY;
// read position of the region inside DF world
p->readDWord (region_x_offset, regionX);
p->readDWord (region_y_offset, regionY);
p->readDWord (region_z_offset, regionZ);
Server::Maps::maps_offsets &off = d->offsets;
// get world size
p->readWord (world_size_x, worldSizeX);
p->readWord (world_size_y, worldSizeY);
p->readWord (off.world_size_x, worldSizeX);
p->readWord (off.world_size_y, worldSizeY);
// get pointer to first part of 2d array of regions
uint32_t regions = p->readDWord (world_regions);
uint32_t regions = p->readDWord (off.world_regions);
// read the geoblock vector
DfVector <uint32_t> geoblocks (d->d->p, world_geoblocks_vector);
DfVector <uint32_t> geoblocks (d->d->p, off.world_geoblocks_vector);
// iterate over 8 surrounding regions + local region
for (int i = eNorthWest; i < eBiomeCount; i++)
{
// check against worldmap boundaries, fix if needed
int bioRX = regionX / 16 + (i % 3) - 1;
int bioRX = d->regionX / 16 + (i % 3) - 1;
if (bioRX < 0) bioRX = 0;
if (bioRX >= worldSizeX) bioRX = worldSizeX - 1;
int bioRY = regionY / 16 + (i / 3) - 1;
int bioRY = d->regionY / 16 + (i / 3) - 1;
if (bioRY < 0) bioRY = 0;
if (bioRY >= worldSizeY) bioRY = worldSizeY - 1;
@ -607,7 +742,7 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
// get index into geoblock vector
uint16_t geoindex;
p->readWord (geoX + bioRY*region_size + region_geo_index_offset, geoindex);
p->readWord (geoX + bioRY*off.region_size + off.region_geo_index_offset, geoindex);
/// geology blocks are assigned to regions from a vector
// get the geoblock from the geoblock vector using the geoindex
@ -616,7 +751,7 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
/// geology blocks have a vector of layer descriptors
// get the vector with pointer to layers
DfVector <uint32_t> geolayers (p, geoblock_off + geolayer_geoblock_offset); // let's hope
DfVector <uint32_t> geolayers (p, geoblock_off + off.geolayer_geoblock_offset); // let's hope
// make sure we don't load crap
assert (geolayers.size() > 0 && geolayers.size() <= 16);
@ -628,7 +763,7 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
// read pointer to a layer
uint32_t geol_offset = geolayers[j];
// read word at pointer + 2, store in our geology vectors
d->v_geology[i].push_back (p->readWord (geol_offset + type_inside_geolayer));
d->v_geology[i].push_back (p->readWord (geol_offset + off.type_inside_geolayer));
}
}
assign.clear();

@ -42,6 +42,9 @@ typedef struct
uint32_t x_count_offset;// = d->offset_descriptor->getAddress ("x_count");
uint32_t y_count_offset;// = d->offset_descriptor->getAddress ("y_count");
uint32_t z_count_offset;// = d->offset_descriptor->getAddress ("z_count");
/*
Block
*/
uint32_t tile_type_offset;// = d->offset_descriptor->getOffset ("type");
uint32_t designation_offset;// = d->offset_descriptor->getOffset ("designation");
uint32_t occupancy_offset;// = d->offset_descriptor->getOffset ("occupancy");
@ -49,23 +52,27 @@ typedef struct
uint32_t veinvector;// = d->offset_descriptor->getOffset ("v_vein");
uint32_t temperature1_offset;
uint32_t temperature2_offset;
uint32_t global_feature_offset;
uint32_t local_feature_offset;
uint32_t vein_mineral_vptr;
uint32_t vein_ice_vptr;
uint32_t vein_spatter_vptr;
/*
GEOLOGY
*/
uint32_t region_x_offset;// = minfo->getAddress ("region_x");
uint32_t region_y_offset;// = minfo->getAddress ("region_y");
uint32_t region_z_offset;// = minfo->getAddress ("region_z");
uint32_t world_offset;// = minfo->getAddress ("world");
uint32_t world_regions_offset;// = minfo->getOffset ("w_regions_arr");
uint32_t world_regions;// mem->getAddress ("ptr2_region_array");
uint32_t region_size;// = minfo->getHexValue ("region_size");
uint32_t region_geo_index_offset;// = minfo->getOffset ("region_geo_index_off");
uint32_t world_geoblocks_offset;// = minfo->getOffset ("w_geoblocks");
uint32_t world_geoblocks_vector;// = minfo->getOffset ("geoblock_vector");
uint32_t world_size_x;// = minfo->getOffset ("world_size_x");
uint32_t world_size_y;// = minfo->getOffset ("world_size_y");
uint32_t geolayer_geoblock_offset;// = minfo->getOffset ("geolayer_geoblock_offset");
*/
uint32_t type_inside_geolayer;// = mem->getOffset ("type_inside_geolayer");
} maps_offsets;
typedef struct

@ -49,12 +49,18 @@ int main (int argc, const char* argv[])
showhidden = true;
#endif
uint32_t x_max,y_max,z_max;
/*
DFHack::tiletypes40d tiletypes;
DFHack::designations40d designations;
DFHack::biome_indices40d regionoffsets;
*/
DFHack::mapblock40d Block;
map <int16_t, uint32_t> materials;
materials.clear();
vector<DFHack::t_matgloss> stonetypes;
vector<DFHack::t_feature> global_features;
std::map <DFHack::planecoord, std::vector<DFHack::t_feature *> > local_features;
vector< vector <uint16_t> > layerassign;
DFHack::API DF("Memory.xml");
@ -86,6 +92,23 @@ int main (int argc, const char* argv[])
}
Maps->getSize(x_max,y_max,z_max);
if(!Maps->ReadGlobalFeatures(global_features))
{
cerr << "Can't get global features." << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
if(!Maps->ReadLocalFeatures(local_features))
{
cerr << "Can't get local features." << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
// get stone matgloss mapping
if(!Mats->ReadInorganicMaterials(stonetypes))
{
@ -122,8 +145,9 @@ int main (int argc, const char* argv[])
continue;
// read data
Maps->ReadTileTypes(x,y,z, &tiletypes);
Maps->ReadDesignations(x,y,z, &designations);
Maps->ReadBlock40d(x,y,z, &Block);
//Maps->ReadTileTypes(x,y,z, &tiletypes);
//Maps->ReadDesignations(x,y,z, &designations);
memset(tempvein, -1, sizeof(tempvein));
veins.clear();
@ -131,24 +155,24 @@ int main (int argc, const char* argv[])
if(showbaselayers)
{
Maps->ReadRegionOffsets(x,y,z, &regionoffsets);
//Maps->ReadRegionOffsets(x,y,z, &regionoffsets);
// get the layer materials
for(uint32_t xx = 0;xx<16;xx++)
{
for (uint32_t yy = 0; yy< 16;yy++)
{
uint8_t test = designations[xx][yy].bits.biome;
uint8_t test = Block.designation[xx][yy].bits.biome;
if(test > maximum_regionoffset)
maximum_regionoffset = test;
if( test >= sizeof(regionoffsets))
if( test >= sizeof(Block.biome_indices))
{
num_overflows++;
continue;
}
tempvein[xx][yy] =
layerassign
[regionoffsets[test]]
[designations[xx][yy].bits.geolayer_index];
[Block.biome_indices[test]]
[Block.designation[xx][yy].bits.geolayer_index];
}
}
}
@ -172,6 +196,56 @@ int main (int argc, const char* argv[])
}
}
}
// global feature overrides
int16_t idx = Block.global_feature;
if( idx != -1 && uint16_t(idx) < global_features.size() && global_features[idx].type == DFHack::feature_Underworld)
{
for(uint32_t xi = 0 ; xi< 16 ; xi++) for(uint32_t yi = 0 ; yi< 16 ; yi++)
{
if(Block.designation[xi][yi].bits.feature_global)
{
if(global_features[idx].main_material == 0) // stone
{
tempvein[xi][yi] = global_features[idx].sub_material;
}
else
{
tempvein[xi][yi] = -1;
}
}
}
}
idx = Block.local_feature;
if( idx != -1 )
{
DFHack::planecoord pc;
pc.dim.x = x;
pc.dim.y = y;
std::map <DFHack::planecoord, std::vector<DFHack::t_feature *> >::iterator it;
it = local_features.find(pc);
if(it != local_features.end())
{
std::vector<DFHack::t_feature *>& vectr = (*it).second;
if(uint16_t(idx) < vectr.size() && vectr[idx]->type == DFHack::feature_Adamantine_Tube)
for(uint32_t xi = 0 ; xi< 16 ; xi++) for(uint32_t yi = 0 ; yi< 16 ; yi++)
{
if(Block.designation[xi][yi].bits.feature_global)
{
if(vectr[idx]->main_material == 0) // stone
{
tempvein[xi][yi] = vectr[idx]->sub_material;
}
else
{
tempvein[xi][yi] = -1;
}
}
}
}
}
// count the material types
for(uint32_t xi = 0 ; xi< 16 ; xi++)
{
@ -179,7 +253,7 @@ int main (int argc, const char* argv[])
{
// hidden tiles are ignored unless '-a' is provided on the command line
// non-wall tiles are ignored
if( (designations[xi][yi].bits.hidden && !showhidden) || !DFHack::isWallTerrain(tiletypes[xi][yi]))
if( (Block.designation[xi][yi].bits.hidden && !showhidden) || !DFHack::isWallTerrain(Block.tiletypes[xi][yi]))
continue;
if(tempvein[xi][yi] < 0)
continue;
@ -199,7 +273,7 @@ int main (int argc, const char* argv[])
}
// print report
cout << "Maximal regionoffset seen: " << maximum_regionoffset << ".";
if(maximum_regionoffset >= sizeof(regionoffsets) )
if(maximum_regionoffset >= sizeof(Block.biome_indices) )
{
cout << " This is above the regionoffsets array size!" << endl;
cout << "Number of overflows: " << num_overflows;
@ -208,9 +282,16 @@ int main (int argc, const char* argv[])
map<int16_t, uint32_t>::iterator p;
for(p = materials.begin(); p != materials.end(); p++)
{
if(p->first == -1)
{
cout << "Non-stone" << " : " << p->second << endl;
}
else
{
cout << stonetypes[p->first].id << " : " << p->second << endl;
}
}
DF.Detach();
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;