X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmap.cpp;h=40950423233a417a44de6f605076988218fcf86d;hb=65c09a96f41705bb8e75fc5ff4276342be91ed11;hp=4b0d2e2d8e846d8e5ee664ece1e245a8e4b4faaa;hpb=5b8855e83c0d1cc7aef21492e7fe862b7d06917e;p=minetest.git diff --git a/src/map.cpp b/src/map.cpp index 4b0d2e2d8..409504232 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map.h" #include "mapsector.h" #include "mapblock.h" -#include "main.h" #include "filesys.h" #include "voxel.h" #include "porting.h" @@ -43,6 +42,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database.h" #include "database-dummy.h" #include "database-sqlite3.h" +#include +#include #if USE_LEVELDB #include "database-leveldb.h" #endif @@ -52,22 +53,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" -/* - SQLite format specification: - - Initially only replaces sectors/ and sectors2/ - - If map.sqlite does not exist in the save dir - or the block was not found in the database - the map will try to load from sectors folder. - In either case, map.sqlite will be created - and all future saves will save there. - - Structure of map.sqlite: - Tables: - blocks - (PK) INT pos - BLOB data -*/ /* Map @@ -76,7 +61,11 @@ with this program; if not, write to the Free Software Foundation, Inc., Map::Map(std::ostream &dout, IGameDef *gamedef): m_dout(dout), m_gamedef(gamedef), - m_sector_cache(NULL) + m_sector_cache(NULL), + m_transforming_liquid_loop_count_multiplier(1.0f), + m_unprocessed_count(0), + m_inc_trending_up_start_time(0), + m_queue_size_timer_started(false) { } @@ -276,7 +265,7 @@ void Map::unspreadLight(enum LightBank bank, v3s16(-1,0,0), // left }; - if(from_nodes.size() == 0) + if(from_nodes.empty()) return; u32 blockchangecount = 0; @@ -330,7 +319,8 @@ void Map::unspreadLight(enum LightBank bank, v3s16 n2pos = pos + dirs[i]; // Get the block where the node is located - v3s16 blockpos = getNodeBlockPos(n2pos); + v3s16 blockpos, relpos; + getNodeBlockPosWithOffset(n2pos, blockpos, relpos); // Only fetch a new block if the block position has changed try { @@ -346,8 +336,6 @@ void Map::unspreadLight(enum LightBank bank, continue; } - // Calculate relative position in block - v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE; // Get node straight from the block bool is_valid_position; MapNode n2 = block->getNode(relpos, &is_valid_position); @@ -414,11 +402,11 @@ void Map::unspreadLight(enum LightBank bank, } /*infostream<<"unspreadLight(): Changed block " - < 0) + if(!unlighted_nodes.empty()) unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks); } @@ -455,7 +443,7 @@ void Map::spreadLight(enum LightBank bank, v3s16(-1,0,0), // left }; - if(from_nodes.size() == 0) + if(from_nodes.empty()) return; u32 blockchangecount = 0; @@ -467,14 +455,16 @@ void Map::spreadLight(enum LightBank bank, */ v3s16 blockpos_last; MapBlock *block = NULL; - // Cache this a bit, too + // Cache this a bit, too bool block_checked_in_modified = false; for(std::set::iterator j = from_nodes.begin(); j != from_nodes.end(); ++j) { v3s16 pos = *j; - v3s16 blockpos = getNodeBlockPos(pos); + v3s16 blockpos, relpos; + + getNodeBlockPosWithOffset(pos, blockpos, relpos); // Only fetch a new block if the block position has changed try { @@ -493,9 +483,6 @@ void Map::spreadLight(enum LightBank bank, if(block->isDummy()) continue; - // Calculate relative position in block - v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE; - // Get node straight from the block bool is_valid_position; MapNode n = block->getNode(relpos, &is_valid_position); @@ -509,7 +496,8 @@ void Map::spreadLight(enum LightBank bank, v3s16 n2pos = pos + dirs[i]; // Get the block where the node is located - v3s16 blockpos = getNodeBlockPos(n2pos); + v3s16 blockpos, relpos; + getNodeBlockPosWithOffset(n2pos, blockpos, relpos); // Only fetch a new block if the block position has changed try { @@ -525,8 +513,6 @@ void Map::spreadLight(enum LightBank bank, continue; } - // Calculate relative position in block - v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE; // Get node straight from the block MapNode n2 = block->getNode(relpos, &is_valid_position); if (!is_valid_position) @@ -575,7 +561,7 @@ void Map::spreadLight(enum LightBank bank, <<" for "< 0) + if(!lighted_nodes.empty()) spreadLight(bank, lighted_nodes, modified_blocks); } @@ -687,7 +673,7 @@ void Map::updateLighting(enum LightBank bank, { INodeDefManager *nodemgr = m_gamedef->ndef(); - /*m_dout< blocks_to_update; + //std::map blocks_to_update; std::set light_sources; @@ -721,7 +707,7 @@ void Map::updateLighting(enum LightBank bank, v3s16 pos = block->getPos(); v3s16 posnodes = block->getPosRelative(); modified_blocks[pos] = block; - blocks_to_update[pos] = block; + //blocks_to_update[pos] = block; /* Clear all light from block @@ -781,8 +767,7 @@ void Map::updateLighting(enum LightBank bank, } else { - // Invalid lighting bank - assert(0); + assert("Invalid lighting bank" == NULL); } /*infostream<<"Bottom for sunlight-propagated block (" @@ -797,7 +782,7 @@ void Map::updateLighting(enum LightBank bank, } catch(InvalidPositionException &e) { - assert(0); + FATAL_ERROR("Invalid position"); } } @@ -943,7 +928,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, INodeDefManager *ndef = m_gamedef->ndef(); /*PrintInfo(m_dout); - m_dout< ybottom="< ybottom="<= ybottom; y--) { v3s16 p2(p.X, y, p.Z); - /*m_dout<getUsageTimer() < b.block->getUsageTimer(); + }; +}; + /* Updates usage timers */ -void Map::timerUpdate(float dtime, float unload_timeout, - std::list *unloaded_blocks) +void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks, + std::vector *unloaded_blocks) { bool save_before_unloading = (mapType() == MAPTYPE_SERVER); // Profile modified reasons Profiler modprofiler; - std::list sector_deletion_queue; + std::vector sector_deletion_queue; u32 deleted_blocks_count = 0; u32 saved_blocks_count = 0; u32 block_count_all = 0; beginSave(); - for(std::map::iterator si = m_sectors.begin(); - si != m_sectors.end(); ++si) - { - MapSector *sector = si->second; - bool all_blocks_deleted = true; + // If there is no practical limit, we spare creation of mapblock_queue + if (max_loaded_blocks == U32_MAX) { + for (std::map::iterator si = m_sectors.begin(); + si != m_sectors.end(); ++si) { + MapSector *sector = si->second; - std::list blocks; - sector->getBlocks(blocks); + bool all_blocks_deleted = true; - for(std::list::iterator i = blocks.begin(); - i != blocks.end(); ++i) - { - MapBlock *block = (*i); + MapBlockVect blocks; + sector->getBlocks(blocks); - block->incrementUsageTimer(dtime); + for (MapBlockVect::iterator i = blocks.begin(); + i != blocks.end(); ++i) { + MapBlock *block = (*i); - if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout) - { - v3s16 p = block->getPos(); + block->incrementUsageTimer(dtime); - // Save if modified - if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) - { - modprofiler.add(block->getModifiedReason(), 1); - if (!saveBlock(block)) - continue; - saved_blocks_count++; - } + if (block->refGet() == 0 + && block->getUsageTimer() > unload_timeout) { + v3s16 p = block->getPos(); - // Delete from memory - sector->deleteBlock(block); + // Save if modified + if (block->getModified() != MOD_STATE_CLEAN + && save_before_unloading) { + modprofiler.add(block->getModifiedReasonString(), 1); + if (!saveBlock(block)) + continue; + saved_blocks_count++; + } + + // Delete from memory + sector->deleteBlock(block); - if(unloaded_blocks) - unloaded_blocks->push_back(p); + if (unloaded_blocks) + unloaded_blocks->push_back(p); - deleted_blocks_count++; + deleted_blocks_count++; + } else { + all_blocks_deleted = false; + block_count_all++; + } } - else - { - all_blocks_deleted = false; - block_count_all++; + + if (all_blocks_deleted) { + sector_deletion_queue.push_back(si->first); } } + } else { + std::priority_queue mapblock_queue; + for (std::map::iterator si = m_sectors.begin(); + si != m_sectors.end(); ++si) { + MapSector *sector = si->second; - if(all_blocks_deleted) - { - sector_deletion_queue.push_back(si->first); + MapBlockVect blocks; + sector->getBlocks(blocks); + + for(MapBlockVect::iterator i = blocks.begin(); + i != blocks.end(); ++i) { + MapBlock *block = (*i); + + block->incrementUsageTimer(dtime); + mapblock_queue.push(TimeOrderedMapBlock(sector, block)); + } + } + block_count_all = mapblock_queue.size(); + // Delete old blocks, and blocks over the limit from the memory + while (!mapblock_queue.empty() && (mapblock_queue.size() > max_loaded_blocks + || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) { + TimeOrderedMapBlock b = mapblock_queue.top(); + mapblock_queue.pop(); + + MapBlock *block = b.block; + + if (block->refGet() != 0) + continue; + + v3s16 p = block->getPos(); + + // Save if modified + if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) { + modprofiler.add(block->getModifiedReasonString(), 1); + if (!saveBlock(block)) + continue; + saved_blocks_count++; + } + + // Delete from memory + b.sect->deleteBlock(block); + + if (unloaded_blocks) + unloaded_blocks->push_back(p); + + deleted_blocks_count++; + block_count_all--; + } + // Delete empty sectors + for (std::map::iterator si = m_sectors.begin(); + si != m_sectors.end(); ++si) { + if (si->second->empty()) { + sector_deletion_queue.push_back(si->first); + } } } endSave(); @@ -1505,16 +1558,15 @@ void Map::timerUpdate(float dtime, float unload_timeout, } } -void Map::unloadUnreferencedBlocks(std::list *unloaded_blocks) +void Map::unloadUnreferencedBlocks(std::vector *unloaded_blocks) { - timerUpdate(0.0, -1.0, unloaded_blocks); + timerUpdate(0.0, -1.0, 0, unloaded_blocks); } -void Map::deleteSectors(std::list &list) +void Map::deleteSectors(std::vector §orList) { - for(std::list::iterator j = list.begin(); - j != list.end(); ++j) - { + for(std::vector::iterator j = sectorList.begin(); + j != sectorList.end(); ++j) { MapSector *sector = m_sectors[*j]; // If sector is in sector cache, remove it from there if(m_sector_cache == sector) @@ -1525,63 +1577,6 @@ void Map::deleteSectors(std::list &list) } } -#if 0 -void Map::unloadUnusedData(float timeout, - core::list *deleted_blocks) -{ - core::list sector_deletion_queue; - u32 deleted_blocks_count = 0; - u32 saved_blocks_count = 0; - - core::map::Iterator si = m_sectors.getIterator(); - for(; si.atEnd() == false; si++) - { - MapSector *sector = si.getNode()->getValue(); - - bool all_blocks_deleted = true; - - core::list blocks; - sector->getBlocks(blocks); - for(core::list::Iterator i = blocks.begin(); - i != blocks.end(); i++) - { - MapBlock *block = (*i); - - if(block->getUsageTimer() > timeout) - { - // Save if modified - if(block->getModified() != MOD_STATE_CLEAN) - { - saveBlock(block); - saved_blocks_count++; - } - // Delete from memory - sector->deleteBlock(block); - deleted_blocks_count++; - } - else - { - all_blocks_deleted = false; - } - } - - if(all_blocks_deleted) - { - sector_deletion_queue.push_back(si.getNode()->getKey()); - } - } - - deleteSectors(sector_deletion_queue); - - infostream<<"Map: Unloaded "< & modified_blocks) { + INodeDefManager *nodemgr = m_gamedef->ndef(); - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); //TimeTaker timer("transformLiquids()"); u32 loopcount = 0; @@ -1623,24 +1629,43 @@ void Map::transformLiquids(std::map & modified_blocks) infostream<<"transformLiquids(): initial_size="< must_reflow; + std::deque must_reflow; // List of MapBlocks that will require a lighting update (due to lava) std::map lighting_modified_blocks; - u16 loop_max = g_settings->getU16("liquid_loop_max"); + u32 liquid_loop_max = g_settings->getS32("liquid_loop_max"); + u32 loop_max = liquid_loop_max; + +#if 0 + + /* If liquid_loop_max is not keeping up with the queue size increase + * loop_max up to a maximum of liquid_loop_max * dedicated_server_step. + */ + if (m_transforming_liquid.size() > loop_max * 2) { + // "Burst" mode + float server_step = g_settings->getFloat("dedicated_server_step"); + if (m_transforming_liquid_loop_count_multiplier - 1.0 < server_step) + m_transforming_liquid_loop_count_multiplier *= 1.0 + server_step / 10; + } else { + m_transforming_liquid_loop_count_multiplier = 1.0; + } + + loop_max *= m_transforming_liquid_loop_count_multiplier; +#endif - while(m_transforming_liquid.size() != 0) + while (m_transforming_liquid.size() != 0) { // This should be done here so that it is done when continue is used - if(loopcount >= initial_size || loopcount >= loop_max) + if (loopcount >= initial_size || loopcount >= loop_max) break; loopcount++; /* Get a queued transforming liquid node */ - v3s16 p0 = m_transforming_liquid.pop_front(); + v3s16 p0 = m_transforming_liquid.front(); + m_transforming_liquid.pop_front(); MapNode n0 = getNodeNoEx(p0); @@ -1649,21 +1674,24 @@ void Map::transformLiquids(std::map & modified_blocks) */ s8 liquid_level = -1; content_t liquid_kind = CONTENT_IGNORE; - LiquidType liquid_type = nodemgr->get(n0).liquid_type; + content_t floodable_node = CONTENT_AIR; + ContentFeatures cf = nodemgr->get(n0); + LiquidType liquid_type = cf.liquid_type; switch (liquid_type) { case LIQUID_SOURCE: liquid_level = LIQUID_LEVEL_SOURCE; - liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing); + liquid_kind = nodemgr->getId(cf.liquid_alternative_flowing); break; case LIQUID_FLOWING: liquid_level = (n0.param2 & LIQUID_LEVEL_MASK); liquid_kind = n0.getContent(); break; case LIQUID_NONE: - // if this is an air node, it *could* be transformed into a liquid. otherwise, - // continue with the next node. - if (n0.getContent() != CONTENT_AIR) + // if this node is 'floodable', it *could* be transformed + // into a liquid, otherwise, continue with the next node. + if (!cf.floodable) continue; + floodable_node = n0.getContent(); liquid_kind = CONTENT_AIR; break; } @@ -1692,10 +1720,11 @@ void Map::transformLiquids(std::map & modified_blocks) break; } v3s16 npos = p0 + dirs[i]; - NodeNeighbor nb = {getNodeNoEx(npos), nt, npos}; + NodeNeighbor nb(getNodeNoEx(npos), nt, npos); + ContentFeatures cfnb = nodemgr->get(nb.n); switch (nodemgr->get(nb.n.getContent()).liquid_type) { case LIQUID_NONE: - if (nb.n.getContent() == CONTENT_AIR) { + if (cfnb.floodable) { airs[num_airs++] = nb; // if the current node is a water source the neighbor // should be enqueded for transformation regardless of whether the @@ -1703,18 +1732,21 @@ void Map::transformLiquids(std::map & modified_blocks) if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE) m_transforming_liquid.push_back(npos); // if the current node happens to be a flowing node, it will start to flow down here. - if (nb.t == NEIGHBOR_LOWER) { + if (nb.t == NEIGHBOR_LOWER) flowing_down = true; - } } else { neutrals[num_neutrals++] = nb; + // If neutral below is ignore prevent water spreading outwards + if (nb.t == NEIGHBOR_LOWER && + nb.n.getContent() == CONTENT_IGNORE) + flowing_down = true; } break; case LIQUID_SOURCE: // if this node is not (yet) of a liquid type, choose the first liquid type we encounter if (liquid_kind == CONTENT_AIR) - liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing); - if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) { + liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing); + if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) { neutrals[num_neutrals++] = nb; } else { // Do not count bottom source, it will screw things up @@ -1725,8 +1757,8 @@ void Map::transformLiquids(std::map & modified_blocks) case LIQUID_FLOWING: // if this node is not (yet) of a liquid type, choose the first liquid type we encounter if (liquid_kind == CONTENT_AIR) - liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing); - if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) { + liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing); + if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) { neutrals[num_neutrals++] = nb; } else { flows[num_flows++] = nb; @@ -1743,7 +1775,11 @@ void Map::transformLiquids(std::map & modified_blocks) content_t new_node_content; s8 new_node_level = -1; s8 max_node_level = -1; - u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1); + + u8 range = nodemgr->get(liquid_kind).liquid_range; + if (range > LIQUID_LEVEL_MAX + 1) + range = LIQUID_LEVEL_MAX + 1; + if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) { // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid) // or the flowing alternative of the first of the surrounding sources (if it's air), so @@ -1751,10 +1787,11 @@ void Map::transformLiquids(std::map & modified_blocks) new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source); } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) { // liquid_kind is set properly, see above - new_node_content = liquid_kind; max_node_level = new_node_level = LIQUID_LEVEL_MAX; - if (new_node_level < (LIQUID_LEVEL_MAX+1-range)) - new_node_content = CONTENT_AIR; + if (new_node_level >= (LIQUID_LEVEL_MAX + 1 - range)) + new_node_content = liquid_kind; + else + new_node_content = floodable_node; } else { // no surrounding sources, so get the maximum level that can flow into this node for (u16 i = 0; i < num_flows; i++) { @@ -1765,16 +1802,16 @@ void Map::transformLiquids(std::map & modified_blocks) max_node_level = LIQUID_LEVEL_MAX; if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX) max_node_level = nb_liquid_level + WATER_DROP_BOOST; - } else if (nb_liquid_level > max_node_level) + } else if (nb_liquid_level > max_node_level) { max_node_level = nb_liquid_level; + } break; case NEIGHBOR_LOWER: break; case NEIGHBOR_SAME_LEVEL: if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK && - nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) { + nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) max_node_level = nb_liquid_level - 1; - } break; } } @@ -1792,23 +1829,25 @@ void Map::transformLiquids(std::map & modified_blocks) new_node_level = liquid_level + 1; if (new_node_level != max_node_level) must_reflow.push_back(p0); - } else + } else { new_node_level = max_node_level; + } - if (max_node_level >= (LIQUID_LEVEL_MAX+1-range)) + if (max_node_level >= (LIQUID_LEVEL_MAX + 1 - range)) new_node_content = liquid_kind; else - new_node_content = CONTENT_AIR; + new_node_content = floodable_node; } /* check if anything has changed. if not, just continue with the next node. */ - if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING || - ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level && - ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK) - == flowing_down))) + if (new_node_content == n0.getContent() && + (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING || + ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level && + ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK) + == flowing_down))) continue; @@ -1828,11 +1867,10 @@ void Map::transformLiquids(std::map & modified_blocks) // Find out whether there is a suspect for this action std::string suspect; - if(m_gamedef->rollback()){ + if (m_gamedef->rollback()) suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1); - } - if(!suspect.empty()){ + if (m_gamedef->rollback() && !suspect.empty()) { // Blame suspect RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true); // Get old node for rollback @@ -1851,10 +1889,10 @@ void Map::transformLiquids(std::map & modified_blocks) v3s16 blockpos = getNodeBlockPos(p0); MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block != NULL) { + if (block != NULL) { modified_blocks[blockpos] = block; // If new or old node emits light, MapBlock requires lighting update - if(nodemgr->get(n0).light_source != 0 || + if (nodemgr->get(n0).light_source != 0 || nodemgr->get(n00).light_source != 0) lighting_modified_blocks[block->getPos()] = block; } @@ -1881,9 +1919,101 @@ void Map::transformLiquids(std::map & modified_blocks) } } //infostream<<"Map::transformLiquids(): loopcount="< 0) - m_transforming_liquid.push_back(must_reflow.pop_front()); + + for (std::deque::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter) + m_transforming_liquid.push_back(*iter); + updateLighting(lighting_modified_blocks, modified_blocks); + + + /* ---------------------------------------------------------------------- + * Manage the queue so that it does not grow indefinately + */ + u16 time_until_purge = g_settings->getU16("liquid_queue_purge_time"); + + if (time_until_purge == 0) + return; // Feature disabled + + time_until_purge *= 1000; // seconds -> milliseconds + + u32 curr_time = getTime(PRECISION_MILLI); + u32 prev_unprocessed = m_unprocessed_count; + m_unprocessed_count = m_transforming_liquid.size(); + + // if unprocessed block count is decreasing or stable + if (m_unprocessed_count <= prev_unprocessed) { + m_queue_size_timer_started = false; + } else { + if (!m_queue_size_timer_started) + m_inc_trending_up_start_time = curr_time; + m_queue_size_timer_started = true; + } + + // Account for curr_time overflowing + if (m_queue_size_timer_started && m_inc_trending_up_start_time > curr_time) + m_queue_size_timer_started = false; + + /* If the queue has been growing for more than liquid_queue_purge_time seconds + * and the number of unprocessed blocks is still > liquid_loop_max then we + * cannot keep up; dump the oldest blocks from the queue so that the queue + * has liquid_loop_max items in it + */ + if (m_queue_size_timer_started + && curr_time - m_inc_trending_up_start_time > time_until_purge + && m_unprocessed_count > liquid_loop_max) { + + size_t dump_qty = m_unprocessed_count - liquid_loop_max; + + infostream << "transformLiquids(): DUMPING " << dump_qty + << " blocks from the queue" << std::endl; + + while (dump_qty--) + m_transforming_liquid.pop_front(); + + m_queue_size_timer_started = false; // optimistically assume we can keep up now + m_unprocessed_count = m_transforming_liquid.size(); + } +} + +std::vector Map::findNodesWithMetadata(v3s16 p1, v3s16 p2) +{ + std::vector positions_with_meta; + + sortBoxVerticies(p1, p2); + v3s16 bpmin = getNodeBlockPos(p1); + v3s16 bpmax = getNodeBlockPos(p2); + + VoxelArea area(p1, p2); + + for (s16 z = bpmin.Z; z <= bpmax.Z; z++) + for (s16 y = bpmin.Y; y <= bpmax.Y; y++) + for (s16 x = bpmin.X; x <= bpmax.X; x++) { + v3s16 blockpos(x, y, z); + + MapBlock *block = getBlockNoCreateNoEx(blockpos); + if (!block) { + verbosestream << "Map::getNodeMetadata(): Need to emerge " + << PP(blockpos) << std::endl; + block = emergeBlock(blockpos, false); + } + if (!block) { + infostream << "WARNING: Map::getNodeMetadata(): Block not found" + << std::endl; + continue; + } + + v3s16 p_base = blockpos * MAP_BLOCKSIZE; + std::vector keys = block->m_node_metadata.getAllKeys(); + for (size_t i = 0; i != keys.size(); i++) { + v3s16 p(keys[i] + p_base); + if (!area.contains(p)) + continue; + + positions_with_meta.push_back(p); + } + } + + return positions_with_meta; } NodeMetadata *Map::getNodeMetadata(v3s16 p) @@ -1897,7 +2027,7 @@ NodeMetadata *Map::getNodeMetadata(v3s16 p) block = emergeBlock(blockpos, false); } if(!block){ - infostream<<"WARNING: Map::getNodeMetadata(): Block not found" + warningstream<<"Map::getNodeMetadata(): Block not found" <params.water_level; } -bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) +bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data) { - bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info; - EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos)); + s16 csize = m_emerge->params.chunksize; + v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize); + v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1); - s16 chunksize = m_emerge->params.chunksize; - s16 coffset = -chunksize / 2; - v3s16 chunk_offset(coffset, coffset, coffset); - v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize); - v3s16 blockpos_min = blockpos_div * chunksize; - v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1); - blockpos_min += chunk_offset; - blockpos_max += chunk_offset; + bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info; + EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax)); - v3s16 extra_borders(1,1,1); + v3s16 extra_borders(1, 1, 1); + v3s16 full_bpmin = bpmin - extra_borders; + v3s16 full_bpmax = bpmax + extra_borders; // Do nothing if not inside limits (+-1 because of neighbors) - if(blockpos_over_limit(blockpos_min - extra_borders) || - blockpos_over_limit(blockpos_max + extra_borders)) + if (blockpos_over_limit(full_bpmin) || + blockpos_over_limit(full_bpmax)) return false; data->seed = m_emerge->params.seed; - data->blockpos_min = blockpos_min; - data->blockpos_max = blockpos_max; + data->blockpos_min = bpmin; + data->blockpos_max = bpmax; data->blockpos_requested = blockpos; data->nodedef = m_gamedef->ndef(); /* Create the whole area of this and the neighboring blocks */ - { - //TimeTaker timer("initBlockMake() create area"); - - for(s16 x=blockpos_min.X-extra_borders.X; - x<=blockpos_max.X+extra_borders.X; x++) - for(s16 z=blockpos_min.Z-extra_borders.Z; - z<=blockpos_max.Z+extra_borders.Z; z++) - { - v2s16 sectorpos(x, z); - // Sector metadata is loaded from disk if not already loaded. - ServerMapSector *sector = createSector(sectorpos); - assert(sector); - (void) sector; - - for(s16 y=blockpos_min.Y-extra_borders.Y; - y<=blockpos_max.Y+extra_borders.Y; y++) - { - v3s16 p(x,y,z); - //MapBlock *block = createBlock(p); - // 1) get from memory, 2) load from disk - MapBlock *block = emergeBlock(p, false); - // 3) create a blank one - if(block == NULL) - { - block = createBlock(p); - - /* - Block gets sunlight if this is true. + for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++) + for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) { + v2s16 sectorpos(x, z); + // Sector metadata is loaded from disk if not already loaded. + ServerMapSector *sector = createSector(sectorpos); + FATAL_ERROR_IF(sector == NULL, "createSector() failed"); + + for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) { + v3s16 p(x, y, z); - Refer to the map generator heuristics. - */ - bool ug = m_emerge->isBlockUnderground(p); - block->setIsUnderground(ug); - } + MapBlock *block = emergeBlock(p, false); + if (block == NULL) { + block = createBlock(p); - // Lighting will not be valid after make_chunk is called - block->setLightingExpired(true); - // Lighting will be calculated - //block->setLightingExpired(false); + // Block gets sunlight if this is true. + // Refer to the map generator heuristics. + bool ug = m_emerge->isBlockUnderground(p); + block->setIsUnderground(ug); } } } @@ -2225,21 +2319,14 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) neighboring blocks */ - // The area that contains this block and it's neighbors - v3s16 bigarea_blocks_min = blockpos_min - extra_borders; - v3s16 bigarea_blocks_max = blockpos_max + extra_borders; + data->vmanip = new MMVManip(this); + data->vmanip->initialEmerge(full_bpmin, full_bpmax); - data->vmanip = new ManualMapVoxelManipulator(this); - //data->vmanip->setMap(this); - - // Add the area - { - //TimeTaker timer("initBlockMake() initialEmerge"); - data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max, false); - } - - // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE -/* for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) { + // Note: we may need this again at some point. +#if 0 + // Ensure none of the blocks to be generated were marked as + // containing CONTENT_IGNORE + for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) { for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) { for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) { core::map::Node *n; @@ -2251,124 +2338,62 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) n->setValue(flags); } } - }*/ + } +#endif // Data is ready now. return true; } void ServerMap::finishBlockMake(BlockMakeData *data, - std::map &changed_blocks) + std::map *changed_blocks) { - v3s16 blockpos_min = data->blockpos_min; - v3s16 blockpos_max = data->blockpos_max; - v3s16 blockpos_requested = data->blockpos_requested; - /*infostream<<"finishBlockMake(): ("<blockpos_min; + v3s16 bpmax = data->blockpos_max; - v3s16 extra_borders(1,1,1); + v3s16 extra_borders(1, 1, 1); + v3s16 full_bpmin = bpmin - extra_borders; + v3s16 full_bpmax = bpmax + extra_borders; - bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info; + bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info; + EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax)); - /*infostream<<"Resulting vmanip:"<vmanip.print(infostream);*/ + /* + Set lighting to non-expired state in all of them. + This is cheating, but it is not fast enough if all of them + would actually be updated. + */ + for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++) + for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) + for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) { + MapBlock *block = emergeBlock(v3s16(x, y, z), false); + if (!block) + continue; - // Make sure affected blocks are loaded - for(s16 x=blockpos_min.X-extra_borders.X; - x<=blockpos_max.X+extra_borders.X; x++) - for(s16 z=blockpos_min.Z-extra_borders.Z; - z<=blockpos_max.Z+extra_borders.Z; z++) - for(s16 y=blockpos_min.Y-extra_borders.Y; - y<=blockpos_max.Y+extra_borders.Y; y++) - { - v3s16 p(x, y, z); - // Load from disk if not already in memory - emergeBlock(p, false); + block->setLightingExpired(false); } /* Blit generated stuff to map NOTE: blitBackAll adds nearly everything to changed_blocks */ - { - // 70ms @cs=8 - //TimeTaker timer("finishBlockMake() blitBackAll"); - data->vmanip->blitBackAll(&changed_blocks); - } + data->vmanip->blitBackAll(changed_blocks); - EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size()); + EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" + << changed_blocks->size()); /* Copy transforming liquid information */ - while(data->transforming_liquid.size() > 0) - { - v3s16 p = data->transforming_liquid.pop_front(); - m_transforming_liquid.push_back(p); - } - - /* - Do stuff in central blocks - */ - - /* - Update lighting - */ - { -#if 0 - TimeTaker t("finishBlockMake lighting update"); - - core::map lighting_update_blocks; - - // Center blocks - for(s16 x=blockpos_min.X-extra_borders.X; - x<=blockpos_max.X+extra_borders.X; x++) - for(s16 z=blockpos_min.Z-extra_borders.Z; - z<=blockpos_max.Z+extra_borders.Z; z++) - for(s16 y=blockpos_min.Y-extra_borders.Y; - y<=blockpos_max.Y+extra_borders.Y; y++) - { - v3s16 p(x, y, z); - MapBlock *block = getBlockNoCreateNoEx(p); - assert(block); - lighting_update_blocks.insert(block->getPos(), block); - } - - updateLighting(lighting_update_blocks, changed_blocks); -#endif - - /* - Set lighting to non-expired state in all of them. - This is cheating, but it is not fast enough if all of them - would actually be updated. - */ - for(s16 x=blockpos_min.X-extra_borders.X; - x<=blockpos_max.X+extra_borders.X; x++) - for(s16 z=blockpos_min.Z-extra_borders.Z; - z<=blockpos_max.Z+extra_borders.Z; z++) - for(s16 y=blockpos_min.Y-extra_borders.Y; - y<=blockpos_max.Y+extra_borders.Y; y++) - { - v3s16 p(x, y, z); - MapBlock * block = getBlockNoCreateNoEx(p); - if (block != NULL) - block->setLightingExpired(false); - } - -#if 0 - if(enable_mapgen_debug_info == false) - t.stop(true); // Hide output -#endif + while (data->transforming_liquid.size()) { + m_transforming_liquid.push_back(data->transforming_liquid.front()); + data->transforming_liquid.pop_front(); } - /* - Go through changed blocks - */ - for(std::map::iterator i = changed_blocks.begin(); - i != changed_blocks.end(); ++i) - { - MapBlock *block = i->second; + for (std::map::iterator + it = changed_blocks->begin(); + it != changed_blocks->end(); ++it) { + MapBlock *block = it->second; if (!block) continue; /* @@ -2379,20 +2404,19 @@ void ServerMap::finishBlockMake(BlockMakeData *data, Set block as modified */ block->raiseModified(MOD_STATE_WRITE_NEEDED, - "finishBlockMake expireDayNightDiff"); + MOD_REASON_EXPIRE_DAYNIGHTDIFF); } /* Set central blocks as generated */ - for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++) - for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++) - for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++) - { - v3s16 p(x, y, z); - MapBlock *block = getBlockNoCreateNoEx(p); + for (s16 x = bpmin.X; x <= bpmax.X; x++) + for (s16 z = bpmin.Z; z <= bpmax.Z; z++) + for (s16 y = bpmin.Y; y <= bpmax.Y; y++) { + MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z)); if (!block) continue; + block->setGenerated(true); } @@ -2401,42 +2425,12 @@ void ServerMap::finishBlockMake(BlockMakeData *data, NOTE: Will be saved later. */ //save(MOD_STATE_WRITE_AT_UNLOAD); - - /*infostream<<"finishBlockMake() done for ("< MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) + const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT, + g_settings->getU16("map_generation_limit")); + if(p2d.X < -map_gen_limit / MAP_BLOCKSIZE + || p2d.X > map_gen_limit / MAP_BLOCKSIZE + || p2d.Y < -map_gen_limit / MAP_BLOCKSIZE + || p2d.Y > map_gen_limit / MAP_BLOCKSIZE) throw InvalidPositionException("createSector(): pos. over limit"); /* @@ -2501,7 +2497,7 @@ MapBlock * ServerMap::generateBlock( std::map &modified_blocks ) { - DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z); + DSTACKF("%s: p=(%d,%d,%d)", FUNCTION_NAME, p.X, p.Y, p.Z); /*infostream<<"generateBlock(): " <<"("< MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) + if (blockpos_over_limit(p)) throw InvalidPositionException("createBlock(): pos. over limit"); v2s16 p2d(p.X, p.Z); @@ -2634,7 +2625,7 @@ MapBlock * ServerMap::createBlock(v3s16 p) lighting on blocks for them. */ ServerMapSector *sector; - try{ + try { sector = (ServerMapSector*)createSector(p2d); assert(sector->getId() == MAPSECTOR_SERVER); } @@ -2675,7 +2666,7 @@ MapBlock * ServerMap::createBlock(v3s16 p) MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank) { DSTACKF("%s: p=(%d,%d,%d), create_blank=%d", - __FUNCTION_NAME, + FUNCTION_NAME, p.X, p.Y, p.Z, create_blank); { @@ -2747,7 +2738,7 @@ void ServerMap::updateVManip(v3s16 pos) if (!mg) return; - ManualMapVoxelManipulator *vm = mg->vm; + MMVManip *vm = mg->vm; if (!vm) return; @@ -2806,7 +2797,8 @@ s16 ServerMap::findGroundLevel(v2s16 p2d) } bool ServerMap::loadFromFolders() { - if(!dbase->Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ? + if (!dbase->initialized() && + !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) return true; return false; } @@ -2815,7 +2807,7 @@ void ServerMap::createDirs(std::string path) { if(fs::CreateAllDirs(path) == false) { - m_dout<::iterator i = m_sectors.begin(); - i != m_sectors.end(); ++i) - { + i != m_sectors.end(); ++i) { ServerMapSector *sector = (ServerMapSector*)i->second; assert(sector->getId() == MAPSECTOR_SERVER); - if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN) - { + if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN) { saveSectorMeta(sector); sector_meta_count++; } - std::list blocks; + + MapBlockVect blocks; sector->getBlocks(blocks); - for(std::list::iterator j = blocks.begin(); - j != blocks.end(); ++j) - { + for(MapBlockVect::iterator j = blocks.begin(); + j != blocks.end(); ++j) { MapBlock *block = *j; block_count_all++; - if(block->getModified() >= (u32)save_level) - { + if(block->getModified() >= (u32)save_level) { // Lazy beginSave() - if(!save_started){ + if(!save_started) { beginSave(); save_started = true; } - modprofiler.add(block->getModifiedReason(), 1); + modprofiler.add(block->getModifiedReasonString(), 1); saveBlock(block); block_count++; @@ -2964,6 +2952,7 @@ void ServerMap::save(ModifiedState save_level) } } } + if(save_started) endSave(); @@ -2971,8 +2960,7 @@ void ServerMap::save(ModifiedState save_level) Only print if something happened or saved whole map */ if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0 - || block_count != 0) - { + || block_count != 0) { infostream<<"ServerMap: Written: " < &dst) +void ServerMap::listAllLoadableBlocks(std::vector &dst) { - if(loadFromFolders()){ - errorstream<<"Map::listAllLoadableBlocks(): Result will be missing " - <<"all blocks that are stored in flat files"<listAllLoadableBlocks(dst); } -void ServerMap::listAllLoadedBlocks(std::list &dst) +void ServerMap::listAllLoadedBlocks(std::vector &dst) { for(std::map::iterator si = m_sectors.begin(); si != m_sectors.end(); ++si) { MapSector *sector = si->second; - std::list blocks; + MapBlockVect blocks; sector->getBlocks(blocks); - for(std::list::iterator i = blocks.begin(); - i != blocks.end(); ++i) - { - MapBlock *block = (*i); - v3s16 p = block->getPos(); + for(MapBlockVect::iterator i = blocks.begin(); + i != blocks.end(); ++i) { + v3s16 p = (*i)->getPos(); dst.push_back(p); } } @@ -3015,28 +3001,22 @@ void ServerMap::listAllLoadedBlocks(std::list &dst) void ServerMap::saveMapMeta() { - DSTACK(__FUNCTION_NAME); - - /*infostream<<"ServerMap::saveMapMeta(): " - <<"seed="<saveParamsToSettings(¶ms); - params.writeLines(ss); + m_emerge->params.save(conf); + conf.writeLines(oss); - ss<<"[end_of_params]\n"; + oss << "[end_of_params]\n"; - if(!fs::safeWriteToFile(fullpath, ss.str())) - { - infostream<<"ERROR: ServerMap::saveMapMeta(): " - <<"could not write "<loadParamsFromSettings(¶ms); + m_emerge->params.load(conf); verbosestream << "ServerMap::loadMapMeta(): seed=" << m_emerge->params.seed << std::endl; @@ -3070,7 +3050,7 @@ void ServerMap::loadMapMeta() void ServerMap::saveSectorMeta(ServerMapSector *sector) { - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); // Format used for writing u8 version = SER_FMT_VER_HIGHEST_WRITE; // Get destination @@ -3091,7 +3071,7 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector) MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load) { - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); // Get destination v2s16 p2d = getSectorPos(sectordir); @@ -3132,9 +3112,7 @@ MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load bool ServerMap::loadSectorMeta(v2s16 p2d) { - DSTACK(__FUNCTION_NAME); - - MapSector *sector = NULL; + DSTACK(FUNCTION_NAME); // The directory layout we're going to load from. // 1 - original sectors/xxxxzzzz/ @@ -3155,7 +3133,7 @@ bool ServerMap::loadSectorMeta(v2s16 p2d) } try{ - sector = loadSectorMeta(sectordir, loadlayout != 2); + loadSectorMeta(sectordir, loadlayout != 2); } catch(InvalidFilenameException &e) { @@ -3176,7 +3154,7 @@ bool ServerMap::loadSectorMeta(v2s16 p2d) #if 0 bool ServerMap::loadSectorFull(v2s16 p2d) { - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); MapSector *sector = NULL; @@ -3245,6 +3223,27 @@ bool ServerMap::loadSectorFull(v2s16 p2d) } #endif +Database *ServerMap::createDatabase( + const std::string &name, + const std::string &savedir, + Settings &conf) +{ + if (name == "sqlite3") + return new Database_SQLite3(savedir); + if (name == "dummy") + return new Database_Dummy(); + #if USE_LEVELDB + else if (name == "leveldb") + return new Database_LevelDB(savedir); + #endif + #if USE_REDIS + else if (name == "redis") + return new Database_Redis(conf); + #endif + else + throw BaseException(std::string("Database backend ") + name + " not supported."); +} + void ServerMap::beginSave() { dbase->beginSave(); @@ -3266,7 +3265,7 @@ bool ServerMap::saveBlock(MapBlock *block, Database *db) // Dummy blocks are not written if (block->isDummy()) { - errorstream << "WARNING: saveBlock: Not writing dummy block " + warningstream << "saveBlock: Not writing dummy block " << PP(p3d) << std::endl; return true; } @@ -3284,7 +3283,7 @@ bool ServerMap::saveBlock(MapBlock *block, Database *db) std::string data = o.str(); bool ret = db->saveBlock(p3d, data); - if(ret) { + if (ret) { // We just wrote it to the disk so clear modified flag block->resetModified(); } @@ -3294,9 +3293,9 @@ bool ServerMap::saveBlock(MapBlock *block, Database *db) void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load) { - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); - std::string fullpath = sectordir+DIR_DELIM+blockfile; + std::string fullpath = sectordir + DIR_DELIM + blockfile; try { std::ifstream is(fullpath.c_str(), std::ios_base::binary); @@ -3356,13 +3355,13 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, } catch(SerializationError &e) { - infostream<<"WARNING: Invalid block data on disk " + warningstream<<"Invalid block data on disk " <<"fullpath="<deleteBlock(blockpos)) + return false; + + MapBlock *block = getBlockNoCreateNoEx(blockpos); + if (block) { + v2s16 p2d(blockpos.X, blockpos.Z); + MapSector *sector = getSectorNoGenerateNoEx(p2d); + if (!sector) + return false; + sector->deleteBlock(block); + } + + return true; +} + void ServerMap::PrintInfo(std::ostream &out) { out<<"ServerMap: "; } -ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map): +MMVManip::MMVManip(Map *map): VoxelManipulator(), m_is_dirty(false), m_create_area(false), @@ -3521,12 +3537,12 @@ ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map): { } -ManualMapVoxelManipulator::~ManualMapVoxelManipulator() +MMVManip::~MMVManip() { } -void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min, - v3s16 blockpos_max, bool load_if_inexistent) +void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, + bool load_if_inexistent) { TimeTaker timer1("initialEmerge", &emerge_time); @@ -3584,8 +3600,7 @@ void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min, block = svrmap->emergeBlock(p, false); if (block == NULL) block = svrmap->createBlock(p); - else - block->copyTo(*this); + block->copyTo(*this); } else { flags |= VMANIP_BLOCK_DATA_INEXIST; @@ -3614,9 +3629,8 @@ void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min, m_is_dirty = false; } -void ManualMapVoxelManipulator::blitBackAll( - std::map *modified_blocks, - bool overwrite_generated) +void MMVManip::blitBackAll(std::map *modified_blocks, + bool overwrite_generated) { if(m_area.getExtent() == v3s16(0,0,0)) return;