From 815646982517f3b14466a76a8448e238901cdb81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 24 Apr 2010 01:15:15 +0200 Subject: [PATCH] Global, local feature reading in Maps --- dfhack/include/modules/Maps.h | 45 +++++++- dfhack/modules/Maps.cpp | 195 ++++++++++++++++++++++++++++------ dfhack/shm/mod-maps.h | 15 ++- examples/veinlook.cpp | 4 +- tools/prospector.cpp | 101 ++++++++++++++++-- 5 files changed, 311 insertions(+), 49 deletions(-) diff --git a/dfhack/include/modules/Maps.h b/dfhack/include/modules/Maps.h index 883fa61ae..433937603 100644 --- a/dfhack/include/modules/Maps.h +++ b/dfhack/include/modules/Maps.h @@ -11,7 +11,37 @@ 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; @@ -52,7 +82,7 @@ namespace DFHack eSouthEast, eBiomeCount }; - + enum e_traffic { traffic_normal, @@ -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 >& assign ); - + vector global_features; + // map between feature address and the read object + map local_feature_store; + // map between mangled coords and pointer to feature + + + bool ReadGlobalFeatures( std::vector & features); + bool ReadLocalFeatures( std::map > & local_features ); /* * BLOCK DATA */ diff --git a/dfhack/modules/Maps.cpp b/dfhack/modules/Maps.cpp index b562ed655..69e04ef72 100644 --- a/dfhack/modules/Maps.cpp +++ b/dfhack/modules/Maps.cpp @@ -54,9 +54,136 @@ struct Maps::Private Process * owner; bool Inited; bool Started; + + vector global_features; + // map between feature address and the read object + map local_feature_store; + // map between mangled coords and pointer to feature + map > local_features; + vector v_geology[eBiomeCount]; }; +bool Maps::ReadLocalFeatures( std::map > & 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) * crap; + uint32_t feat_vector = wtf + sizeof_vec * (16 * (region_x_plus8 % 16) + (region_y_local % 16)); + DfVector p_features(p, feat_vector); + uint size = p_features.size(); + planecoord pc; + pc.dim.x = blockX; + pc.dim.y = blockY; + std::vector tempvec; + for(uint i = 0; i < size; i++) + { + uint32_t cur_ptr = p_features[i]; + + map ::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 & 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 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,9 +204,29 @@ 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 off.vein_ice_vptr = 0; @@ -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 >& 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 geoblocks (d->d->p, world_geoblocks_vector); + DfVector 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 >& 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 >& assign) /// geology blocks have a vector of layer descriptors // get the vector with pointer to layers - DfVector geolayers (p, geoblock_off + geolayer_geoblock_offset); // let's hope + DfVector 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 >& 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(); diff --git a/dfhack/shm/mod-maps.h b/dfhack/shm/mod-maps.h index 832c4e8c8..de3a9812f 100644 --- a/dfhack/shm/mod-maps.h +++ b/dfhack/shm/mod-maps.h @@ -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 diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index 5c084e211..7b78342d0 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -345,11 +345,11 @@ void do_features(Process* p, uint32_t blockaddr, uint32_t blockX, uint32_t block cout << name << endl; } */ - gotoxy(printX,printY+7); + gotoxy(printX,printY + 7); cprintf("feature %d addr: 0x%x\n", idx, p_features[idx]); if(idx >= p_features.size()) { - gotoxy(printX,printY+8); + gotoxy(printX,printY + 8); cprintf("ERROR, out of vector bounds."); } else diff --git a/tools/prospector.cpp b/tools/prospector.cpp index b64790793..2c5e686e1 100644 --- a/tools/prospector.cpp +++ b/tools/prospector.cpp @@ -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 materials; materials.clear(); vector stonetypes; + vector global_features; + std::map > local_features; + vector< vector > 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, ®ionoffsets); + //Maps->ReadRegionOffsets(x,y,z, ®ionoffsets); // 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 >::iterator it; + it = local_features.find(pc); + if(it != local_features.end()) + { + std::vector& 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; @@ -209,7 +283,14 @@ int main (int argc, const char* argv[]) map::iterator p; for(p = materials.begin(); p != materials.end(); p++) { - cout << stonetypes[p->first].id << " : " << p->second << endl; + if(p->first == -1) + { + cout << "Non-stone" << " : " << p->second << endl; + } + else + { + cout << stonetypes[p->first].id << " : " << p->second << endl; + } } DF.Detach(); #ifndef LINUX_BUILD