void read_segment( void *arg) { if(!Maps::IsValid()) { return; } static bool firstLoad = 1; ssConfig.threadstarted = 1; WorldSegment* segment = NULL; { CoreSuspender suspend; //read cursor if (ssConfig.follow_DFcursor) { Gui::getCursorCoords(ssState.dfCursor.x, ssState.dfCursor.y, ssState.dfCursor.z); ssState.dfSelection.x = df::global::selection_rect->start_x; ssState.dfSelection.y = df::global::selection_rect->start_y; ssState.dfSelection.z = df::global::selection_rect->start_z; } if (firstLoad || ssConfig.track_mode != GameConfiguration::TRACKING_NONE) { firstLoad = 0; if (ssConfig.track_mode == GameConfiguration::TRACKING_CENTER) { followCurrentDFCenter(); } else if (ssConfig.track_mode == GameConfiguration::TRACKING_WINDOW) { followCurrentDFWindow(); } else if (ssConfig.track_mode == GameConfiguration::TRACKING_FOCUS) { followCurrentDFFocus(); ssConfig.follow_DFcursor = true; } } segment = map_segment.getRead(); readMapSegment(segment, ssState); ssConfig.threadstarted = 0; } if(segment) { beautifySegment(segment); //putting these here to increase responsiveness of the UI and to make megashots work //segment->segState.Position = ssState.Position; //segment->segState.dfCursor = ssState.dfCursor; segment->AssembleAllTiles(); //only need to lock the drawing segment because the reading segment is already locked map_segment.lockDraw(); map_segment.swap(); map_segment.unlockDraw(); } }
void read_segment( void *arg) { if(!Maps::IsValid()) { return; } static bool firstLoad = 1; ssConfig.threadstarted = 1; WorldSegment* segment = NULL; { CoreSuspender suspend; if (firstLoad || ssConfig.follow_DFscreen) { firstLoad = 0; if (ssConfig.track_center) { FollowCurrentDFCenter(); } else { FollowCurrentDFWindow(); } } segment = map_segment.getRead(); readMapSegment(segment, parms.x, parms.y, parms.z,parms.sizex, parms.sizey, parms.sizez); ssConfig.threadstarted = 0; } if(segment) { beautifySegment(segment); //putting these here to increase responsiveness of the UI and to make megashots work segment->segState.DisplayedSegment = ssState.DisplayedSegment; segment->AssembleAllTiles(); //only need to lock the drawing segment because the reading segment is already locked map_segment.lockDraw(); map_segment.swap(); map_segment.unlockDraw(); } }
/** * reads one 16x16 block pulled over RPC into stonesense tiles */ void readRemoteBlockToSegment(RemoteFortressReader::MapBlock &block, WorldSegment& segment) { for (int xx = 0; xx < BLOCKEDGESIZE; xx++) for (int yy = 0; yy < BLOCKEDGESIZE; yy++) { int32_t x = xx + block.map_x(); int32_t y = yy + block.map_y(); int32_t z = block.map_z(); int32_t index = xx + (yy * BLOCKEDGESIZE); Tile * t = segment.getTile(x, y, z); if (!t) continue; t->tileType = (tiletype::tiletype)block.tiles(index); t->material.index = block.materials(index).mat_index(); t->material.type = block.materials(index).mat_type(); } }
/** * reads one 16x16 map block into stonesense tiles * attempts to only read as much information as is necessary to do the tile optimization */ void readBlockToSegment(DFHack::Core& DF, WorldSegment& segment, int BlockX, int BlockY, int BlockZ, uint32_t BoundrySX, uint32_t BoundrySY, uint32_t BoundryEX, uint32_t BoundryEY, vector< vector <int16_t> >* allLayers) { if(ssConfig.skipMaps) { return; } //boundry check int blockDimX, blockDimY, blockDimZ; Maps::getSize((unsigned int &)blockDimX, (unsigned int &)blockDimY, (unsigned int &)blockDimZ); if( BlockX < 0 || BlockX >= blockDimX || BlockY < 0 || BlockY >= blockDimY || BlockZ < 0 || BlockZ >= blockDimZ ) { return; } //make boundries local BoundrySX -= BlockX * BLOCKEDGESIZE; BoundryEX -= BlockX * BLOCKEDGESIZE; BoundrySY -= BlockY * BLOCKEDGESIZE; BoundryEY -= BlockY * BLOCKEDGESIZE; //read block data df::map_block *trueBlock; trueBlock = Maps::getBlock(BlockX, BlockY, BlockZ); if(!trueBlock) { return; } //read the map features t_feature local, global; Maps::ReadFeatures(BlockX,BlockY,BlockZ,&local,&global); //read local vein data vector <df::block_square_event_mineralst * > veins; vector <df::block_square_event_frozen_liquidst * > ices; vector <df::block_square_event_material_spatterst * > splatter; vector <df::block_square_event_grassst * > grass; vector <df::block_square_event_world_constructionst * > worldconstructions; Maps::SortBlockEvents( trueBlock, &veins, &ices, &splatter, &grass, &worldconstructions); //parse block for(uint32_t ly = BoundrySY; ly <= BoundryEY; ly++) { for(uint32_t lx = BoundrySX; lx <= BoundryEX; lx++) { uint32_t gx = lx + (BlockX * BLOCKEDGESIZE); uint32_t gy = ly + (BlockY * BLOCKEDGESIZE); if( !segment.CoordinateInsideSegment( gx, gy, BlockZ) ) { continue; } bool shouldBeIncluded = true; //open terrain needs to be included to make blackboxes if // we are shading but not showing hidden tiles if(isOpenTerrain(trueBlock->tiletype[lx][ly]) && trueBlock->tiletype[lx][ly] != tiletype::RampTop) { if(!ssConfig.show_hidden_tiles && ssConfig.shade_hidden_tiles && trueBlock->designation[lx][ly].bits.hidden) { shouldBeIncluded = true; } else { shouldBeIncluded = false; } //all other terrain needs including, except for hidden tiles // when we are neither showing nor shading hidden tiles } else if(!ssConfig.show_hidden_tiles && !ssConfig.shade_hidden_tiles && trueBlock->designation[lx][ly].bits.hidden) { shouldBeIncluded = false; } //add back in any liquid tiles, in case they can be seen from above // as well as any hanging buildings if(trueBlock->designation[lx][ly].bits.flow_size || trueBlock->occupancy[lx][ly].bits.building) { shouldBeIncluded = true; } //add back in any tiles that are constructions or designations if( ssConfig.show_designations && containsDesignations( trueBlock->designation[lx][ly], trueBlock->occupancy[lx][ly] ) ) { shouldBeIncluded = true; } if(!shouldBeIncluded){ continue; } Tile * b = segment.ResetTile(gx, gy, BlockZ, trueBlock->tiletype[lx][ly]); b->occ.bits.unit = false;//this will be set manually when we read the creatures vector b->occ = trueBlock->occupancy[lx][ly]; b->designation = trueBlock->designation[lx][ly]; //if the tile has designations, read them and nothing else if( ssConfig.show_designations && readDesignationsToTile( b, trueBlock->designation[lx][ly], trueBlock->occupancy[lx][ly] ) ) { continue; } //set whether the tile is hidden b->fog_of_war = !b->designation.bits.pile; //don't read detailed information for blackbox tiles if(!ssConfig.show_hidden_tiles && ssConfig.shade_hidden_tiles && b->designation.bits.hidden && !b->designation.bits.flow_size) { continue; } //read the grasses b->grasslevel = 0; b->grassmat = -1; //b->grasslevels.clear(); //b->grassmats.clear(); for(int i = 0; i < grass.size(); i++) { if(grass[i]->amount[lx][ly] > 0 && b->grasslevel == 0) { //b->grasslevel) b->grasslevel = grass[i]->amount[lx][ly]; b->grassmat = grass[i]->plant_index; //b->grasslevels.push_back(grass[i].intensity[lx][ly]); //b->grassmats.push_back(grass[i].material); } } //read the water flows and direction. b->flow_direction = trueBlock->liquid_flow[lx][ly].bits.perm_flow_dir; //read the tile spatter readSpatterToTile(b, lx, ly, splatter); //read the tile material readMaterialToTile(b, lx, ly, trueBlock, local, global, veins, allLayers); } } //add trees and other vegetation for(auto iter = trueBlock->plants.begin(); iter != trueBlock->plants.end(); iter++) { df::plant * wheat = *iter; assert(wheat != NULL); Tile* b = segment.getTile( wheat->pos.x, wheat->pos.y, wheat->pos.z); if(!b) { b = segment.ResetTile(wheat->pos.x, wheat->pos.y, wheat->pos.z, tiletype::OpenSpace); if(!b) { continue; } } if( b->tileShape() == tiletype_shape::TREE || b->tileShape() == tiletype_shape::SAPLING || b->tileShape() == tiletype_shape::SHRUB) { b->tree.type = wheat->flags.whole; b->tree.index = wheat->material; } } //add items for(auto iter = trueBlock->items.begin(); iter != trueBlock->items.end(); iter++) { int32_t item_index = *iter; df::item * found_item = df::item::find(item_index); if(!found_item) { continue; } Tile* b = segment.getTile( found_item->pos.x, found_item->pos.y, found_item->pos.z); if(!b) { b = segment.ResetTile(found_item->pos.x, found_item->pos.y, found_item->pos.z, tiletype::OpenSpace); if(!b) { continue; } } b->Item = ConvertItem(found_item, segment); } //add effects for(auto iter = trueBlock->flows.begin(); iter != trueBlock->flows.end(); iter++) { df::flow_info * eff = *iter; if(eff == NULL || eff->density <= 0) { continue; } Tile* b = segment.getTile( eff->pos.x, eff->pos.y, eff->pos.z); if(segment.CoordinateInsideSegment(eff->pos.x, eff->pos.y, eff->pos.z)) { if(!b) { b = segment.ResetTile(eff->pos.x, eff->pos.y, eff->pos.z, tiletype::OpenSpace); if(!b) { continue; } } if(eff->density > b->tileeffect.density || b->tileeffect.type == (df::flow_type) INVALID_INDEX) { b->tileeffect.type = eff->type; b->tileeffect.density = eff->density; b->tileeffect.matt.index = eff->mat_index; b->tileeffect.matt.type = eff->mat_type; } } } }
void readBlockColumnToSegment(DFHack::Core& DF, WorldSegment& segment, int BlockX, int BlockY) { if (ssConfig.skipMaps) { return; } //boundry check int blockDimX, blockDimY, blockDimZ; Maps::getSize((unsigned int &)blockDimX, (unsigned int &)blockDimY, (unsigned int &)blockDimZ); if (BlockX < 0 || BlockX >= blockDimX || BlockY < 0 || BlockY >= blockDimY) { return; } //read block data df::map_block_column *trueColumn; trueColumn = Maps::getBlockColumn(BlockX, BlockY); if (!trueColumn) { return; } for (int i = 0; i < trueColumn->plants.size(); i++) { df::plant * pp = trueColumn->plants[i]; // A plant without tree_info is single tile if (!pp->tree_info) { if (!segment.CoordinateInsideSegment(pp->pos.x, pp->pos.y, pp->pos.z)) continue; Tile * t = segment.getTile(pp->pos.x, pp->pos.y, pp->pos.z); if (!t) t = segment.ResetTile(pp->pos.x, pp->pos.y, pp->pos.z); if (!t) continue; t->tree.type = pp->flags.whole; t->tree.index = pp->material; continue; } // tree_info contains vertical slices of the tree. This ensures there's a slice for our Z-level. df::plant_tree_info * info = pp->tree_info; if (!segment.RangeInsideSegment( pp->pos.x - (pp->tree_info->dim_x / 2), pp->pos.y - (pp->tree_info->dim_y / 2), pp->pos.z - (pp->tree_info->roots_depth), pp->pos.x + (pp->tree_info->dim_x / 2), pp->pos.y + (pp->tree_info->dim_y / 2), pp->pos.z + pp->tree_info->body_height - 1)) continue; auto raw = df::plant_raw::find(pp->material); for (int zz = 0; zz < info->body_height; zz++) { // Parse through a single horizontal slice of the tree. for (int xx = 0; xx < info->dim_x; xx++) for (int yy = 0; yy < info->dim_y; yy++) { // Any non-zero value here other than blocked means there's some sort of branch here. // If the block is at or above the plant's base level, we use the body array // otherwise we use the roots. // TODO: verify that the tree bounds intersect the block. df::plant_tree_tile tile = info->body[zz][xx + (yy*info->dim_x)]; if (tile.whole && !(tile.bits.blocked)) { df::coord pos = pp->pos; pos.x = pos.x - (info->dim_x / 2) + xx; pos.y = pos.y - (info->dim_y / 2) + yy; pos.z = pos.z + zz; if (!segment.CoordinateInsideSegment(pos.x, pos.y, pos.z)) continue; Tile * t = segment.getTile(pos.x, pos.y, pos.z); if (!t) t = segment.ResetTile(pos.x, pos.y, pos.z); if (!t) continue; t->tree.type = pp->flags.whole; t->tree.index = pp->material; t->tree_tile = tile; if (raw) { t->material.type = raw->material_defs.type_basic_mat; t->material.index = raw->material_defs.idx_basic_mat; } } } } for (int zz = 0; zz < info->roots_depth; zz++) { // Parse through a single horizontal slice of the tree. for (int xx = 0; xx < info->dim_x; xx++) for (int yy = 0; yy < info->dim_y; yy++) { // Any non-zero value here other than blocked means there's some sort of branch here. // If the block is at or above the plant's base level, we use the body array // otherwise we use the roots. // TODO: verify that the tree bounds intersect the block. df::plant_tree_tile tile = info->roots[zz][xx + (yy*info->dim_x)]; if (tile.whole && !(tile.bits.blocked)) { df::coord pos = pp->pos; pos.x = pos.x - (info->dim_x / 2) + xx; pos.y = pos.y - (info->dim_y / 2) + yy; pos.z = pos.z - 1 - zz; if (!segment.CoordinateInsideSegment(pos.x, pos.y, pos.z)) continue; Tile * t = segment.getTile(pos.x, pos.y, pos.z); if (!t) t = segment.ResetTile(pos.x, pos.y, pos.z); if (!t) continue; t->tree.type = pp->flags.whole; t->tree.index = pp->material; } } } } }