diff options
Diffstat (limited to 'src/map.cpp')
-rw-r--r-- | src/map.cpp | 175 |
1 files changed, 130 insertions, 45 deletions
diff --git a/src/map.cpp b/src/map.cpp index a11bbb96a..a53680065 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -102,7 +102,7 @@ MapSector * Map::getSectorNoGenerateNoLock(v2s16 p) return sector; } - std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p); + auto n = m_sectors.find(p); if (n == m_sectors.end()) return NULL; @@ -165,24 +165,32 @@ MapNode Map::getNode(v3s16 p, bool *is_valid_position) return node; } -// throws InvalidPositionException if not found -void Map::setNode(v3s16 p, MapNode & n) +static void set_node_in_block(MapBlock *block, v3s16 relpos, MapNode n) { - v3s16 blockpos = getNodeBlockPos(p); - MapBlock *block = getBlockNoCreate(blockpos); - v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; // Never allow placing CONTENT_IGNORE, it causes problems if(n.getContent() == CONTENT_IGNORE){ + const NodeDefManager *nodedef = block->getParent()->getNodeDefManager(); + v3s16 blockpos = block->getPos(); + v3s16 p = blockpos * MAP_BLOCKSIZE + relpos; bool temp_bool; - errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE" + errorstream<<"Not allowing to place CONTENT_IGNORE" <<" while trying to replace \"" - <<m_nodedef->get(block->getNodeNoCheck(relpos, &temp_bool)).name + <<nodedef->get(block->getNodeNoCheck(relpos, &temp_bool)).name <<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl; return; } block->setNodeNoCheck(relpos, n); } +// throws InvalidPositionException if not found +void Map::setNode(v3s16 p, MapNode & n) +{ + v3s16 blockpos = getNodeBlockPos(p); + MapBlock *block = getBlockNoCreate(blockpos); + v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; + set_node_in_block(block, relpos, n); +} + void Map::addNodeAndUpdate(v3s16 p, MapNode n, std::map<v3s16, MapBlock*> &modified_blocks, bool remove_metadata) @@ -190,8 +198,14 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, // Collect old node for rollback RollbackNode rollback_oldnode(this, p, m_gamedef); + v3s16 blockpos = getNodeBlockPos(p); + MapBlock *block = getBlockNoCreate(blockpos); + if (block->isDummy()) + throw InvalidPositionException(); + v3s16 relpos = p - blockpos * MAP_BLOCKSIZE; + // This is needed for updating the lighting - MapNode oldnode = getNode(p); + MapNode oldnode = block->getNodeUnsafe(relpos); // Remove node metadata if (remove_metadata) { @@ -199,18 +213,29 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, } // Set the node on the map - // Ignore light (because calling voxalgo::update_lighting_nodes) - n.setLight(LIGHTBANK_DAY, 0, m_nodedef); - n.setLight(LIGHTBANK_NIGHT, 0, m_nodedef); - setNode(p, n); + const ContentFeatures &cf = m_nodedef->get(n); + const ContentFeatures &oldcf = m_nodedef->get(oldnode); + if (cf.lightingEquivalent(oldcf)) { + // No light update needed, just copy over the old light. + n.setLight(LIGHTBANK_DAY, oldnode.getLightRaw(LIGHTBANK_DAY, oldcf), cf); + n.setLight(LIGHTBANK_NIGHT, oldnode.getLightRaw(LIGHTBANK_NIGHT, oldcf), cf); + set_node_in_block(block, relpos, n); + + modified_blocks[blockpos] = block; + } else { + // Ignore light (because calling voxalgo::update_lighting_nodes) + n.setLight(LIGHTBANK_DAY, 0, cf); + n.setLight(LIGHTBANK_NIGHT, 0, cf); + set_node_in_block(block, relpos, n); - // Update lighting - std::vector<std::pair<v3s16, MapNode> > oldnodes; - oldnodes.emplace_back(p, oldnode); - voxalgo::update_lighting_nodes(this, oldnodes, modified_blocks); + // Update lighting + std::vector<std::pair<v3s16, MapNode> > oldnodes; + oldnodes.emplace_back(p, oldnode); + voxalgo::update_lighting_nodes(this, oldnodes, modified_blocks); - for (auto &modified_block : modified_blocks) { - modified_block.second->expireDayNightDiff(); + for (auto &modified_block : modified_blocks) { + modified_block.second->expireDayNightDiff(); + } } // Report for rollback @@ -221,22 +246,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, action.setSetNode(p, rollback_oldnode, rollback_newnode); m_gamedef->rollback()->reportAction(action); } - - /* - Add neighboring liquid nodes and this node to transform queue. - (it's vital for the node itself to get updated last, if it was removed.) - */ - - for (const v3s16 &dir : g_7dirs) { - v3s16 p2 = p + dir; - - bool is_valid_position; - MapNode n2 = getNode(p2, &is_valid_position); - if(is_valid_position && - (m_nodedef->get(n2).isLiquid() || - n2.getContent() == CONTENT_AIR)) - m_transforming_liquid.push_back(p2); - } } void Map::removeNodeAndUpdate(v3s16 p, @@ -314,10 +323,10 @@ struct TimeOrderedMapBlock { /* Updates usage timers */ -void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks, +void Map::timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks, std::vector<v3s16> *unloaded_blocks) { - bool save_before_unloading = (mapType() == MAPTYPE_SERVER); + bool save_before_unloading = maySaveBlocks(); // Profile modified reasons Profiler modprofiler; @@ -327,10 +336,11 @@ void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks, u32 saved_blocks_count = 0; u32 block_count_all = 0; + const auto start_time = porting::getTimeUs(); beginSave(); // If there is no practical limit, we spare creation of mapblock_queue - if (max_loaded_blocks == U32_MAX) { + if (max_loaded_blocks < 0) { for (auto §or_it : m_sectors) { MapSector *sector = sector_it.second; @@ -368,6 +378,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks, } } + // Delete sector if we emptied it if (all_blocks_deleted) { sector_deletion_queue.push_back(sector_it.first); } @@ -386,8 +397,9 @@ void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks, } } 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 + while (!mapblock_queue.empty() && ((s32)mapblock_queue.size() > max_loaded_blocks || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) { TimeOrderedMapBlock b = mapblock_queue.top(); mapblock_queue.pop(); @@ -416,6 +428,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks, deleted_blocks_count++; block_count_all--; } + // Delete empty sectors for (auto §or_it : m_sectors) { if (sector_it.second->empty()) { @@ -423,7 +436,11 @@ void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks, } } } + endSave(); + const auto end_time = porting::getTimeUs(); + + reportMetrics(end_time - start_time, saved_blocks_count, block_count_all); // Finally delete the empty sectors deleteSectors(sector_deletion_queue); @@ -502,11 +519,11 @@ struct NodeNeighbor { { } }; -void Map::transforming_liquid_add(v3s16 p) { +void ServerMap::transforming_liquid_add(v3s16 p) { m_transforming_liquid.push_back(p); } -void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks, +void ServerMap::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks, ServerEnvironment *env) { u32 loopcount = 0; @@ -1209,7 +1226,12 @@ ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef, m_savedir = savedir; m_map_saving_enabled = false; - m_save_time_counter = mb->addCounter("minetest_core_map_save_time", "Map save time (in nanoseconds)"); + m_save_time_counter = mb->addCounter( + "minetest_map_save_time", "Time spent saving blocks (in microseconds)"); + m_save_count_counter = mb->addCounter( + "minetest_map_saved_blocks", "Number of blocks saved"); + m_loaded_blocks_gauge = mb->addGauge( + "minetest_map_loaded_blocks", "Number of loaded blocks"); m_map_compression_level = rangelim(g_settings->getS16("map_compression_level_disk"), -1, 9); @@ -1540,6 +1562,29 @@ bool ServerMap::isBlockInQueue(v3s16 pos) return m_emerge && m_emerge->isBlockInQueue(pos); } +void ServerMap::addNodeAndUpdate(v3s16 p, MapNode n, + std::map<v3s16, MapBlock*> &modified_blocks, + bool remove_metadata) +{ + Map::addNodeAndUpdate(p, n, modified_blocks, remove_metadata); + + /* + Add neighboring liquid nodes and this node to transform queue. + (it's vital for the node itself to get updated last, if it was removed.) + */ + + for (const v3s16 &dir : g_7dirs) { + v3s16 p2 = p + dir; + + bool is_valid_position; + MapNode n2 = getNode(p2, &is_valid_position); + if(is_valid_position && + (m_nodedef->get(n2).isLiquid() || + n2.getContent() == CONTENT_AIR)) + m_transforming_liquid.push_back(p2); + } +} + // N.B. This requires no synchronization, since data will not be modified unless // the VoxelManipulator being updated belongs to the same thread. void ServerMap::updateVManip(v3s16 pos) @@ -1562,6 +1607,13 @@ void ServerMap::updateVManip(v3s16 pos) vm->m_is_dirty = true; } +void ServerMap::reportMetrics(u64 save_time_us, u32 saved_blocks, u32 all_blocks) +{ + m_loaded_blocks_gauge->set(all_blocks); + m_save_time_counter->increment(save_time_us); + m_save_count_counter->increment(saved_blocks); +} + void ServerMap::save(ModifiedState save_level) { if (!m_map_saving_enabled) { @@ -1569,7 +1621,7 @@ void ServerMap::save(ModifiedState save_level) return; } - u64 start_time = porting::getTimeNs(); + const auto start_time = porting::getTimeUs(); if(save_level == MOD_STATE_CLEAN) infostream<<"ServerMap: Saving whole map, this can take time." @@ -1630,8 +1682,8 @@ void ServerMap::save(ModifiedState save_level) modprofiler.print(infostream); } - auto end_time = porting::getTimeNs(); - m_save_time_counter->increment(end_time - start_time); + const auto end_time = porting::getTimeUs(); + reportMetrics(end_time - start_time, block_count, block_count_all); } void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst) @@ -1864,6 +1916,7 @@ MMVManip::MMVManip(Map *map): VoxelManipulator(), m_map(map) { + assert(map); } void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, @@ -1871,6 +1924,8 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, { TimeTaker timer1("initialEmerge", &emerge_time); + assert(m_map); + // Units of these are MapBlocks v3s16 p_min = blockpos_min; v3s16 p_max = blockpos_max; @@ -1954,6 +2009,7 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks, { if(m_area.getExtent() == v3s16(0,0,0)) return; + assert(m_map); /* Copy data of all blocks @@ -1974,4 +2030,33 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks, } } +MMVManip *MMVManip::clone() const +{ + MMVManip *ret = new MMVManip(); + + const s32 size = m_area.getVolume(); + ret->m_area = m_area; + if (m_data) { + ret->m_data = new MapNode[size]; + memcpy(ret->m_data, m_data, size * sizeof(MapNode)); + } + if (m_flags) { + ret->m_flags = new u8[size]; + memcpy(ret->m_flags, m_flags, size * sizeof(u8)); + } + + ret->m_is_dirty = m_is_dirty; + // Even if the copy is disconnected from a map object keep the information + // needed to write it back to one + ret->m_loaded_blocks = m_loaded_blocks; + + return ret; +} + +void MMVManip::reparent(Map *map) +{ + assert(map && !m_map); + m_map = map; +} + //END |