3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "mapsector.h"
25 #include "voxelalgorithms.h"
27 #include "serialization.h"
28 #include "nodemetadata.h"
34 #include "util/directiontables.h"
35 #include "util/basic_macros.h"
36 #include "rollback_interface.h"
37 #include "environment.h"
38 #include "reflowscan.h"
40 #include "mapgen/mapgen_v6.h"
41 #include "mapgen/mg_biome.h"
44 #include "database/database.h"
45 #include "database/database-dummy.h"
46 #include "database/database-sqlite3.h"
47 #include "script/scripting_server.h"
51 #include "database/database-leveldb.h"
54 #include "database/database-redis.h"
57 #include "database/database-postgresql.h"
65 Map::Map(IGameDef *gamedef):
67 m_nodedef(gamedef->ndef())
76 for (auto §or : m_sectors) {
81 void Map::addEventReceiver(MapEventReceiver *event_receiver)
83 m_event_receivers.insert(event_receiver);
86 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
88 m_event_receivers.erase(event_receiver);
91 void Map::dispatchEvent(const MapEditEvent &event)
93 for (MapEventReceiver *event_receiver : m_event_receivers) {
94 event_receiver->onMapEditEvent(event);
98 MapSector * Map::getSectorNoGenerateNoLock(v2s16 p)
100 if(m_sector_cache != NULL && p == m_sector_cache_p){
101 MapSector * sector = m_sector_cache;
105 std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
107 if (n == m_sectors.end())
110 MapSector *sector = n->second;
112 // Cache the last result
113 m_sector_cache_p = p;
114 m_sector_cache = sector;
119 MapSector * Map::getSectorNoGenerate(v2s16 p)
121 return getSectorNoGenerateNoLock(p);
124 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
126 v2s16 p2d(p3d.X, p3d.Z);
127 MapSector * sector = getSectorNoGenerate(p2d);
130 MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
134 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
136 MapBlock *block = getBlockNoCreateNoEx(p3d);
138 throw InvalidPositionException();
142 void Map::listAllLoadedBlocks(std::vector<v3s16> &dst)
144 for (auto §or_it : m_sectors) {
145 MapSector *sector = sector_it.second;
148 sector->getBlocks(blocks);
150 for (MapBlock *block : blocks) {
151 v3s16 p = block->getPos();
157 bool Map::isNodeUnderground(v3s16 p)
159 v3s16 blockpos = getNodeBlockPos(p);
160 MapBlock *block = getBlockNoCreateNoEx(blockpos);
161 return block && block->getIsUnderground();
164 bool Map::isValidPosition(v3s16 p)
166 v3s16 blockpos = getNodeBlockPos(p);
167 MapBlock *block = getBlockNoCreateNoEx(blockpos);
168 return (block != NULL);
171 // Returns a CONTENT_IGNORE node if not found
172 MapNode Map::getNode(v3s16 p, bool *is_valid_position)
174 v3s16 blockpos = getNodeBlockPos(p);
175 MapBlock *block = getBlockNoCreateNoEx(blockpos);
177 if (is_valid_position != NULL)
178 *is_valid_position = false;
179 return {CONTENT_IGNORE};
182 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
184 MapNode node = block->getNodeNoCheck(relpos, &is_valid_p);
185 if (is_valid_position != NULL)
186 *is_valid_position = is_valid_p;
190 // throws InvalidPositionException if not found
191 void Map::setNode(v3s16 p, MapNode & n)
193 v3s16 blockpos = getNodeBlockPos(p);
194 MapBlock *block = getBlockNoCreate(blockpos);
195 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
196 // Never allow placing CONTENT_IGNORE, it causes problems
197 if(n.getContent() == CONTENT_IGNORE){
199 errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE"
200 <<" while trying to replace \""
201 <<m_nodedef->get(block->getNodeNoCheck(relpos, &temp_bool)).name
202 <<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
205 block->setNodeNoCheck(relpos, n);
208 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
209 std::map<v3s16, MapBlock*> &modified_blocks,
210 bool remove_metadata)
212 // Collect old node for rollback
213 RollbackNode rollback_oldnode(this, p, m_gamedef);
215 // This is needed for updating the lighting
216 MapNode oldnode = getNode(p);
218 // Remove node metadata
219 if (remove_metadata) {
220 removeNodeMetadata(p);
223 // Set the node on the map
224 // Ignore light (because calling voxalgo::update_lighting_nodes)
225 n.setLight(LIGHTBANK_DAY, 0, m_nodedef);
226 n.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
230 std::vector<std::pair<v3s16, MapNode> > oldnodes;
231 oldnodes.emplace_back(p, oldnode);
232 voxalgo::update_lighting_nodes(this, oldnodes, modified_blocks);
234 for (auto &modified_block : modified_blocks) {
235 modified_block.second->expireDayNightDiff();
238 // Report for rollback
239 if(m_gamedef->rollback())
241 RollbackNode rollback_newnode(this, p, m_gamedef);
242 RollbackAction action;
243 action.setSetNode(p, rollback_oldnode, rollback_newnode);
244 m_gamedef->rollback()->reportAction(action);
248 Add neighboring liquid nodes and this node to transform queue.
249 (it's vital for the node itself to get updated last, if it was removed.)
252 for (const v3s16 &dir : g_7dirs) {
255 bool is_valid_position;
256 MapNode n2 = getNode(p2, &is_valid_position);
257 if(is_valid_position &&
258 (m_nodedef->get(n2).isLiquid() ||
259 n2.getContent() == CONTENT_AIR))
260 m_transforming_liquid.push_back(p2);
264 void Map::removeNodeAndUpdate(v3s16 p,
265 std::map<v3s16, MapBlock*> &modified_blocks)
267 addNodeAndUpdate(p, MapNode(CONTENT_AIR), modified_blocks, true);
270 bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
273 event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
277 bool succeeded = true;
279 std::map<v3s16, MapBlock*> modified_blocks;
280 addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
282 // Copy modified_blocks to event
283 for (auto &modified_block : modified_blocks) {
284 event.modified_blocks.insert(modified_block.first);
287 catch(InvalidPositionException &e){
291 dispatchEvent(event);
296 bool Map::removeNodeWithEvent(v3s16 p)
299 event.type = MEET_REMOVENODE;
302 bool succeeded = true;
304 std::map<v3s16, MapBlock*> modified_blocks;
305 removeNodeAndUpdate(p, modified_blocks);
307 // Copy modified_blocks to event
308 for (auto &modified_block : modified_blocks) {
309 event.modified_blocks.insert(modified_block.first);
312 catch(InvalidPositionException &e){
316 dispatchEvent(event);
321 struct TimeOrderedMapBlock {
325 TimeOrderedMapBlock(MapSector *sect, MapBlock *block) :
330 bool operator<(const TimeOrderedMapBlock &b) const
332 return block->getUsageTimer() < b.block->getUsageTimer();
339 void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
340 std::vector<v3s16> *unloaded_blocks)
342 bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
344 // Profile modified reasons
345 Profiler modprofiler;
347 std::vector<v2s16> sector_deletion_queue;
348 u32 deleted_blocks_count = 0;
349 u32 saved_blocks_count = 0;
350 u32 block_count_all = 0;
354 // If there is no practical limit, we spare creation of mapblock_queue
355 if (max_loaded_blocks == U32_MAX) {
356 for (auto §or_it : m_sectors) {
357 MapSector *sector = sector_it.second;
359 bool all_blocks_deleted = true;
362 sector->getBlocks(blocks);
364 for (MapBlock *block : blocks) {
365 block->incrementUsageTimer(dtime);
367 if (block->refGet() == 0
368 && block->getUsageTimer() > unload_timeout) {
369 v3s16 p = block->getPos();
372 if (block->getModified() != MOD_STATE_CLEAN
373 && save_before_unloading) {
374 modprofiler.add(block->getModifiedReasonString(), 1);
375 if (!saveBlock(block))
377 saved_blocks_count++;
380 // Delete from memory
381 sector->deleteBlock(block);
384 unloaded_blocks->push_back(p);
386 deleted_blocks_count++;
388 all_blocks_deleted = false;
393 if (all_blocks_deleted) {
394 sector_deletion_queue.push_back(sector_it.first);
398 std::priority_queue<TimeOrderedMapBlock> mapblock_queue;
399 for (auto §or_it : m_sectors) {
400 MapSector *sector = sector_it.second;
403 sector->getBlocks(blocks);
405 for (MapBlock *block : blocks) {
406 block->incrementUsageTimer(dtime);
407 mapblock_queue.push(TimeOrderedMapBlock(sector, block));
410 block_count_all = mapblock_queue.size();
411 // Delete old blocks, and blocks over the limit from the memory
412 while (!mapblock_queue.empty() && (mapblock_queue.size() > max_loaded_blocks
413 || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) {
414 TimeOrderedMapBlock b = mapblock_queue.top();
415 mapblock_queue.pop();
417 MapBlock *block = b.block;
419 if (block->refGet() != 0)
422 v3s16 p = block->getPos();
425 if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
426 modprofiler.add(block->getModifiedReasonString(), 1);
427 if (!saveBlock(block))
429 saved_blocks_count++;
432 // Delete from memory
433 b.sect->deleteBlock(block);
436 unloaded_blocks->push_back(p);
438 deleted_blocks_count++;
441 // Delete empty sectors
442 for (auto §or_it : m_sectors) {
443 if (sector_it.second->empty()) {
444 sector_deletion_queue.push_back(sector_it.first);
450 // Finally delete the empty sectors
451 deleteSectors(sector_deletion_queue);
453 if(deleted_blocks_count != 0)
455 PrintInfo(infostream); // ServerMap/ClientMap:
456 infostream<<"Unloaded "<<deleted_blocks_count
457 <<" blocks from memory";
458 if(save_before_unloading)
459 infostream<<", of which "<<saved_blocks_count<<" were written";
460 infostream<<", "<<block_count_all<<" blocks in memory";
461 infostream<<"."<<std::endl;
462 if(saved_blocks_count != 0){
463 PrintInfo(infostream); // ServerMap/ClientMap:
464 infostream<<"Blocks modified by: "<<std::endl;
465 modprofiler.print(infostream);
470 void Map::unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks)
472 timerUpdate(0.0, -1.0, 0, unloaded_blocks);
475 void Map::deleteSectors(std::vector<v2s16> §orList)
477 for (v2s16 j : sectorList) {
478 MapSector *sector = m_sectors[j];
479 // If sector is in sector cache, remove it from there
480 if(m_sector_cache == sector)
481 m_sector_cache = NULL;
482 // Remove from map and delete
488 void Map::PrintInfo(std::ostream &out)
493 #define WATER_DROP_BOOST 4
495 const static v3s16 liquid_6dirs[6] = {
496 // order: upper before same level before lower
505 enum NeighborType : u8 {
511 struct NodeNeighbor {
517 : n(CONTENT_AIR), t(NEIGHBOR_SAME_LEVEL)
520 NodeNeighbor(const MapNode &node, NeighborType n_type, const v3s16 &pos)
527 void Map::transforming_liquid_add(v3s16 p) {
528 m_transforming_liquid.push_back(p);
531 void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks,
532 ServerEnvironment *env)
535 u32 initial_size = m_transforming_liquid.size();
537 /*if(initial_size != 0)
538 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
540 // list of nodes that due to viscosity have not reached their max level height
541 std::deque<v3s16> must_reflow;
543 std::vector<std::pair<v3s16, MapNode> > changed_nodes;
545 u32 liquid_loop_max = g_settings->getS32("liquid_loop_max");
546 u32 loop_max = liquid_loop_max;
550 /* If liquid_loop_max is not keeping up with the queue size increase
551 * loop_max up to a maximum of liquid_loop_max * dedicated_server_step.
553 if (m_transforming_liquid.size() > loop_max * 2) {
555 float server_step = g_settings->getFloat("dedicated_server_step");
556 if (m_transforming_liquid_loop_count_multiplier - 1.0 < server_step)
557 m_transforming_liquid_loop_count_multiplier *= 1.0 + server_step / 10;
559 m_transforming_liquid_loop_count_multiplier = 1.0;
562 loop_max *= m_transforming_liquid_loop_count_multiplier;
565 while (m_transforming_liquid.size() != 0)
567 // This should be done here so that it is done when continue is used
568 if (loopcount >= initial_size || loopcount >= loop_max)
573 Get a queued transforming liquid node
575 v3s16 p0 = m_transforming_liquid.front();
576 m_transforming_liquid.pop_front();
578 MapNode n0 = getNode(p0);
581 Collect information about current node
583 s8 liquid_level = -1;
584 // The liquid node which will be placed there if
585 // the liquid flows into this node.
586 content_t liquid_kind = CONTENT_IGNORE;
587 // The node which will be placed there if liquid
588 // can't flow into this node.
589 content_t floodable_node = CONTENT_AIR;
590 const ContentFeatures &cf = m_nodedef->get(n0);
591 LiquidType liquid_type = cf.liquid_type;
592 switch (liquid_type) {
594 liquid_level = LIQUID_LEVEL_SOURCE;
595 liquid_kind = cf.liquid_alternative_flowing_id;
598 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
599 liquid_kind = n0.getContent();
602 // if this node is 'floodable', it *could* be transformed
603 // into a liquid, otherwise, continue with the next node.
606 floodable_node = n0.getContent();
607 liquid_kind = CONTENT_AIR;
612 Collect information about the environment
614 NodeNeighbor sources[6]; // surrounding sources
616 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
618 NodeNeighbor airs[6]; // surrounding air
620 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
621 int num_neutrals = 0;
622 bool flowing_down = false;
623 bool ignored_sources = false;
624 for (u16 i = 0; i < 6; i++) {
625 NeighborType nt = NEIGHBOR_SAME_LEVEL;
636 v3s16 npos = p0 + liquid_6dirs[i];
637 NodeNeighbor nb(getNode(npos), nt, npos);
638 const ContentFeatures &cfnb = m_nodedef->get(nb.n);
639 switch (m_nodedef->get(nb.n.getContent()).liquid_type) {
641 if (cfnb.floodable) {
642 airs[num_airs++] = nb;
643 // if the current node is a water source the neighbor
644 // should be enqueded for transformation regardless of whether the
645 // current node changes or not.
646 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
647 m_transforming_liquid.push_back(npos);
648 // if the current node happens to be a flowing node, it will start to flow down here.
649 if (nb.t == NEIGHBOR_LOWER)
652 neutrals[num_neutrals++] = nb;
653 if (nb.n.getContent() == CONTENT_IGNORE) {
654 // If node below is ignore prevent water from
655 // spreading outwards and otherwise prevent from
656 // flowing away as ignore node might be the source
657 if (nb.t == NEIGHBOR_LOWER)
660 ignored_sources = true;
665 // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
666 if (liquid_kind == CONTENT_AIR)
667 liquid_kind = cfnb.liquid_alternative_flowing_id;
668 if (cfnb.liquid_alternative_flowing_id != liquid_kind) {
669 neutrals[num_neutrals++] = nb;
671 // Do not count bottom source, it will screw things up
672 if(nt != NEIGHBOR_LOWER)
673 sources[num_sources++] = nb;
677 if (nb.t != NEIGHBOR_SAME_LEVEL ||
678 (nb.n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK) {
679 // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
680 // but exclude falling liquids on the same level, they cannot flow here anyway
681 if (liquid_kind == CONTENT_AIR)
682 liquid_kind = cfnb.liquid_alternative_flowing_id;
684 if (cfnb.liquid_alternative_flowing_id != liquid_kind) {
685 neutrals[num_neutrals++] = nb;
687 flows[num_flows++] = nb;
688 if (nb.t == NEIGHBOR_LOWER)
696 decide on the type (and possibly level) of the current node
698 content_t new_node_content;
699 s8 new_node_level = -1;
700 s8 max_node_level = -1;
702 u8 range = m_nodedef->get(liquid_kind).liquid_range;
703 if (range > LIQUID_LEVEL_MAX + 1)
704 range = LIQUID_LEVEL_MAX + 1;
706 if ((num_sources >= 2 && m_nodedef->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
707 // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
708 // or the flowing alternative of the first of the surrounding sources (if it's air), so
709 // it's perfectly safe to use liquid_kind here to determine the new node content.
710 new_node_content = m_nodedef->get(liquid_kind).liquid_alternative_source_id;
711 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
712 // liquid_kind is set properly, see above
713 max_node_level = new_node_level = LIQUID_LEVEL_MAX;
714 if (new_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
715 new_node_content = liquid_kind;
717 new_node_content = floodable_node;
718 } else if (ignored_sources && liquid_level >= 0) {
719 // Maybe there are neighbouring sources that aren't loaded yet
720 // so prevent flowing away.
721 new_node_level = liquid_level;
722 new_node_content = liquid_kind;
724 // no surrounding sources, so get the maximum level that can flow into this node
725 for (u16 i = 0; i < num_flows; i++) {
726 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
727 switch (flows[i].t) {
729 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
730 max_node_level = LIQUID_LEVEL_MAX;
731 if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
732 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
733 } else if (nb_liquid_level > max_node_level) {
734 max_node_level = nb_liquid_level;
739 case NEIGHBOR_SAME_LEVEL:
740 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
741 nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level)
742 max_node_level = nb_liquid_level - 1;
747 u8 viscosity = m_nodedef->get(liquid_kind).liquid_viscosity;
748 if (viscosity > 1 && max_node_level != liquid_level) {
749 // amount to gain, limited by viscosity
750 // must be at least 1 in absolute value
751 s8 level_inc = max_node_level - liquid_level;
752 if (level_inc < -viscosity || level_inc > viscosity)
753 new_node_level = liquid_level + level_inc/viscosity;
754 else if (level_inc < 0)
755 new_node_level = liquid_level - 1;
756 else if (level_inc > 0)
757 new_node_level = liquid_level + 1;
758 if (new_node_level != max_node_level)
759 must_reflow.push_back(p0);
761 new_node_level = max_node_level;
764 if (max_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
765 new_node_content = liquid_kind;
767 new_node_content = floodable_node;
772 check if anything has changed. if not, just continue with the next node.
774 if (new_node_content == n0.getContent() &&
775 (m_nodedef->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
776 ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
777 ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
783 update the current node
786 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
787 if (m_nodedef->get(new_node_content).liquid_type == LIQUID_FLOWING) {
788 // set level to last 3 bits, flowing down bit to 4th bit
789 n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
791 // set the liquid level and flow bits to 0
792 n0.param2 &= ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
796 n0.setContent(new_node_content);
798 // on_flood() the node
799 if (floodable_node != CONTENT_AIR) {
800 if (env->getScriptIface()->node_on_flood(p0, n00, n0))
804 // Ignore light (because calling voxalgo::update_lighting_nodes)
805 n0.setLight(LIGHTBANK_DAY, 0, m_nodedef);
806 n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
808 // Find out whether there is a suspect for this action
810 if (m_gamedef->rollback())
811 suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
813 if (m_gamedef->rollback() && !suspect.empty()) {
815 RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
816 // Get old node for rollback
817 RollbackNode rollback_oldnode(this, p0, m_gamedef);
821 RollbackNode rollback_newnode(this, p0, m_gamedef);
822 RollbackAction action;
823 action.setSetNode(p0, rollback_oldnode, rollback_newnode);
824 m_gamedef->rollback()->reportAction(action);
830 v3s16 blockpos = getNodeBlockPos(p0);
831 MapBlock *block = getBlockNoCreateNoEx(blockpos);
833 modified_blocks[blockpos] = block;
834 changed_nodes.emplace_back(p0, n00);
838 enqueue neighbors for update if neccessary
840 switch (m_nodedef->get(n0.getContent()).liquid_type) {
843 // make sure source flows into all neighboring nodes
844 for (u16 i = 0; i < num_flows; i++)
845 if (flows[i].t != NEIGHBOR_UPPER)
846 m_transforming_liquid.push_back(flows[i].p);
847 for (u16 i = 0; i < num_airs; i++)
848 if (airs[i].t != NEIGHBOR_UPPER)
849 m_transforming_liquid.push_back(airs[i].p);
852 // this flow has turned to air; neighboring flows might need to do the same
853 for (u16 i = 0; i < num_flows; i++)
854 m_transforming_liquid.push_back(flows[i].p);
858 //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
860 for (auto &iter : must_reflow)
861 m_transforming_liquid.push_back(iter);
863 voxalgo::update_lighting_nodes(this, changed_nodes, modified_blocks);
866 /* ----------------------------------------------------------------------
867 * Manage the queue so that it does not grow indefinately
869 u16 time_until_purge = g_settings->getU16("liquid_queue_purge_time");
871 if (time_until_purge == 0)
872 return; // Feature disabled
874 time_until_purge *= 1000; // seconds -> milliseconds
876 u64 curr_time = porting::getTimeMs();
877 u32 prev_unprocessed = m_unprocessed_count;
878 m_unprocessed_count = m_transforming_liquid.size();
880 // if unprocessed block count is decreasing or stable
881 if (m_unprocessed_count <= prev_unprocessed) {
882 m_queue_size_timer_started = false;
884 if (!m_queue_size_timer_started)
885 m_inc_trending_up_start_time = curr_time;
886 m_queue_size_timer_started = true;
889 // Account for curr_time overflowing
890 if (m_queue_size_timer_started && m_inc_trending_up_start_time > curr_time)
891 m_queue_size_timer_started = false;
893 /* If the queue has been growing for more than liquid_queue_purge_time seconds
894 * and the number of unprocessed blocks is still > liquid_loop_max then we
895 * cannot keep up; dump the oldest blocks from the queue so that the queue
896 * has liquid_loop_max items in it
898 if (m_queue_size_timer_started
899 && curr_time - m_inc_trending_up_start_time > time_until_purge
900 && m_unprocessed_count > liquid_loop_max) {
902 size_t dump_qty = m_unprocessed_count - liquid_loop_max;
904 infostream << "transformLiquids(): DUMPING " << dump_qty
905 << " blocks from the queue" << std::endl;
908 m_transforming_liquid.pop_front();
910 m_queue_size_timer_started = false; // optimistically assume we can keep up now
911 m_unprocessed_count = m_transforming_liquid.size();
915 std::vector<v3s16> Map::findNodesWithMetadata(v3s16 p1, v3s16 p2)
917 std::vector<v3s16> positions_with_meta;
919 sortBoxVerticies(p1, p2);
920 v3s16 bpmin = getNodeBlockPos(p1);
921 v3s16 bpmax = getNodeBlockPos(p2);
923 VoxelArea area(p1, p2);
925 for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
926 for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
927 for (s16 x = bpmin.X; x <= bpmax.X; x++) {
928 v3s16 blockpos(x, y, z);
930 MapBlock *block = getBlockNoCreateNoEx(blockpos);
932 verbosestream << "Map::getNodeMetadata(): Need to emerge "
933 << PP(blockpos) << std::endl;
934 block = emergeBlock(blockpos, false);
937 infostream << "WARNING: Map::getNodeMetadata(): Block not found"
942 v3s16 p_base = blockpos * MAP_BLOCKSIZE;
943 std::vector<v3s16> keys = block->m_node_metadata.getAllKeys();
944 for (size_t i = 0; i != keys.size(); i++) {
945 v3s16 p(keys[i] + p_base);
946 if (!area.contains(p))
949 positions_with_meta.push_back(p);
953 return positions_with_meta;
956 NodeMetadata *Map::getNodeMetadata(v3s16 p)
958 v3s16 blockpos = getNodeBlockPos(p);
959 v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
960 MapBlock *block = getBlockNoCreateNoEx(blockpos);
962 infostream<<"Map::getNodeMetadata(): Need to emerge "
963 <<PP(blockpos)<<std::endl;
964 block = emergeBlock(blockpos, false);
967 warningstream<<"Map::getNodeMetadata(): Block not found"
971 NodeMetadata *meta = block->m_node_metadata.get(p_rel);
975 bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
977 v3s16 blockpos = getNodeBlockPos(p);
978 v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
979 MapBlock *block = getBlockNoCreateNoEx(blockpos);
981 infostream<<"Map::setNodeMetadata(): Need to emerge "
982 <<PP(blockpos)<<std::endl;
983 block = emergeBlock(blockpos, false);
986 warningstream<<"Map::setNodeMetadata(): Block not found"
990 block->m_node_metadata.set(p_rel, meta);
994 void Map::removeNodeMetadata(v3s16 p)
996 v3s16 blockpos = getNodeBlockPos(p);
997 v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
998 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1001 warningstream<<"Map::removeNodeMetadata(): Block not found"
1005 block->m_node_metadata.remove(p_rel);
1008 NodeTimer Map::getNodeTimer(v3s16 p)
1010 v3s16 blockpos = getNodeBlockPos(p);
1011 v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1012 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1014 infostream<<"Map::getNodeTimer(): Need to emerge "
1015 <<PP(blockpos)<<std::endl;
1016 block = emergeBlock(blockpos, false);
1019 warningstream<<"Map::getNodeTimer(): Block not found"
1023 NodeTimer t = block->m_node_timers.get(p_rel);
1024 NodeTimer nt(t.timeout, t.elapsed, p);
1028 void Map::setNodeTimer(const NodeTimer &t)
1030 v3s16 p = t.position;
1031 v3s16 blockpos = getNodeBlockPos(p);
1032 v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1033 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1035 infostream<<"Map::setNodeTimer(): Need to emerge "
1036 <<PP(blockpos)<<std::endl;
1037 block = emergeBlock(blockpos, false);
1040 warningstream<<"Map::setNodeTimer(): Block not found"
1044 NodeTimer nt(t.timeout, t.elapsed, p_rel);
1045 block->m_node_timers.set(nt);
1048 void Map::removeNodeTimer(v3s16 p)
1050 v3s16 blockpos = getNodeBlockPos(p);
1051 v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1052 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1055 warningstream<<"Map::removeNodeTimer(): Block not found"
1059 block->m_node_timers.remove(p_rel);
1062 bool Map::determineAdditionalOcclusionCheck(const v3s16 &pos_camera,
1063 const core::aabbox3d<s16> &block_bounds, v3s16 &check)
1066 This functions determines the node inside the target block that is
1067 closest to the camera position. This increases the occlusion culling
1068 accuracy in straight and diagonal corridors.
1069 The returned position will be occlusion checked first in addition to the
1070 others (8 corners + center).
1071 No position is returned if
1072 - the closest node is a corner, corners are checked anyway.
1073 - the camera is inside the target block, it will never be occluded.
1075 #define CLOSEST_EDGE(pos, bounds, axis) \
1076 ((pos).axis <= (bounds).MinEdge.axis) ? (bounds).MinEdge.axis : \
1077 (bounds).MaxEdge.axis
1079 bool x_inside = (block_bounds.MinEdge.X <= pos_camera.X) &&
1080 (pos_camera.X <= block_bounds.MaxEdge.X);
1081 bool y_inside = (block_bounds.MinEdge.Y <= pos_camera.Y) &&
1082 (pos_camera.Y <= block_bounds.MaxEdge.Y);
1083 bool z_inside = (block_bounds.MinEdge.Z <= pos_camera.Z) &&
1084 (pos_camera.Z <= block_bounds.MaxEdge.Z);
1086 if (x_inside && y_inside && z_inside)
1087 return false; // Camera inside target mapblock
1090 if (x_inside && y_inside) {
1091 check = v3s16(pos_camera.X, pos_camera.Y, 0);
1092 check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
1094 } else if (y_inside && z_inside) {
1095 check = v3s16(0, pos_camera.Y, pos_camera.Z);
1096 check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
1098 } else if (x_inside && z_inside) {
1099 check = v3s16(pos_camera.X, 0, pos_camera.Z);
1100 check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
1106 check = v3s16(pos_camera.X, 0, 0);
1107 check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
1108 check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
1110 } else if (y_inside) {
1111 check = v3s16(0, pos_camera.Y, 0);
1112 check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
1113 check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
1115 } else if (z_inside) {
1116 check = v3s16(0, 0, pos_camera.Z);
1117 check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
1118 check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
1122 // Closest node would be a corner, none returned
1126 bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
1127 float step, float stepfac, float offset, float end_offset, u32 needed_count)
1129 v3f direction = intToFloat(pos_target - pos_camera, BS);
1130 float distance = direction.getLength();
1132 // Normalize direction vector
1133 if (distance > 0.0f)
1134 direction /= distance;
1136 v3f pos_origin_f = intToFloat(pos_camera, BS);
1138 bool is_valid_position;
1140 for (; offset < distance + end_offset; offset += step) {
1141 v3f pos_node_f = pos_origin_f + direction * offset;
1142 v3s16 pos_node = floatToInt(pos_node_f, BS);
1144 MapNode node = getNode(pos_node, &is_valid_position);
1146 if (is_valid_position &&
1147 !m_nodedef->get(node).light_propagates) {
1148 // Cannot see through light-blocking nodes --> occluded
1150 if (count >= needed_count)
1158 bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes)
1160 // Check occlusion for center and all 8 corners of the mapblock
1161 // Overshoot a little for less flickering
1162 static const s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
1163 static const v3s16 dir9[9] = {
1165 v3s16( 1, 1, 1) * bs2,
1166 v3s16( 1, 1, -1) * bs2,
1167 v3s16( 1, -1, 1) * bs2,
1168 v3s16( 1, -1, -1) * bs2,
1169 v3s16(-1, 1, 1) * bs2,
1170 v3s16(-1, 1, -1) * bs2,
1171 v3s16(-1, -1, 1) * bs2,
1172 v3s16(-1, -1, -1) * bs2,
1175 v3s16 pos_blockcenter = block->getPosRelative() + (MAP_BLOCKSIZE / 2);
1177 // Starting step size, value between 1m and sqrt(3)m
1178 float step = BS * 1.2f;
1179 // Multiply step by each iteraction by 'stepfac' to reduce checks in distance
1180 float stepfac = 1.05f;
1182 float start_offset = BS * 1.0f;
1184 // The occlusion search of 'isOccluded()' must stop short of the target
1185 // point by distance 'end_offset' to not enter the target mapblock.
1186 // For the 8 mapblock corners 'end_offset' must therefore be the maximum
1187 // diagonal of a mapblock, because we must consider all view angles.
1188 // sqrt(1^2 + 1^2 + 1^2) = 1.732
1189 float end_offset = -BS * MAP_BLOCKSIZE * 1.732f;
1191 // to reduce the likelihood of falsely occluded blocks
1192 // require at least two solid blocks
1193 // this is a HACK, we should think of a more precise algorithm
1194 u32 needed_count = 2;
1196 // Additional occlusion check, see comments in that function
1198 if (determineAdditionalOcclusionCheck(cam_pos_nodes, block->getBox(), check)) {
1199 // node is always on a side facing the camera, end_offset can be lower
1200 if (!isOccluded(cam_pos_nodes, check, step, stepfac, start_offset,
1201 -1.0f, needed_count))
1205 for (const v3s16 &dir : dir9) {
1206 if (!isOccluded(cam_pos_nodes, pos_blockcenter + dir, step, stepfac,
1207 start_offset, end_offset, needed_count))
1216 ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef,
1217 EmergeManager *emerge, MetricsBackend *mb):
1219 settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"),
1222 verbosestream<<FUNCTION_NAME<<std::endl;
1224 // Tell the EmergeManager about our MapSettingsManager
1225 emerge->map_settings_mgr = &settings_mgr;
1228 Try to load map; if not found, create a new one.
1231 // Determine which database backend to use
1232 std::string conf_path = savedir + DIR_DELIM + "world.mt";
1234 bool succeeded = conf.readConfigFile(conf_path.c_str());
1235 if (!succeeded || !conf.exists("backend")) {
1236 // fall back to sqlite3
1237 conf.set("backend", "sqlite3");
1239 std::string backend = conf.get("backend");
1240 dbase = createDatabase(backend, savedir, conf);
1241 if (conf.exists("readonly_backend")) {
1242 std::string readonly_dir = savedir + DIR_DELIM + "readonly";
1243 dbase_ro = createDatabase(conf.get("readonly_backend"), readonly_dir, conf);
1245 if (!conf.updateConfigFile(conf_path.c_str()))
1246 errorstream << "ServerMap::ServerMap(): Failed to update world.mt!" << std::endl;
1248 m_savedir = savedir;
1249 m_map_saving_enabled = false;
1251 m_save_time_counter = mb->addCounter("minetest_core_map_save_time", "Map save time (in nanoseconds)");
1253 m_map_compression_level = rangelim(g_settings->getS16("map_compression_level_disk"), -1, 9);
1256 // If directory exists, check contents and load if possible
1257 if (fs::PathExists(m_savedir)) {
1258 // If directory is empty, it is safe to save into it.
1259 if (fs::GetDirListing(m_savedir).empty()) {
1260 infostream<<"ServerMap: Empty save directory is valid."
1262 m_map_saving_enabled = true;
1267 if (settings_mgr.loadMapMeta()) {
1268 infostream << "ServerMap: Metadata loaded from "
1269 << savedir << std::endl;
1271 infostream << "ServerMap: Metadata could not be loaded "
1272 "from " << savedir << ", assuming valid save "
1273 "directory." << std::endl;
1276 m_map_saving_enabled = true;
1277 // Map loaded, not creating new one
1281 // If directory doesn't exist, it is safe to save to it
1283 m_map_saving_enabled = true;
1286 catch(std::exception &e)
1288 warningstream<<"ServerMap: Failed to load map from "<<savedir
1289 <<", exception: "<<e.what()<<std::endl;
1290 infostream<<"Please remove the map or fix it."<<std::endl;
1291 warningstream<<"Map saving will be disabled."<<std::endl;
1295 ServerMap::~ServerMap()
1297 verbosestream<<FUNCTION_NAME<<std::endl;
1301 if (m_map_saving_enabled) {
1302 // Save only changed parts
1303 save(MOD_STATE_WRITE_AT_UNLOAD);
1304 infostream << "ServerMap: Saved map to " << m_savedir << std::endl;
1306 infostream << "ServerMap: Map not saved" << std::endl;
1309 catch(std::exception &e)
1311 infostream<<"ServerMap: Failed to save map to "<<m_savedir
1312 <<", exception: "<<e.what()<<std::endl;
1316 Close database if it was opened
1325 core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1326 for(; i.atEnd() == false; i++)
1328 MapChunk *chunk = i.getNode()->getValue();
1334 MapgenParams *ServerMap::getMapgenParams()
1336 // getMapgenParams() should only ever be called after Server is initialized
1337 assert(settings_mgr.mapgen_params != NULL);
1338 return settings_mgr.mapgen_params;
1341 u64 ServerMap::getSeed()
1343 return getMapgenParams()->seed;
1346 bool ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1348 const s16 mapgen_limit_bp = rangelim(
1349 getMapgenParams()->mapgen_limit, 0, MAX_MAP_GENERATION_LIMIT) /
1351 return p.X < -mapgen_limit_bp ||
1352 p.X > mapgen_limit_bp ||
1353 p.Y < -mapgen_limit_bp ||
1354 p.Y > mapgen_limit_bp ||
1355 p.Z < -mapgen_limit_bp ||
1356 p.Z > mapgen_limit_bp;
1359 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
1361 s16 csize = getMapgenParams()->chunksize;
1362 v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
1363 v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
1365 if (!m_chunks_in_progress.insert(bpmin).second)
1368 bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1369 EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
1371 v3s16 extra_borders(1, 1, 1);
1372 v3s16 full_bpmin = bpmin - extra_borders;
1373 v3s16 full_bpmax = bpmax + extra_borders;
1375 // Do nothing if not inside mapgen limits (+-1 because of neighbors)
1376 if (blockpos_over_mapgen_limit(full_bpmin) ||
1377 blockpos_over_mapgen_limit(full_bpmax))
1380 data->seed = getSeed();
1381 data->blockpos_min = bpmin;
1382 data->blockpos_max = bpmax;
1383 data->nodedef = m_nodedef;
1386 Create the whole area of this and the neighboring blocks
1388 for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
1389 for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
1390 v2s16 sectorpos(x, z);
1391 // Sector metadata is loaded from disk if not already loaded.
1392 MapSector *sector = createSector(sectorpos);
1393 FATAL_ERROR_IF(sector == NULL, "createSector() failed");
1395 for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
1398 MapBlock *block = emergeBlock(p, false);
1399 if (block == NULL) {
1400 block = createBlock(p);
1402 // Block gets sunlight if this is true.
1403 // Refer to the map generator heuristics.
1404 bool ug = m_emerge->isBlockUnderground(p);
1405 block->setIsUnderground(ug);
1411 Now we have a big empty area.
1413 Make a ManualMapVoxelManipulator that contains this and the
1417 data->vmanip = new MMVManip(this);
1418 data->vmanip->initialEmerge(full_bpmin, full_bpmax);
1420 // Note: we may need this again at some point.
1422 // Ensure none of the blocks to be generated were marked as
1423 // containing CONTENT_IGNORE
1424 for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
1425 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
1426 for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
1427 core::map<v3s16, u8>::Node *n;
1428 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
1431 u8 flags = n->getValue();
1432 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
1439 // Data is ready now.
1443 void ServerMap::finishBlockMake(BlockMakeData *data,
1444 std::map<v3s16, MapBlock*> *changed_blocks)
1446 v3s16 bpmin = data->blockpos_min;
1447 v3s16 bpmax = data->blockpos_max;
1449 v3s16 extra_borders(1, 1, 1);
1451 bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1452 EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
1455 Blit generated stuff to map
1456 NOTE: blitBackAll adds nearly everything to changed_blocks
1458 data->vmanip->blitBackAll(changed_blocks);
1460 EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
1461 << changed_blocks->size());
1464 Copy transforming liquid information
1466 while (data->transforming_liquid.size()) {
1467 m_transforming_liquid.push_back(data->transforming_liquid.front());
1468 data->transforming_liquid.pop_front();
1471 for (auto &changed_block : *changed_blocks) {
1472 MapBlock *block = changed_block.second;
1476 Update day/night difference cache of the MapBlocks
1478 block->expireDayNightDiff();
1480 Set block as modified
1482 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1483 MOD_REASON_EXPIRE_DAYNIGHTDIFF);
1487 Set central blocks as generated
1489 for (s16 x = bpmin.X; x <= bpmax.X; x++)
1490 for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
1491 for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
1492 MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
1496 block->setGenerated(true);
1500 Save changed parts of map
1501 NOTE: Will be saved later.
1503 //save(MOD_STATE_WRITE_AT_UNLOAD);
1504 m_chunks_in_progress.erase(bpmin);
1507 MapSector *ServerMap::createSector(v2s16 p2d)
1510 Check if it exists already in memory
1512 MapSector *sector = getSectorNoGenerate(p2d);
1517 Do not create over max mapgen limit
1519 const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
1520 if (p2d.X < -max_limit_bp ||
1521 p2d.X > max_limit_bp ||
1522 p2d.Y < -max_limit_bp ||
1523 p2d.Y > max_limit_bp)
1524 throw InvalidPositionException("createSector(): pos. over max mapgen limit");
1527 Generate blank sector
1530 sector = new MapSector(this, p2d, m_gamedef);
1532 // Sector position on map in nodes
1533 //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
1538 m_sectors[p2d] = sector;
1545 This is a quick-hand function for calling makeBlock().
1547 MapBlock * ServerMap::generateBlock(
1549 std::map<v3s16, MapBlock*> &modified_blocks
1552 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
1554 TimeTaker timer("generateBlock");
1556 //MapBlock *block = original_dummy;
1558 v2s16 p2d(p.X, p.Z);
1559 v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
1562 Do not generate over-limit
1564 if(blockpos_over_limit(p))
1566 infostream<<FUNCTION_NAME<<": Block position over limit"<<std::endl;
1567 throw InvalidPositionException("generateBlock(): pos. over limit");
1571 Create block make data
1574 initBlockMake(&data, p);
1580 TimeTaker t("mapgen::make_block()");
1581 mapgen->makeChunk(&data);
1582 //mapgen::make_block(&data);
1584 if(enable_mapgen_debug_info == false)
1585 t.stop(true); // Hide output
1589 Blit data back on map, update lighting, add mobs and whatever this does
1591 finishBlockMake(&data, modified_blocks);
1596 MapBlock *block = getBlockNoCreateNoEx(p);
1604 bool erroneus_content = false;
1605 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1606 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1607 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1610 MapNode n = block->getNode(p);
1611 if(n.getContent() == CONTENT_IGNORE)
1613 infostream<<"CONTENT_IGNORE at "
1614 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1616 erroneus_content = true;
1620 if(erroneus_content)
1629 Generate a completely empty block
1633 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1634 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1636 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1639 n.setContent(CONTENT_AIR);
1640 block->setNode(v3s16(x0,y0,z0), n);
1646 if(enable_mapgen_debug_info == false)
1647 timer.stop(true); // Hide output
1653 MapBlock * ServerMap::createBlock(v3s16 p)
1656 Do not create over max mapgen limit
1658 if (blockpos_over_max_limit(p))
1659 throw InvalidPositionException("createBlock(): pos. over max mapgen limit");
1661 v2s16 p2d(p.X, p.Z);
1664 This will create or load a sector if not found in memory.
1665 If block exists on disk, it will be loaded.
1667 NOTE: On old save formats, this will be slow, as it generates
1668 lighting on blocks for them.
1672 sector = createSector(p2d);
1673 } catch (InvalidPositionException &e) {
1674 infostream<<"createBlock: createSector() failed"<<std::endl;
1679 Try to get a block from the sector
1682 MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
1684 if(block->isDummy())
1689 block = sector->createBlankBlock(block_y);
1694 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
1697 MapBlock *block = getBlockNoCreateNoEx(p);
1698 if (block && !block->isDummy())
1703 MapBlock *block = loadBlock(p);
1709 MapSector *sector = createSector(v2s16(p.X, p.Z));
1710 MapBlock *block = sector->createBlankBlock(p.Y);
1718 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
1720 MapBlock *block = getBlockNoCreateNoEx(p3d);
1722 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
1727 // N.B. This requires no synchronization, since data will not be modified unless
1728 // the VoxelManipulator being updated belongs to the same thread.
1729 void ServerMap::updateVManip(v3s16 pos)
1731 Mapgen *mg = m_emerge->getCurrentMapgen();
1735 MMVManip *vm = mg->vm;
1739 if (!vm->m_area.contains(pos))
1742 s32 idx = vm->m_area.index(pos);
1743 vm->m_data[idx] = getNode(pos);
1744 vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
1746 vm->m_is_dirty = true;
1749 void ServerMap::save(ModifiedState save_level)
1751 if (!m_map_saving_enabled) {
1752 warningstream<<"Not saving map, saving disabled."<<std::endl;
1756 u64 start_time = porting::getTimeNs();
1758 if(save_level == MOD_STATE_CLEAN)
1759 infostream<<"ServerMap: Saving whole map, this can take time."
1762 if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
1763 if (settings_mgr.saveMapMeta())
1764 m_map_metadata_changed = false;
1767 // Profile modified reasons
1768 Profiler modprofiler;
1770 u32 block_count = 0;
1771 u32 block_count_all = 0; // Number of blocks in memory
1773 // Don't do anything with sqlite unless something is really saved
1774 bool save_started = false;
1776 for (auto §or_it : m_sectors) {
1777 MapSector *sector = sector_it.second;
1779 MapBlockVect blocks;
1780 sector->getBlocks(blocks);
1782 for (MapBlock *block : blocks) {
1785 if(block->getModified() >= (u32)save_level) {
1789 save_started = true;
1792 modprofiler.add(block->getModifiedReasonString(), 1);
1804 Only print if something happened or saved whole map
1806 if(save_level == MOD_STATE_CLEAN
1807 || block_count != 0) {
1808 infostream << "ServerMap: Written: "
1809 << block_count << " blocks"
1810 << ", " << block_count_all << " blocks in memory."
1812 PrintInfo(infostream); // ServerMap/ClientMap:
1813 infostream<<"Blocks modified by: "<<std::endl;
1814 modprofiler.print(infostream);
1817 auto end_time = porting::getTimeNs();
1818 m_save_time_counter->increment(end_time - start_time);
1821 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
1823 dbase->listAllLoadableBlocks(dst);
1825 dbase_ro->listAllLoadableBlocks(dst);
1828 MapDatabase *ServerMap::createDatabase(
1829 const std::string &name,
1830 const std::string &savedir,
1833 if (name == "sqlite3")
1834 return new MapDatabaseSQLite3(savedir);
1835 if (name == "dummy")
1836 return new Database_Dummy();
1838 if (name == "leveldb")
1839 return new Database_LevelDB(savedir);
1842 if (name == "redis")
1843 return new Database_Redis(conf);
1846 if (name == "postgresql") {
1847 std::string connect_string;
1848 conf.getNoEx("pgsql_connection", connect_string);
1849 return new MapDatabasePostgreSQL(connect_string);
1853 throw BaseException(std::string("Database backend ") + name + " not supported.");
1856 void ServerMap::beginSave()
1861 void ServerMap::endSave()
1866 bool ServerMap::saveBlock(MapBlock *block)
1868 return saveBlock(block, dbase, m_map_compression_level);
1871 bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db, int compression_level)
1873 v3s16 p3d = block->getPos();
1875 // Dummy blocks are not written
1876 if (block->isDummy()) {
1877 warningstream << "saveBlock: Not writing dummy block "
1878 << PP(p3d) << std::endl;
1882 // Format used for writing
1883 u8 version = SER_FMT_VER_HIGHEST_WRITE;
1886 [0] u8 serialization version
1889 std::ostringstream o(std::ios_base::binary);
1890 o.write((char*) &version, 1);
1891 block->serialize(o, version, true, compression_level);
1893 bool ret = db->saveBlock(p3d, o.str());
1895 // We just wrote it to the disk so clear modified flag
1896 block->resetModified();
1901 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
1904 std::istringstream is(*blob, std::ios_base::binary);
1906 u8 version = SER_FMT_VER_INVALID;
1907 is.read((char*)&version, 1);
1910 throw SerializationError("ServerMap::loadBlock(): Failed"
1911 " to read MapBlock version");
1913 MapBlock *block = NULL;
1914 bool created_new = false;
1915 block = sector->getBlockNoCreateNoEx(p3d.Y);
1918 block = sector->createBlankBlockNoInsert(p3d.Y);
1923 block->deSerialize(is, version, true);
1925 // If it's a new block, insert it to the map
1927 sector->insertBlock(block);
1928 ReflowScan scanner(this, m_emerge->ndef);
1929 scanner.scan(block, &m_transforming_liquid);
1933 Save blocks loaded in old format in new format
1936 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
1937 // Only save if asked to; no need to update version
1941 // We just loaded it from, so it's up-to-date.
1942 block->resetModified();
1944 catch(SerializationError &e)
1946 errorstream<<"Invalid block data in database"
1947 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
1948 <<" (SerializationError): "<<e.what()<<std::endl;
1950 // TODO: Block should be marked as invalid in memory so that it is
1951 // not touched but the game can run
1953 if(g_settings->getBool("ignore_world_load_errors")){
1954 errorstream<<"Ignoring block load error. Duck and cover! "
1955 <<"(ignore_world_load_errors)"<<std::endl;
1957 throw SerializationError("Invalid block data in database");
1962 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
1964 bool created_new = (getBlockNoCreateNoEx(blockpos) == NULL);
1966 v2s16 p2d(blockpos.X, blockpos.Z);
1969 dbase->loadBlock(blockpos, &ret);
1971 loadBlock(&ret, blockpos, createSector(p2d), false);
1972 } else if (dbase_ro) {
1973 dbase_ro->loadBlock(blockpos, &ret);
1975 loadBlock(&ret, blockpos, createSector(p2d), false);
1981 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1982 if (created_new && (block != NULL)) {
1983 std::map<v3s16, MapBlock*> modified_blocks;
1984 // Fix lighting if necessary
1985 voxalgo::update_block_border_lighting(this, block, modified_blocks);
1986 if (!modified_blocks.empty()) {
1987 //Modified lighting, send event
1989 event.type = MEET_OTHER;
1990 std::map<v3s16, MapBlock *>::iterator it;
1991 for (it = modified_blocks.begin();
1992 it != modified_blocks.end(); ++it)
1993 event.modified_blocks.insert(it->first);
1994 dispatchEvent(event);
2000 bool ServerMap::deleteBlock(v3s16 blockpos)
2002 if (!dbase->deleteBlock(blockpos))
2005 MapBlock *block = getBlockNoCreateNoEx(blockpos);
2007 v2s16 p2d(blockpos.X, blockpos.Z);
2008 MapSector *sector = getSectorNoGenerate(p2d);
2011 sector->deleteBlock(block);
2017 void ServerMap::PrintInfo(std::ostream &out)
2022 bool ServerMap::repairBlockLight(v3s16 blockpos,
2023 std::map<v3s16, MapBlock *> *modified_blocks)
2025 MapBlock *block = emergeBlock(blockpos, false);
2026 if (!block || !block->isGenerated())
2028 voxalgo::repair_block_light(this, block, modified_blocks);
2032 MMVManip::MMVManip(Map *map):
2038 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
2039 bool load_if_inexistent)
2041 TimeTaker timer1("initialEmerge", &emerge_time);
2043 // Units of these are MapBlocks
2044 v3s16 p_min = blockpos_min;
2045 v3s16 p_max = blockpos_max;
2047 VoxelArea block_area_nodes
2048 (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
2050 u32 size_MB = block_area_nodes.getVolume()*4/1000000;
2053 infostream<<"initialEmerge: area: ";
2054 block_area_nodes.print(infostream);
2055 infostream<<" ("<<size_MB<<"MB)";
2056 infostream<<std::endl;
2059 addArea(block_area_nodes);
2061 for(s32 z=p_min.Z; z<=p_max.Z; z++)
2062 for(s32 y=p_min.Y; y<=p_max.Y; y++)
2063 for(s32 x=p_min.X; x<=p_max.X; x++)
2068 std::map<v3s16, u8>::iterator n;
2069 n = m_loaded_blocks.find(p);
2070 if(n != m_loaded_blocks.end())
2073 bool block_data_inexistent = false;
2075 TimeTaker timer2("emerge load", &emerge_load_time);
2077 block = m_map->getBlockNoCreateNoEx(p);
2078 if (!block || block->isDummy())
2079 block_data_inexistent = true;
2081 block->copyTo(*this);
2084 if(block_data_inexistent)
2087 if (load_if_inexistent && !blockpos_over_max_limit(p)) {
2088 ServerMap *svrmap = (ServerMap *)m_map;
2089 block = svrmap->emergeBlock(p, false);
2091 block = svrmap->createBlock(p);
2092 block->copyTo(*this);
2094 flags |= VMANIP_BLOCK_DATA_INEXIST;
2097 Mark area inexistent
2099 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
2100 // Fill with VOXELFLAG_NO_DATA
2101 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
2102 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
2104 s32 i = m_area.index(a.MinEdge.X,y,z);
2105 memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
2109 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
2111 // Mark that block was loaded as blank
2112 flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
2115 m_loaded_blocks[p] = flags;
2121 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
2122 bool overwrite_generated)
2124 if(m_area.getExtent() == v3s16(0,0,0))
2128 Copy data of all blocks
2130 for (auto &loaded_block : m_loaded_blocks) {
2131 v3s16 p = loaded_block.first;
2132 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
2133 bool existed = !(loaded_block.second & VMANIP_BLOCK_DATA_INEXIST);
2134 if (!existed || (block == NULL) ||
2135 (!overwrite_generated && block->isGenerated()))
2138 block->copyFrom(*this);
2139 block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_VMANIP);
2142 (*modified_blocks)[p] = block;