diff --git a/src/emerge.cpp b/src/emerge.cpp index e98ede145c..825b50d5d1 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -596,8 +596,7 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata, Perform post-processing on blocks (invalidate lighting, queue liquid transforms, etc.) to finish block make */ - m_map->finishBlockMake(bmdata, modified_blocks, - m_server->m_env->getGameTime()); + m_map->finishBlockMake(bmdata, modified_blocks, m_server->m_env); MapBlock *block = m_map->getBlockNoCreateNoEx(pos); if (!block) { diff --git a/src/servermap.cpp b/src/servermap.cpp index 0c04cad39f..01fe04a3a9 100644 --- a/src/servermap.cpp +++ b/src/servermap.cpp @@ -279,10 +279,11 @@ void ServerMap::cancelBlockMake(BlockMakeData *data) } void ServerMap::finishBlockMake(BlockMakeData *data, - std::map *changed_blocks, u32 now) + std::map *changed_blocks, ServerEnvironment *env) { assert(data); assert(changed_blocks); + u32 now = env->getGameTime(); const v3s16 bpmin = data->blockpos_min; const v3s16 bpmax = data->blockpos_max; @@ -299,7 +300,13 @@ void ServerMap::finishBlockMake(BlockMakeData *data, << changed_blocks->size()); /* - Copy transforming liquid information + Process the chunk's liquid queue now. + This avoids sending many duplicate block updates. + */ + transformLiquidsLocal(*changed_blocks, data->transforming_liquid, env, g_settings->getS32("liquid_loop_max")); + + /* + Copy remaining (if any) transforming liquid information */ while (!data->transforming_liquid.empty()) { m_transforming_liquid.push_back(data->transforming_liquid.front()); @@ -919,11 +926,10 @@ void ServerMap::transforming_liquid_add(v3s16 p) m_transforming_liquid.push_back(p); } -void ServerMap::transformLiquids(std::map &modified_blocks, - ServerEnvironment *env) +void ServerMap::transformLiquidsLocal(std::map &modified_blocks, UniqueQueue &liquid_queue, + ServerEnvironment *env, u32 liquid_loop_max) { u32 loopcount = 0; - u32 initial_size = m_transforming_liquid.size(); /*if(initial_size != 0) infostream<<"transformLiquids(): initial_size="< &modified_blocks, std::vector check_for_falling; - u32 liquid_loop_max = g_settings->getS32("liquid_loop_max"); - u32 loop_max = liquid_loop_max; - - while (m_transforming_liquid.size() != 0) + while (!liquid_queue.empty()) { // This should be done here so that it is done when continue is used - if (loopcount >= initial_size || loopcount >= loop_max) + if (loopcount >= liquid_loop_max) break; loopcount++; /* Get a queued transforming liquid node */ - v3s16 p0 = m_transforming_liquid.front(); - m_transforming_liquid.pop_front(); + v3s16 p0 = liquid_queue.front(); + liquid_queue.pop_front(); MapNode n0 = getNode(p0); @@ -1025,7 +1028,7 @@ void ServerMap::transformLiquids(std::map &modified_blocks, // should be enqueded for transformation regardless of whether the // current node changes or not. if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE) - m_transforming_liquid.push_back(npos); + liquid_queue.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) flowing_down = true; @@ -1220,15 +1223,15 @@ void ServerMap::transformLiquids(std::map &modified_blocks, // make sure source flows into all neighboring nodes for (u16 i = 0; i < num_flows; i++) if (flows[i].t != NEIGHBOR_UPPER) - m_transforming_liquid.push_back(flows[i].p); + liquid_queue.push_back(flows[i].p); for (u16 i = 0; i < num_airs; i++) if (airs[i].t != NEIGHBOR_UPPER) - m_transforming_liquid.push_back(airs[i].p); + liquid_queue.push_back(airs[i].p); break; case LIQUID_NONE: // this flow has turned to air; neighboring flows might need to do the same for (u16 i = 0; i < num_flows; i++) - m_transforming_liquid.push_back(flows[i].p); + liquid_queue.push_back(flows[i].p); break; case LiquidType_END: break; @@ -1237,7 +1240,7 @@ void ServerMap::transformLiquids(std::map &modified_blocks, //infostream<<"Map::transformLiquids(): loopcount="< &modified_blocks, } env->getScriptIface()->on_liquid_transformed(changed_nodes); +} + +void ServerMap::transformLiquids(std::map &modified_blocks, + ServerEnvironment *env) +{ + // process the whole queue at most once, to rate-limit + u32 liquid_loop_max = std::min(m_transforming_liquid.size(), g_settings->getS32("liquid_loop_max")); + + transformLiquidsLocal(modified_blocks, m_transforming_liquid, env, liquid_loop_max); /* ---------------------------------------------------------------------- * Manage the queue so that it does not grow indefinitely diff --git a/src/servermap.h b/src/servermap.h index d44823de2a..558a86bf9c 100644 --- a/src/servermap.h +++ b/src/servermap.h @@ -66,7 +66,7 @@ public: /// @brief write data back to map after mapgen /// @param now current game time void finishBlockMake(BlockMakeData *data, - std::map *changed_blocks, u32 now); + std::map *changed_blocks, ServerEnvironment *env); void cancelBlockMake(BlockMakeData *data); /* @@ -158,7 +158,8 @@ public: void transformLiquids(std::map & modified_blocks, ServerEnvironment *env); - + void transformLiquidsLocal(std::map &modified_blocks, UniqueQueue &liquid_queue, + ServerEnvironment *env, u32 liquid_loop_max); void transforming_liquid_add(v3s16 p); MapSettingsManager settings_mgr;