]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
ce69accb5180445ea284882a0680e8e0b6a3fd77
[dragonfireclient.git] / src / map.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 #include "map.h"
21 #include "mapsector.h"
22 #include "mapblock.h"
23 #include "filesys.h"
24 #include "voxel.h"
25 #include "voxelalgorithms.h"
26 #include "porting.h"
27 #include "serialization.h"
28 #include "nodemetadata.h"
29 #include "settings.h"
30 #include "log.h"
31 #include "profiler.h"
32 #include "nodedef.h"
33 #include "gamedef.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"
39 #include "emerge.h"
40 #include "mapgen/mapgen_v6.h"
41 #include "mapgen/mg_biome.h"
42 #include "config.h"
43 #include "server.h"
44 #include "database/database.h"
45 #include "database/database-dummy.h"
46 #include "database/database-sqlite3.h"
47 #include "script/scripting_server.h"
48 #include <deque>
49 #include <queue>
50 #if USE_LEVELDB
51 #include "database/database-leveldb.h"
52 #endif
53 #if USE_REDIS
54 #include "database/database-redis.h"
55 #endif
56 #if USE_POSTGRESQL
57 #include "database/database-postgresql.h"
58 #endif
59
60
61 /*
62         Map
63 */
64
65 Map::Map(IGameDef *gamedef):
66         m_gamedef(gamedef),
67         m_nodedef(gamedef->ndef())
68 {
69 }
70
71 Map::~Map()
72 {
73         /*
74                 Free all MapSectors
75         */
76         for (auto &sector : m_sectors) {
77                 delete sector.second;
78         }
79 }
80
81 void Map::addEventReceiver(MapEventReceiver *event_receiver)
82 {
83         m_event_receivers.insert(event_receiver);
84 }
85
86 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
87 {
88         m_event_receivers.erase(event_receiver);
89 }
90
91 void Map::dispatchEvent(const MapEditEvent &event)
92 {
93         for (MapEventReceiver *event_receiver : m_event_receivers) {
94                 event_receiver->onMapEditEvent(event);
95         }
96 }
97
98 MapSector * Map::getSectorNoGenerateNoLock(v2s16 p)
99 {
100         if(m_sector_cache != NULL && p == m_sector_cache_p){
101                 MapSector * sector = m_sector_cache;
102                 return sector;
103         }
104
105         std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
106
107         if (n == m_sectors.end())
108                 return NULL;
109
110         MapSector *sector = n->second;
111
112         // Cache the last result
113         m_sector_cache_p = p;
114         m_sector_cache = sector;
115
116         return sector;
117 }
118
119 MapSector * Map::getSectorNoGenerate(v2s16 p)
120 {
121         return getSectorNoGenerateNoLock(p);
122 }
123
124 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
125 {
126         v2s16 p2d(p3d.X, p3d.Z);
127         MapSector * sector = getSectorNoGenerate(p2d);
128         if(sector == NULL)
129                 return NULL;
130         MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
131         return block;
132 }
133
134 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
135 {
136         MapBlock *block = getBlockNoCreateNoEx(p3d);
137         if(block == NULL)
138                 throw InvalidPositionException();
139         return block;
140 }
141
142 bool Map::isValidPosition(v3s16 p)
143 {
144         v3s16 blockpos = getNodeBlockPos(p);
145         MapBlock *block = getBlockNoCreateNoEx(blockpos);
146         return (block != NULL);
147 }
148
149 // Returns a CONTENT_IGNORE node if not found
150 MapNode Map::getNode(v3s16 p, bool *is_valid_position)
151 {
152         v3s16 blockpos = getNodeBlockPos(p);
153         MapBlock *block = getBlockNoCreateNoEx(blockpos);
154         if (block == NULL) {
155                 if (is_valid_position != NULL)
156                         *is_valid_position = false;
157                 return {CONTENT_IGNORE};
158         }
159
160         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
161         bool is_valid_p;
162         MapNode node = block->getNodeNoCheck(relpos, &is_valid_p);
163         if (is_valid_position != NULL)
164                 *is_valid_position = is_valid_p;
165         return node;
166 }
167
168 static void set_node_in_block(MapBlock *block, v3s16 relpos, MapNode n)
169 {
170         // Never allow placing CONTENT_IGNORE, it causes problems
171         if(n.getContent() == CONTENT_IGNORE){
172                 const NodeDefManager *nodedef = block->getParent()->getNodeDefManager();
173                 v3s16 blockpos = block->getPos();
174                 v3s16 p = blockpos * MAP_BLOCKSIZE + relpos;
175                 bool temp_bool;
176                 errorstream<<"Not allowing to place CONTENT_IGNORE"
177                                 <<" while trying to replace \""
178                                 <<nodedef->get(block->getNodeNoCheck(relpos, &temp_bool)).name
179                                 <<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
180                 return;
181         }
182         block->setNodeNoCheck(relpos, n);
183 }
184
185 // throws InvalidPositionException if not found
186 void Map::setNode(v3s16 p, MapNode & n)
187 {
188         v3s16 blockpos = getNodeBlockPos(p);
189         MapBlock *block = getBlockNoCreate(blockpos);
190         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
191         set_node_in_block(block, relpos, n);
192 }
193
194 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
195                 std::map<v3s16, MapBlock*> &modified_blocks,
196                 bool remove_metadata)
197 {
198         // Collect old node for rollback
199         RollbackNode rollback_oldnode(this, p, m_gamedef);
200
201         v3s16 blockpos = getNodeBlockPos(p);
202         MapBlock *block = getBlockNoCreate(blockpos);
203         if (block->isDummy())
204                 throw InvalidPositionException();
205         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
206
207         // This is needed for updating the lighting
208         MapNode oldnode = block->getNodeUnsafe(relpos);
209
210         // Remove node metadata
211         if (remove_metadata) {
212                 removeNodeMetadata(p);
213         }
214
215         // Set the node on the map
216         const ContentFeatures &cf = m_nodedef->get(n);
217         const ContentFeatures &oldcf = m_nodedef->get(oldnode);
218         if (cf.lightingEquivalent(oldcf)) {
219                 // No light update needed, just copy over the old light.
220                 n.setLight(LIGHTBANK_DAY, oldnode.getLightRaw(LIGHTBANK_DAY, oldcf), cf);
221                 n.setLight(LIGHTBANK_NIGHT, oldnode.getLightRaw(LIGHTBANK_NIGHT, oldcf), cf);
222                 set_node_in_block(block, relpos, n);
223
224                 modified_blocks[blockpos] = block;
225         } else {
226                 // Ignore light (because calling voxalgo::update_lighting_nodes)
227                 n.setLight(LIGHTBANK_DAY, 0, cf);
228                 n.setLight(LIGHTBANK_NIGHT, 0, cf);
229                 set_node_in_block(block, relpos, n);
230
231                 // Update lighting
232                 std::vector<std::pair<v3s16, MapNode> > oldnodes;
233                 oldnodes.emplace_back(p, oldnode);
234                 voxalgo::update_lighting_nodes(this, oldnodes, modified_blocks);
235
236                 for (auto &modified_block : modified_blocks) {
237                         modified_block.second->expireDayNightDiff();
238                 }
239         }
240
241         // Report for rollback
242         if(m_gamedef->rollback())
243         {
244                 RollbackNode rollback_newnode(this, p, m_gamedef);
245                 RollbackAction action;
246                 action.setSetNode(p, rollback_oldnode, rollback_newnode);
247                 m_gamedef->rollback()->reportAction(action);
248         }
249 }
250
251 void Map::removeNodeAndUpdate(v3s16 p,
252                 std::map<v3s16, MapBlock*> &modified_blocks)
253 {
254         addNodeAndUpdate(p, MapNode(CONTENT_AIR), modified_blocks, true);
255 }
256
257 bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
258 {
259         MapEditEvent event;
260         event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
261         event.p = p;
262         event.n = n;
263
264         bool succeeded = true;
265         try{
266                 std::map<v3s16, MapBlock*> modified_blocks;
267                 addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
268
269                 // Copy modified_blocks to event
270                 for (auto &modified_block : modified_blocks) {
271                         event.modified_blocks.insert(modified_block.first);
272                 }
273         }
274         catch(InvalidPositionException &e){
275                 succeeded = false;
276         }
277
278         dispatchEvent(event);
279
280         return succeeded;
281 }
282
283 bool Map::removeNodeWithEvent(v3s16 p)
284 {
285         MapEditEvent event;
286         event.type = MEET_REMOVENODE;
287         event.p = p;
288
289         bool succeeded = true;
290         try{
291                 std::map<v3s16, MapBlock*> modified_blocks;
292                 removeNodeAndUpdate(p, modified_blocks);
293
294                 // Copy modified_blocks to event
295                 for (auto &modified_block : modified_blocks) {
296                         event.modified_blocks.insert(modified_block.first);
297                 }
298         }
299         catch(InvalidPositionException &e){
300                 succeeded = false;
301         }
302
303         dispatchEvent(event);
304
305         return succeeded;
306 }
307
308 struct TimeOrderedMapBlock {
309         MapSector *sect;
310         MapBlock *block;
311
312         TimeOrderedMapBlock(MapSector *sect, MapBlock *block) :
313                 sect(sect),
314                 block(block)
315         {}
316
317         bool operator<(const TimeOrderedMapBlock &b) const
318         {
319                 return block->getUsageTimer() < b.block->getUsageTimer();
320         };
321 };
322
323 /*
324         Updates usage timers
325 */
326 void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
327                 std::vector<v3s16> *unloaded_blocks)
328 {
329         bool save_before_unloading = maySaveBlocks();
330
331         // Profile modified reasons
332         Profiler modprofiler;
333
334         std::vector<v2s16> sector_deletion_queue;
335         u32 deleted_blocks_count = 0;
336         u32 saved_blocks_count = 0;
337         u32 block_count_all = 0;
338
339         const auto start_time = porting::getTimeUs();
340         beginSave();
341
342         // If there is no practical limit, we spare creation of mapblock_queue
343         if (max_loaded_blocks == U32_MAX) {
344                 for (auto &sector_it : m_sectors) {
345                         MapSector *sector = sector_it.second;
346
347                         bool all_blocks_deleted = true;
348
349                         MapBlockVect blocks;
350                         sector->getBlocks(blocks);
351
352                         for (MapBlock *block : blocks) {
353                                 block->incrementUsageTimer(dtime);
354
355                                 if (block->refGet() == 0
356                                                 && block->getUsageTimer() > unload_timeout) {
357                                         v3s16 p = block->getPos();
358
359                                         // Save if modified
360                                         if (block->getModified() != MOD_STATE_CLEAN
361                                                         && save_before_unloading) {
362                                                 modprofiler.add(block->getModifiedReasonString(), 1);
363                                                 if (!saveBlock(block))
364                                                         continue;
365                                                 saved_blocks_count++;
366                                         }
367
368                                         // Delete from memory
369                                         sector->deleteBlock(block);
370
371                                         if (unloaded_blocks)
372                                                 unloaded_blocks->push_back(p);
373
374                                         deleted_blocks_count++;
375                                 } else {
376                                         all_blocks_deleted = false;
377                                         block_count_all++;
378                                 }
379                         }
380
381                         // Delete sector if we emptied it
382                         if (all_blocks_deleted) {
383                                 sector_deletion_queue.push_back(sector_it.first);
384                         }
385                 }
386         } else {
387                 std::priority_queue<TimeOrderedMapBlock> mapblock_queue;
388                 for (auto &sector_it : m_sectors) {
389                         MapSector *sector = sector_it.second;
390
391                         MapBlockVect blocks;
392                         sector->getBlocks(blocks);
393
394                         for (MapBlock *block : blocks) {
395                                 block->incrementUsageTimer(dtime);
396                                 mapblock_queue.push(TimeOrderedMapBlock(sector, block));
397                         }
398                 }
399                 block_count_all = mapblock_queue.size();
400
401                 // Delete old blocks, and blocks over the limit from the memory
402                 while (!mapblock_queue.empty() && (mapblock_queue.size() > max_loaded_blocks
403                                 || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) {
404                         TimeOrderedMapBlock b = mapblock_queue.top();
405                         mapblock_queue.pop();
406
407                         MapBlock *block = b.block;
408
409                         if (block->refGet() != 0)
410                                 continue;
411
412                         v3s16 p = block->getPos();
413
414                         // Save if modified
415                         if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
416                                 modprofiler.add(block->getModifiedReasonString(), 1);
417                                 if (!saveBlock(block))
418                                         continue;
419                                 saved_blocks_count++;
420                         }
421
422                         // Delete from memory
423                         b.sect->deleteBlock(block);
424
425                         if (unloaded_blocks)
426                                 unloaded_blocks->push_back(p);
427
428                         deleted_blocks_count++;
429                         block_count_all--;
430                 }
431
432                 // Delete empty sectors
433                 for (auto &sector_it : m_sectors) {
434                         if (sector_it.second->empty()) {
435                                 sector_deletion_queue.push_back(sector_it.first);
436                         }
437                 }
438         }
439
440         endSave();
441         const auto end_time = porting::getTimeUs();
442
443         reportMetrics(end_time - start_time, saved_blocks_count, block_count_all);
444
445         // Finally delete the empty sectors
446         deleteSectors(sector_deletion_queue);
447
448         if(deleted_blocks_count != 0)
449         {
450                 PrintInfo(infostream); // ServerMap/ClientMap:
451                 infostream<<"Unloaded "<<deleted_blocks_count
452                                 <<" blocks from memory";
453                 if(save_before_unloading)
454                         infostream<<", of which "<<saved_blocks_count<<" were written";
455                 infostream<<", "<<block_count_all<<" blocks in memory";
456                 infostream<<"."<<std::endl;
457                 if(saved_blocks_count != 0){
458                         PrintInfo(infostream); // ServerMap/ClientMap:
459                         infostream<<"Blocks modified by: "<<std::endl;
460                         modprofiler.print(infostream);
461                 }
462         }
463 }
464
465 void Map::unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks)
466 {
467         timerUpdate(0.0, -1.0, 0, unloaded_blocks);
468 }
469
470 void Map::deleteSectors(std::vector<v2s16> &sectorList)
471 {
472         for (v2s16 j : sectorList) {
473                 MapSector *sector = m_sectors[j];
474                 // If sector is in sector cache, remove it from there
475                 if(m_sector_cache == sector)
476                         m_sector_cache = NULL;
477                 // Remove from map and delete
478                 m_sectors.erase(j);
479                 delete sector;
480         }
481 }
482
483 void Map::PrintInfo(std::ostream &out)
484 {
485         out<<"Map: ";
486 }
487
488 #define WATER_DROP_BOOST 4
489
490 const static v3s16 liquid_6dirs[6] = {
491         // order: upper before same level before lower
492         v3s16( 0, 1, 0),
493         v3s16( 0, 0, 1),
494         v3s16( 1, 0, 0),
495         v3s16( 0, 0,-1),
496         v3s16(-1, 0, 0),
497         v3s16( 0,-1, 0)
498 };
499
500 enum NeighborType : u8 {
501         NEIGHBOR_UPPER,
502         NEIGHBOR_SAME_LEVEL,
503         NEIGHBOR_LOWER
504 };
505
506 struct NodeNeighbor {
507         MapNode n;
508         NeighborType t;
509         v3s16 p;
510
511         NodeNeighbor()
512                 : n(CONTENT_AIR), t(NEIGHBOR_SAME_LEVEL)
513         { }
514
515         NodeNeighbor(const MapNode &node, NeighborType n_type, const v3s16 &pos)
516                 : n(node),
517                   t(n_type),
518                   p(pos)
519         { }
520 };
521
522 void ServerMap::transforming_liquid_add(v3s16 p) {
523         m_transforming_liquid.push_back(p);
524 }
525
526 void ServerMap::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks,
527                 ServerEnvironment *env)
528 {
529         u32 loopcount = 0;
530         u32 initial_size = m_transforming_liquid.size();
531
532         /*if(initial_size != 0)
533                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
534
535         // list of nodes that due to viscosity have not reached their max level height
536         std::deque<v3s16> must_reflow;
537
538         std::vector<std::pair<v3s16, MapNode> > changed_nodes;
539
540         u32 liquid_loop_max = g_settings->getS32("liquid_loop_max");
541         u32 loop_max = liquid_loop_max;
542
543         while (m_transforming_liquid.size() != 0)
544         {
545                 // This should be done here so that it is done when continue is used
546                 if (loopcount >= initial_size || loopcount >= loop_max)
547                         break;
548                 loopcount++;
549
550                 /*
551                         Get a queued transforming liquid node
552                 */
553                 v3s16 p0 = m_transforming_liquid.front();
554                 m_transforming_liquid.pop_front();
555
556                 MapNode n0 = getNode(p0);
557
558                 /*
559                         Collect information about current node
560                  */
561                 s8 liquid_level = -1;
562                 // The liquid node which will be placed there if
563                 // the liquid flows into this node.
564                 content_t liquid_kind = CONTENT_IGNORE;
565                 // The node which will be placed there if liquid
566                 // can't flow into this node.
567                 content_t floodable_node = CONTENT_AIR;
568                 const ContentFeatures &cf = m_nodedef->get(n0);
569                 LiquidType liquid_type = cf.liquid_type;
570                 switch (liquid_type) {
571                         case LIQUID_SOURCE:
572                                 liquid_level = LIQUID_LEVEL_SOURCE;
573                                 liquid_kind = cf.liquid_alternative_flowing_id;
574                                 break;
575                         case LIQUID_FLOWING:
576                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
577                                 liquid_kind = n0.getContent();
578                                 break;
579                         case LIQUID_NONE:
580                                 // if this node is 'floodable', it *could* be transformed
581                                 // into a liquid, otherwise, continue with the next node.
582                                 if (!cf.floodable)
583                                         continue;
584                                 floodable_node = n0.getContent();
585                                 liquid_kind = CONTENT_AIR;
586                                 break;
587                 }
588
589                 /*
590                         Collect information about the environment
591                  */
592                 NodeNeighbor sources[6]; // surrounding sources
593                 int num_sources = 0;
594                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
595                 int num_flows = 0;
596                 NodeNeighbor airs[6]; // surrounding air
597                 int num_airs = 0;
598                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
599                 int num_neutrals = 0;
600                 bool flowing_down = false;
601                 bool ignored_sources = false;
602                 for (u16 i = 0; i < 6; i++) {
603                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
604                         switch (i) {
605                                 case 0:
606                                         nt = NEIGHBOR_UPPER;
607                                         break;
608                                 case 5:
609                                         nt = NEIGHBOR_LOWER;
610                                         break;
611                                 default:
612                                         break;
613                         }
614                         v3s16 npos = p0 + liquid_6dirs[i];
615                         NodeNeighbor nb(getNode(npos), nt, npos);
616                         const ContentFeatures &cfnb = m_nodedef->get(nb.n);
617                         switch (m_nodedef->get(nb.n.getContent()).liquid_type) {
618                                 case LIQUID_NONE:
619                                         if (cfnb.floodable) {
620                                                 airs[num_airs++] = nb;
621                                                 // if the current node is a water source the neighbor
622                                                 // should be enqueded for transformation regardless of whether the
623                                                 // current node changes or not.
624                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
625                                                         m_transforming_liquid.push_back(npos);
626                                                 // if the current node happens to be a flowing node, it will start to flow down here.
627                                                 if (nb.t == NEIGHBOR_LOWER)
628                                                         flowing_down = true;
629                                         } else {
630                                                 neutrals[num_neutrals++] = nb;
631                                                 if (nb.n.getContent() == CONTENT_IGNORE) {
632                                                         // If node below is ignore prevent water from
633                                                         // spreading outwards and otherwise prevent from
634                                                         // flowing away as ignore node might be the source
635                                                         if (nb.t == NEIGHBOR_LOWER)
636                                                                 flowing_down = true;
637                                                         else
638                                                                 ignored_sources = true;
639                                                 }
640                                         }
641                                         break;
642                                 case LIQUID_SOURCE:
643                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
644                                         if (liquid_kind == CONTENT_AIR)
645                                                 liquid_kind = cfnb.liquid_alternative_flowing_id;
646                                         if (cfnb.liquid_alternative_flowing_id != liquid_kind) {
647                                                 neutrals[num_neutrals++] = nb;
648                                         } else {
649                                                 // Do not count bottom source, it will screw things up
650                                                 if(nt != NEIGHBOR_LOWER)
651                                                         sources[num_sources++] = nb;
652                                         }
653                                         break;
654                                 case LIQUID_FLOWING:
655                                         if (nb.t != NEIGHBOR_SAME_LEVEL ||
656                                                 (nb.n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK) {
657                                                 // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
658                                                 // but exclude falling liquids on the same level, they cannot flow here anyway
659                                                 if (liquid_kind == CONTENT_AIR)
660                                                         liquid_kind = cfnb.liquid_alternative_flowing_id;
661                                         }
662                                         if (cfnb.liquid_alternative_flowing_id != liquid_kind) {
663                                                 neutrals[num_neutrals++] = nb;
664                                         } else {
665                                                 flows[num_flows++] = nb;
666                                                 if (nb.t == NEIGHBOR_LOWER)
667                                                         flowing_down = true;
668                                         }
669                                         break;
670                         }
671                 }
672
673                 /*
674                         decide on the type (and possibly level) of the current node
675                  */
676                 content_t new_node_content;
677                 s8 new_node_level = -1;
678                 s8 max_node_level = -1;
679
680                 u8 range = m_nodedef->get(liquid_kind).liquid_range;
681                 if (range > LIQUID_LEVEL_MAX + 1)
682                         range = LIQUID_LEVEL_MAX + 1;
683
684                 if ((num_sources >= 2 && m_nodedef->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
685                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
686                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
687                         // it's perfectly safe to use liquid_kind here to determine the new node content.
688                         new_node_content = m_nodedef->get(liquid_kind).liquid_alternative_source_id;
689                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
690                         // liquid_kind is set properly, see above
691                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
692                         if (new_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
693                                 new_node_content = liquid_kind;
694                         else
695                                 new_node_content = floodable_node;
696                 } else if (ignored_sources && liquid_level >= 0) {
697                         // Maybe there are neighbouring sources that aren't loaded yet
698                         // so prevent flowing away.
699                         new_node_level = liquid_level;
700                         new_node_content = liquid_kind;
701                 } else {
702                         // no surrounding sources, so get the maximum level that can flow into this node
703                         for (u16 i = 0; i < num_flows; i++) {
704                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
705                                 switch (flows[i].t) {
706                                         case NEIGHBOR_UPPER:
707                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
708                                                         max_node_level = LIQUID_LEVEL_MAX;
709                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
710                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
711                                                 } else if (nb_liquid_level > max_node_level) {
712                                                         max_node_level = nb_liquid_level;
713                                                 }
714                                                 break;
715                                         case NEIGHBOR_LOWER:
716                                                 break;
717                                         case NEIGHBOR_SAME_LEVEL:
718                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
719                                                                 nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level)
720                                                         max_node_level = nb_liquid_level - 1;
721                                                 break;
722                                 }
723                         }
724
725                         u8 viscosity = m_nodedef->get(liquid_kind).liquid_viscosity;
726                         if (viscosity > 1 && max_node_level != liquid_level) {
727                                 // amount to gain, limited by viscosity
728                                 // must be at least 1 in absolute value
729                                 s8 level_inc = max_node_level - liquid_level;
730                                 if (level_inc < -viscosity || level_inc > viscosity)
731                                         new_node_level = liquid_level + level_inc/viscosity;
732                                 else if (level_inc < 0)
733                                         new_node_level = liquid_level - 1;
734                                 else if (level_inc > 0)
735                                         new_node_level = liquid_level + 1;
736                                 if (new_node_level != max_node_level)
737                                         must_reflow.push_back(p0);
738                         } else {
739                                 new_node_level = max_node_level;
740                         }
741
742                         if (max_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
743                                 new_node_content = liquid_kind;
744                         else
745                                 new_node_content = floodable_node;
746
747                 }
748
749                 /*
750                         check if anything has changed. if not, just continue with the next node.
751                  */
752                 if (new_node_content == n0.getContent() &&
753                                 (m_nodedef->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
754                                 ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
755                                 ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
756                                 == flowing_down)))
757                         continue;
758
759
760                 /*
761                         update the current node
762                  */
763                 MapNode n00 = n0;
764                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
765                 if (m_nodedef->get(new_node_content).liquid_type == LIQUID_FLOWING) {
766                         // set level to last 3 bits, flowing down bit to 4th bit
767                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
768                 } else {
769                         // set the liquid level and flow bits to 0
770                         n0.param2 &= ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
771                 }
772
773                 // change the node.
774                 n0.setContent(new_node_content);
775
776                 // on_flood() the node
777                 if (floodable_node != CONTENT_AIR) {
778                         if (env->getScriptIface()->node_on_flood(p0, n00, n0))
779                                 continue;
780                 }
781
782                 // Ignore light (because calling voxalgo::update_lighting_nodes)
783                 n0.setLight(LIGHTBANK_DAY, 0, m_nodedef);
784                 n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
785
786                 // Find out whether there is a suspect for this action
787                 std::string suspect;
788                 if (m_gamedef->rollback())
789                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
790
791                 if (m_gamedef->rollback() && !suspect.empty()) {
792                         // Blame suspect
793                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
794                         // Get old node for rollback
795                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
796                         // Set node
797                         setNode(p0, n0);
798                         // Report
799                         RollbackNode rollback_newnode(this, p0, m_gamedef);
800                         RollbackAction action;
801                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
802                         m_gamedef->rollback()->reportAction(action);
803                 } else {
804                         // Set node
805                         setNode(p0, n0);
806                 }
807
808                 v3s16 blockpos = getNodeBlockPos(p0);
809                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
810                 if (block != NULL) {
811                         modified_blocks[blockpos] =  block;
812                         changed_nodes.emplace_back(p0, n00);
813                 }
814
815                 /*
816                         enqueue neighbors for update if neccessary
817                  */
818                 switch (m_nodedef->get(n0.getContent()).liquid_type) {
819                         case LIQUID_SOURCE:
820                         case LIQUID_FLOWING:
821                                 // make sure source flows into all neighboring nodes
822                                 for (u16 i = 0; i < num_flows; i++)
823                                         if (flows[i].t != NEIGHBOR_UPPER)
824                                                 m_transforming_liquid.push_back(flows[i].p);
825                                 for (u16 i = 0; i < num_airs; i++)
826                                         if (airs[i].t != NEIGHBOR_UPPER)
827                                                 m_transforming_liquid.push_back(airs[i].p);
828                                 break;
829                         case LIQUID_NONE:
830                                 // this flow has turned to air; neighboring flows might need to do the same
831                                 for (u16 i = 0; i < num_flows; i++)
832                                         m_transforming_liquid.push_back(flows[i].p);
833                                 break;
834                 }
835         }
836         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
837
838         for (auto &iter : must_reflow)
839                 m_transforming_liquid.push_back(iter);
840
841         voxalgo::update_lighting_nodes(this, changed_nodes, modified_blocks);
842         env->getScriptIface()->on_liquid_transformed(changed_nodes);
843
844         /* ----------------------------------------------------------------------
845          * Manage the queue so that it does not grow indefinately
846          */
847         u16 time_until_purge = g_settings->getU16("liquid_queue_purge_time");
848
849         if (time_until_purge == 0)
850                 return; // Feature disabled
851
852         time_until_purge *= 1000;       // seconds -> milliseconds
853
854         u64 curr_time = porting::getTimeMs();
855         u32 prev_unprocessed = m_unprocessed_count;
856         m_unprocessed_count = m_transforming_liquid.size();
857
858         // if unprocessed block count is decreasing or stable
859         if (m_unprocessed_count <= prev_unprocessed) {
860                 m_queue_size_timer_started = false;
861         } else {
862                 if (!m_queue_size_timer_started)
863                         m_inc_trending_up_start_time = curr_time;
864                 m_queue_size_timer_started = true;
865         }
866
867         // Account for curr_time overflowing
868         if (m_queue_size_timer_started && m_inc_trending_up_start_time > curr_time)
869                 m_queue_size_timer_started = false;
870
871         /* If the queue has been growing for more than liquid_queue_purge_time seconds
872          * and the number of unprocessed blocks is still > liquid_loop_max then we
873          * cannot keep up; dump the oldest blocks from the queue so that the queue
874          * has liquid_loop_max items in it
875          */
876         if (m_queue_size_timer_started
877                         && curr_time - m_inc_trending_up_start_time > time_until_purge
878                         && m_unprocessed_count > liquid_loop_max) {
879
880                 size_t dump_qty = m_unprocessed_count - liquid_loop_max;
881
882                 infostream << "transformLiquids(): DUMPING " << dump_qty
883                            << " blocks from the queue" << std::endl;
884
885                 while (dump_qty--)
886                         m_transforming_liquid.pop_front();
887
888                 m_queue_size_timer_started = false; // optimistically assume we can keep up now
889                 m_unprocessed_count = m_transforming_liquid.size();
890         }
891 }
892
893 std::vector<v3s16> Map::findNodesWithMetadata(v3s16 p1, v3s16 p2)
894 {
895         std::vector<v3s16> positions_with_meta;
896
897         sortBoxVerticies(p1, p2);
898         v3s16 bpmin = getNodeBlockPos(p1);
899         v3s16 bpmax = getNodeBlockPos(p2);
900
901         VoxelArea area(p1, p2);
902
903         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
904         for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
905         for (s16 x = bpmin.X; x <= bpmax.X; x++) {
906                 v3s16 blockpos(x, y, z);
907
908                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
909                 if (!block) {
910                         verbosestream << "Map::getNodeMetadata(): Need to emerge "
911                                 << PP(blockpos) << std::endl;
912                         block = emergeBlock(blockpos, false);
913                 }
914                 if (!block) {
915                         infostream << "WARNING: Map::getNodeMetadata(): Block not found"
916                                 << std::endl;
917                         continue;
918                 }
919
920                 v3s16 p_base = blockpos * MAP_BLOCKSIZE;
921                 std::vector<v3s16> keys = block->m_node_metadata.getAllKeys();
922                 for (size_t i = 0; i != keys.size(); i++) {
923                         v3s16 p(keys[i] + p_base);
924                         if (!area.contains(p))
925                                 continue;
926
927                         positions_with_meta.push_back(p);
928                 }
929         }
930
931         return positions_with_meta;
932 }
933
934 NodeMetadata *Map::getNodeMetadata(v3s16 p)
935 {
936         v3s16 blockpos = getNodeBlockPos(p);
937         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
938         MapBlock *block = getBlockNoCreateNoEx(blockpos);
939         if(!block){
940                 infostream<<"Map::getNodeMetadata(): Need to emerge "
941                                 <<PP(blockpos)<<std::endl;
942                 block = emergeBlock(blockpos, false);
943         }
944         if(!block){
945                 warningstream<<"Map::getNodeMetadata(): Block not found"
946                                 <<std::endl;
947                 return NULL;
948         }
949         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
950         return meta;
951 }
952
953 bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
954 {
955         v3s16 blockpos = getNodeBlockPos(p);
956         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
957         MapBlock *block = getBlockNoCreateNoEx(blockpos);
958         if(!block){
959                 infostream<<"Map::setNodeMetadata(): Need to emerge "
960                                 <<PP(blockpos)<<std::endl;
961                 block = emergeBlock(blockpos, false);
962         }
963         if(!block){
964                 warningstream<<"Map::setNodeMetadata(): Block not found"
965                                 <<std::endl;
966                 return false;
967         }
968         block->m_node_metadata.set(p_rel, meta);
969         return true;
970 }
971
972 void Map::removeNodeMetadata(v3s16 p)
973 {
974         v3s16 blockpos = getNodeBlockPos(p);
975         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
976         MapBlock *block = getBlockNoCreateNoEx(blockpos);
977         if(block == NULL)
978         {
979                 warningstream<<"Map::removeNodeMetadata(): Block not found"
980                                 <<std::endl;
981                 return;
982         }
983         block->m_node_metadata.remove(p_rel);
984 }
985
986 NodeTimer Map::getNodeTimer(v3s16 p)
987 {
988         v3s16 blockpos = getNodeBlockPos(p);
989         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
990         MapBlock *block = getBlockNoCreateNoEx(blockpos);
991         if(!block){
992                 infostream<<"Map::getNodeTimer(): Need to emerge "
993                                 <<PP(blockpos)<<std::endl;
994                 block = emergeBlock(blockpos, false);
995         }
996         if(!block){
997                 warningstream<<"Map::getNodeTimer(): Block not found"
998                                 <<std::endl;
999                 return NodeTimer();
1000         }
1001         NodeTimer t = block->m_node_timers.get(p_rel);
1002         NodeTimer nt(t.timeout, t.elapsed, p);
1003         return nt;
1004 }
1005
1006 void Map::setNodeTimer(const NodeTimer &t)
1007 {
1008         v3s16 p = t.position;
1009         v3s16 blockpos = getNodeBlockPos(p);
1010         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1011         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1012         if(!block){
1013                 infostream<<"Map::setNodeTimer(): Need to emerge "
1014                                 <<PP(blockpos)<<std::endl;
1015                 block = emergeBlock(blockpos, false);
1016         }
1017         if(!block){
1018                 warningstream<<"Map::setNodeTimer(): Block not found"
1019                                 <<std::endl;
1020                 return;
1021         }
1022         NodeTimer nt(t.timeout, t.elapsed, p_rel);
1023         block->m_node_timers.set(nt);
1024 }
1025
1026 void Map::removeNodeTimer(v3s16 p)
1027 {
1028         v3s16 blockpos = getNodeBlockPos(p);
1029         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1030         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1031         if(block == NULL)
1032         {
1033                 warningstream<<"Map::removeNodeTimer(): Block not found"
1034                                 <<std::endl;
1035                 return;
1036         }
1037         block->m_node_timers.remove(p_rel);
1038 }
1039
1040 bool Map::determineAdditionalOcclusionCheck(const v3s16 &pos_camera,
1041         const core::aabbox3d<s16> &block_bounds, v3s16 &check)
1042 {
1043         /*
1044                 This functions determines the node inside the target block that is
1045                 closest to the camera position. This increases the occlusion culling
1046                 accuracy in straight and diagonal corridors.
1047                 The returned position will be occlusion checked first in addition to the
1048                 others (8 corners + center).
1049                 No position is returned if
1050                 - the closest node is a corner, corners are checked anyway.
1051                 - the camera is inside the target block, it will never be occluded.
1052         */
1053 #define CLOSEST_EDGE(pos, bounds, axis) \
1054         ((pos).axis <= (bounds).MinEdge.axis) ? (bounds).MinEdge.axis : \
1055         (bounds).MaxEdge.axis
1056
1057         bool x_inside = (block_bounds.MinEdge.X <= pos_camera.X) &&
1058                         (pos_camera.X <= block_bounds.MaxEdge.X);
1059         bool y_inside = (block_bounds.MinEdge.Y <= pos_camera.Y) &&
1060                         (pos_camera.Y <= block_bounds.MaxEdge.Y);
1061         bool z_inside = (block_bounds.MinEdge.Z <= pos_camera.Z) &&
1062                         (pos_camera.Z <= block_bounds.MaxEdge.Z);
1063
1064         if (x_inside && y_inside && z_inside)
1065                 return false; // Camera inside target mapblock
1066
1067         // straight
1068         if (x_inside && y_inside) {
1069                 check = v3s16(pos_camera.X, pos_camera.Y, 0);
1070                 check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
1071                 return true;
1072         } else if (y_inside && z_inside) {
1073                 check = v3s16(0, pos_camera.Y, pos_camera.Z);
1074                 check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
1075                 return true;
1076         } else if (x_inside && z_inside) {
1077                 check = v3s16(pos_camera.X, 0, pos_camera.Z);
1078                 check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
1079                 return true;
1080         }
1081
1082         // diagonal
1083         if (x_inside) {
1084                 check = v3s16(pos_camera.X, 0, 0);
1085                 check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
1086                 check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
1087                 return true;
1088         } else if (y_inside) {
1089                 check = v3s16(0, pos_camera.Y, 0);
1090                 check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
1091                 check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
1092                 return true;
1093         } else if (z_inside) {
1094                 check = v3s16(0, 0, pos_camera.Z);
1095                 check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
1096                 check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
1097                 return true;
1098         }
1099
1100         // Closest node would be a corner, none returned
1101         return false;
1102 }
1103
1104 bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
1105         float step, float stepfac, float offset, float end_offset, u32 needed_count)
1106 {
1107         v3f direction = intToFloat(pos_target - pos_camera, BS);
1108         float distance = direction.getLength();
1109
1110         // Normalize direction vector
1111         if (distance > 0.0f)
1112                 direction /= distance;
1113
1114         v3f pos_origin_f = intToFloat(pos_camera, BS);
1115         u32 count = 0;
1116         bool is_valid_position;
1117
1118         for (; offset < distance + end_offset; offset += step) {
1119                 v3f pos_node_f = pos_origin_f + direction * offset;
1120                 v3s16 pos_node = floatToInt(pos_node_f, BS);
1121
1122                 MapNode node = getNode(pos_node, &is_valid_position);
1123
1124                 if (is_valid_position &&
1125                                 !m_nodedef->get(node).light_propagates) {
1126                         // Cannot see through light-blocking nodes --> occluded
1127                         count++;
1128                         if (count >= needed_count)
1129                                 return true;
1130                 }
1131                 step *= stepfac;
1132         }
1133         return false;
1134 }
1135
1136 bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes)
1137 {
1138         // Check occlusion for center and all 8 corners of the mapblock
1139         // Overshoot a little for less flickering
1140         static const s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
1141         static const v3s16 dir9[9] = {
1142                 v3s16( 0,  0,  0),
1143                 v3s16( 1,  1,  1) * bs2,
1144                 v3s16( 1,  1, -1) * bs2,
1145                 v3s16( 1, -1,  1) * bs2,
1146                 v3s16( 1, -1, -1) * bs2,
1147                 v3s16(-1,  1,  1) * bs2,
1148                 v3s16(-1,  1, -1) * bs2,
1149                 v3s16(-1, -1,  1) * bs2,
1150                 v3s16(-1, -1, -1) * bs2,
1151         };
1152
1153         v3s16 pos_blockcenter = block->getPosRelative() + (MAP_BLOCKSIZE / 2);
1154
1155         // Starting step size, value between 1m and sqrt(3)m
1156         float step = BS * 1.2f;
1157         // Multiply step by each iteraction by 'stepfac' to reduce checks in distance
1158         float stepfac = 1.05f;
1159
1160         float start_offset = BS * 1.0f;
1161
1162         // The occlusion search of 'isOccluded()' must stop short of the target
1163         // point by distance 'end_offset' to not enter the target mapblock.
1164         // For the 8 mapblock corners 'end_offset' must therefore be the maximum
1165         // diagonal of a mapblock, because we must consider all view angles.
1166         // sqrt(1^2 + 1^2 + 1^2) = 1.732
1167         float end_offset = -BS * MAP_BLOCKSIZE * 1.732f;
1168
1169         // to reduce the likelihood of falsely occluded blocks
1170         // require at least two solid blocks
1171         // this is a HACK, we should think of a more precise algorithm
1172         u32 needed_count = 2;
1173
1174         // Additional occlusion check, see comments in that function
1175         v3s16 check;
1176         if (determineAdditionalOcclusionCheck(cam_pos_nodes, block->getBox(), check)) {
1177                 // node is always on a side facing the camera, end_offset can be lower
1178                 if (!isOccluded(cam_pos_nodes, check, step, stepfac, start_offset,
1179                                 -1.0f, needed_count))
1180                         return false;
1181         }
1182
1183         for (const v3s16 &dir : dir9) {
1184                 if (!isOccluded(cam_pos_nodes, pos_blockcenter + dir, step, stepfac,
1185                                 start_offset, end_offset, needed_count))
1186                         return false;
1187         }
1188         return true;
1189 }
1190
1191 /*
1192         ServerMap
1193 */
1194 ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef,
1195                 EmergeManager *emerge, MetricsBackend *mb):
1196         Map(gamedef),
1197         settings_mgr(savedir + DIR_DELIM + "map_meta.txt"),
1198         m_emerge(emerge)
1199 {
1200         verbosestream<<FUNCTION_NAME<<std::endl;
1201
1202         // Tell the EmergeManager about our MapSettingsManager
1203         emerge->map_settings_mgr = &settings_mgr;
1204
1205         /*
1206                 Try to load map; if not found, create a new one.
1207         */
1208
1209         // Determine which database backend to use
1210         std::string conf_path = savedir + DIR_DELIM + "world.mt";
1211         Settings conf;
1212         bool succeeded = conf.readConfigFile(conf_path.c_str());
1213         if (!succeeded || !conf.exists("backend")) {
1214                 // fall back to sqlite3
1215                 conf.set("backend", "sqlite3");
1216         }
1217         std::string backend = conf.get("backend");
1218         dbase = createDatabase(backend, savedir, conf);
1219         if (conf.exists("readonly_backend")) {
1220                 std::string readonly_dir = savedir + DIR_DELIM + "readonly";
1221                 dbase_ro = createDatabase(conf.get("readonly_backend"), readonly_dir, conf);
1222         }
1223         if (!conf.updateConfigFile(conf_path.c_str()))
1224                 errorstream << "ServerMap::ServerMap(): Failed to update world.mt!" << std::endl;
1225
1226         m_savedir = savedir;
1227         m_map_saving_enabled = false;
1228
1229         m_save_time_counter = mb->addCounter(
1230                 "minetest_map_save_time", "Time spent saving blocks (in microseconds)");
1231         m_save_count_counter = mb->addCounter(
1232                 "minetest_map_saved_blocks", "Number of blocks saved");
1233         m_loaded_blocks_gauge = mb->addGauge(
1234                 "minetest_map_loaded_blocks", "Number of loaded blocks");
1235
1236         m_map_compression_level = rangelim(g_settings->getS16("map_compression_level_disk"), -1, 9);
1237
1238         try {
1239                 // If directory exists, check contents and load if possible
1240                 if (fs::PathExists(m_savedir)) {
1241                         // If directory is empty, it is safe to save into it.
1242                         if (fs::GetDirListing(m_savedir).empty()) {
1243                                 infostream<<"ServerMap: Empty save directory is valid."
1244                                                 <<std::endl;
1245                                 m_map_saving_enabled = true;
1246                         }
1247                         else
1248                         {
1249
1250                                 if (settings_mgr.loadMapMeta()) {
1251                                         infostream << "ServerMap: Metadata loaded from "
1252                                                 << savedir << std::endl;
1253                                 } else {
1254                                         infostream << "ServerMap: Metadata could not be loaded "
1255                                                 "from " << savedir << ", assuming valid save "
1256                                                 "directory." << std::endl;
1257                                 }
1258
1259                                 m_map_saving_enabled = true;
1260                                 // Map loaded, not creating new one
1261                                 return;
1262                         }
1263                 }
1264                 // If directory doesn't exist, it is safe to save to it
1265                 else{
1266                         m_map_saving_enabled = true;
1267                 }
1268         }
1269         catch(std::exception &e)
1270         {
1271                 warningstream<<"ServerMap: Failed to load map from "<<savedir
1272                                 <<", exception: "<<e.what()<<std::endl;
1273                 infostream<<"Please remove the map or fix it."<<std::endl;
1274                 warningstream<<"Map saving will be disabled."<<std::endl;
1275         }
1276 }
1277
1278 ServerMap::~ServerMap()
1279 {
1280         verbosestream<<FUNCTION_NAME<<std::endl;
1281
1282         try
1283         {
1284                 if (m_map_saving_enabled) {
1285                         // Save only changed parts
1286                         save(MOD_STATE_WRITE_AT_UNLOAD);
1287                         infostream << "ServerMap: Saved map to " << m_savedir << std::endl;
1288                 } else {
1289                         infostream << "ServerMap: Map not saved" << std::endl;
1290                 }
1291         }
1292         catch(std::exception &e)
1293         {
1294                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
1295                                 <<", exception: "<<e.what()<<std::endl;
1296         }
1297
1298         /*
1299                 Close database if it was opened
1300         */
1301         delete dbase;
1302         delete dbase_ro;
1303 }
1304
1305 MapgenParams *ServerMap::getMapgenParams()
1306 {
1307         // getMapgenParams() should only ever be called after Server is initialized
1308         assert(settings_mgr.mapgen_params != NULL);
1309         return settings_mgr.mapgen_params;
1310 }
1311
1312 u64 ServerMap::getSeed()
1313 {
1314         return getMapgenParams()->seed;
1315 }
1316
1317 bool ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1318 {
1319         const s16 mapgen_limit_bp = rangelim(
1320                 getMapgenParams()->mapgen_limit, 0, MAX_MAP_GENERATION_LIMIT) /
1321                 MAP_BLOCKSIZE;
1322         return p.X < -mapgen_limit_bp ||
1323                 p.X >  mapgen_limit_bp ||
1324                 p.Y < -mapgen_limit_bp ||
1325                 p.Y >  mapgen_limit_bp ||
1326                 p.Z < -mapgen_limit_bp ||
1327                 p.Z >  mapgen_limit_bp;
1328 }
1329
1330 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
1331 {
1332         s16 csize = getMapgenParams()->chunksize;
1333         v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
1334         v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
1335
1336         if (!m_chunks_in_progress.insert(bpmin).second)
1337                 return false;
1338
1339         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1340         EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
1341
1342         v3s16 extra_borders(1, 1, 1);
1343         v3s16 full_bpmin = bpmin - extra_borders;
1344         v3s16 full_bpmax = bpmax + extra_borders;
1345
1346         // Do nothing if not inside mapgen limits (+-1 because of neighbors)
1347         if (blockpos_over_mapgen_limit(full_bpmin) ||
1348                         blockpos_over_mapgen_limit(full_bpmax))
1349                 return false;
1350
1351         data->seed = getSeed();
1352         data->blockpos_min = bpmin;
1353         data->blockpos_max = bpmax;
1354         data->nodedef = m_nodedef;
1355
1356         /*
1357                 Create the whole area of this and the neighboring blocks
1358         */
1359         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
1360         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
1361                 v2s16 sectorpos(x, z);
1362                 // Sector metadata is loaded from disk if not already loaded.
1363                 MapSector *sector = createSector(sectorpos);
1364                 FATAL_ERROR_IF(sector == NULL, "createSector() failed");
1365
1366                 for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
1367                         v3s16 p(x, y, z);
1368
1369                         MapBlock *block = emergeBlock(p, false);
1370                         if (block == NULL) {
1371                                 block = createBlock(p);
1372
1373                                 // Block gets sunlight if this is true.
1374                                 // Refer to the map generator heuristics.
1375                                 bool ug = m_emerge->isBlockUnderground(p);
1376                                 block->setIsUnderground(ug);
1377                         }
1378                 }
1379         }
1380
1381         /*
1382                 Now we have a big empty area.
1383
1384                 Make a ManualMapVoxelManipulator that contains this and the
1385                 neighboring blocks
1386         */
1387
1388         data->vmanip = new MMVManip(this);
1389         data->vmanip->initialEmerge(full_bpmin, full_bpmax);
1390
1391         // Data is ready now.
1392         return true;
1393 }
1394
1395 void ServerMap::finishBlockMake(BlockMakeData *data,
1396         std::map<v3s16, MapBlock*> *changed_blocks)
1397 {
1398         v3s16 bpmin = data->blockpos_min;
1399         v3s16 bpmax = data->blockpos_max;
1400
1401         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1402         EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
1403
1404         /*
1405                 Blit generated stuff to map
1406                 NOTE: blitBackAll adds nearly everything to changed_blocks
1407         */
1408         data->vmanip->blitBackAll(changed_blocks);
1409
1410         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
1411                 << changed_blocks->size());
1412
1413         /*
1414                 Copy transforming liquid information
1415         */
1416         while (data->transforming_liquid.size()) {
1417                 m_transforming_liquid.push_back(data->transforming_liquid.front());
1418                 data->transforming_liquid.pop_front();
1419         }
1420
1421         for (auto &changed_block : *changed_blocks) {
1422                 MapBlock *block = changed_block.second;
1423                 if (!block)
1424                         continue;
1425                 /*
1426                         Update day/night difference cache of the MapBlocks
1427                 */
1428                 block->expireDayNightDiff();
1429                 /*
1430                         Set block as modified
1431                 */
1432                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1433                         MOD_REASON_EXPIRE_DAYNIGHTDIFF);
1434         }
1435
1436         /*
1437                 Set central blocks as generated
1438         */
1439         for (s16 x = bpmin.X; x <= bpmax.X; x++)
1440         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
1441         for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
1442                 MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
1443                 if (!block)
1444                         continue;
1445
1446                 block->setGenerated(true);
1447         }
1448
1449         /*
1450                 Save changed parts of map
1451                 NOTE: Will be saved later.
1452         */
1453         //save(MOD_STATE_WRITE_AT_UNLOAD);
1454         m_chunks_in_progress.erase(bpmin);
1455 }
1456
1457 MapSector *ServerMap::createSector(v2s16 p2d)
1458 {
1459         /*
1460                 Check if it exists already in memory
1461         */
1462         MapSector *sector = getSectorNoGenerate(p2d);
1463         if (sector)
1464                 return sector;
1465
1466         /*
1467                 Do not create over max mapgen limit
1468         */
1469         if (blockpos_over_max_limit(v3s16(p2d.X, 0, p2d.Y)))
1470                 throw InvalidPositionException("createSector(): pos. over max mapgen limit");
1471
1472         /*
1473                 Generate blank sector
1474         */
1475
1476         sector = new MapSector(this, p2d, m_gamedef);
1477
1478         /*
1479                 Insert to container
1480         */
1481         m_sectors[p2d] = sector;
1482
1483         return sector;
1484 }
1485
1486 MapBlock * ServerMap::createBlock(v3s16 p)
1487 {
1488         /*
1489                 Do not create over max mapgen limit
1490         */
1491         if (blockpos_over_max_limit(p))
1492                 throw InvalidPositionException("createBlock(): pos. over max mapgen limit");
1493
1494         v2s16 p2d(p.X, p.Z);
1495         s16 block_y = p.Y;
1496         /*
1497                 This will create or load a sector if not found in memory.
1498                 If block exists on disk, it will be loaded.
1499
1500                 NOTE: On old save formats, this will be slow, as it generates
1501                       lighting on blocks for them.
1502         */
1503         MapSector *sector;
1504         try {
1505                 sector = createSector(p2d);
1506         } catch (InvalidPositionException &e) {
1507                 infostream<<"createBlock: createSector() failed"<<std::endl;
1508                 throw e;
1509         }
1510
1511         /*
1512                 Try to get a block from the sector
1513         */
1514
1515         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
1516         if (block) {
1517                 if(block->isDummy())
1518                         block->unDummify();
1519                 return block;
1520         }
1521         // Create blank
1522         block = sector->createBlankBlock(block_y);
1523
1524         return block;
1525 }
1526
1527 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
1528 {
1529         {
1530                 MapBlock *block = getBlockNoCreateNoEx(p);
1531                 if (block && !block->isDummy())
1532                         return block;
1533         }
1534
1535         {
1536                 MapBlock *block = loadBlock(p);
1537                 if(block)
1538                         return block;
1539         }
1540
1541         if (create_blank) {
1542                 MapSector *sector = createSector(v2s16(p.X, p.Z));
1543                 MapBlock *block = sector->createBlankBlock(p.Y);
1544
1545                 return block;
1546         }
1547
1548         return NULL;
1549 }
1550
1551 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
1552 {
1553         MapBlock *block = getBlockNoCreateNoEx(p3d);
1554         if (block == NULL)
1555                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
1556
1557         return block;
1558 }
1559
1560 bool ServerMap::isBlockInQueue(v3s16 pos)
1561 {
1562         return m_emerge && m_emerge->isBlockInQueue(pos);
1563 }
1564
1565 void ServerMap::addNodeAndUpdate(v3s16 p, MapNode n,
1566                 std::map<v3s16, MapBlock*> &modified_blocks,
1567                 bool remove_metadata)
1568 {
1569         Map::addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
1570
1571         /*
1572                 Add neighboring liquid nodes and this node to transform queue.
1573                 (it's vital for the node itself to get updated last, if it was removed.)
1574          */
1575
1576         for (const v3s16 &dir : g_7dirs) {
1577                 v3s16 p2 = p + dir;
1578
1579                 bool is_valid_position;
1580                 MapNode n2 = getNode(p2, &is_valid_position);
1581                 if(is_valid_position &&
1582                                 (m_nodedef->get(n2).isLiquid() ||
1583                                 n2.getContent() == CONTENT_AIR))
1584                         m_transforming_liquid.push_back(p2);
1585         }
1586 }
1587
1588 // N.B.  This requires no synchronization, since data will not be modified unless
1589 // the VoxelManipulator being updated belongs to the same thread.
1590 void ServerMap::updateVManip(v3s16 pos)
1591 {
1592         Mapgen *mg = m_emerge->getCurrentMapgen();
1593         if (!mg)
1594                 return;
1595
1596         MMVManip *vm = mg->vm;
1597         if (!vm)
1598                 return;
1599
1600         if (!vm->m_area.contains(pos))
1601                 return;
1602
1603         s32 idx = vm->m_area.index(pos);
1604         vm->m_data[idx] = getNode(pos);
1605         vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
1606
1607         vm->m_is_dirty = true;
1608 }
1609
1610 void ServerMap::reportMetrics(u64 save_time_us, u32 saved_blocks, u32 all_blocks)
1611 {
1612         m_loaded_blocks_gauge->set(all_blocks);
1613         m_save_time_counter->increment(save_time_us);
1614         m_save_count_counter->increment(saved_blocks);
1615 }
1616
1617 void ServerMap::save(ModifiedState save_level)
1618 {
1619         if (!m_map_saving_enabled) {
1620                 warningstream<<"Not saving map, saving disabled."<<std::endl;
1621                 return;
1622         }
1623
1624         const auto start_time = porting::getTimeUs();
1625
1626         if(save_level == MOD_STATE_CLEAN)
1627                 infostream<<"ServerMap: Saving whole map, this can take time."
1628                                 <<std::endl;
1629
1630         if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
1631                 if (settings_mgr.saveMapMeta())
1632                         m_map_metadata_changed = false;
1633         }
1634
1635         // Profile modified reasons
1636         Profiler modprofiler;
1637
1638         u32 block_count = 0;
1639         u32 block_count_all = 0; // Number of blocks in memory
1640
1641         // Don't do anything with sqlite unless something is really saved
1642         bool save_started = false;
1643
1644         for (auto &sector_it : m_sectors) {
1645                 MapSector *sector = sector_it.second;
1646
1647                 MapBlockVect blocks;
1648                 sector->getBlocks(blocks);
1649
1650                 for (MapBlock *block : blocks) {
1651                         block_count_all++;
1652
1653                         if(block->getModified() >= (u32)save_level) {
1654                                 // Lazy beginSave()
1655                                 if(!save_started) {
1656                                         beginSave();
1657                                         save_started = true;
1658                                 }
1659
1660                                 modprofiler.add(block->getModifiedReasonString(), 1);
1661
1662                                 saveBlock(block);
1663                                 block_count++;
1664                         }
1665                 }
1666         }
1667
1668         if(save_started)
1669                 endSave();
1670
1671         /*
1672                 Only print if something happened or saved whole map
1673         */
1674         if(save_level == MOD_STATE_CLEAN
1675                         || block_count != 0) {
1676                 infostream << "ServerMap: Written: "
1677                                 << block_count << " blocks"
1678                                 << ", " << block_count_all << " blocks in memory."
1679                                 << std::endl;
1680                 PrintInfo(infostream); // ServerMap/ClientMap:
1681                 infostream<<"Blocks modified by: "<<std::endl;
1682                 modprofiler.print(infostream);
1683         }
1684
1685         const auto end_time = porting::getTimeUs();
1686         reportMetrics(end_time - start_time, block_count, block_count_all);
1687 }
1688
1689 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
1690 {
1691         dbase->listAllLoadableBlocks(dst);
1692         if (dbase_ro)
1693                 dbase_ro->listAllLoadableBlocks(dst);
1694 }
1695
1696 void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
1697 {
1698         for (auto &sector_it : m_sectors) {
1699                 MapSector *sector = sector_it.second;
1700
1701                 MapBlockVect blocks;
1702                 sector->getBlocks(blocks);
1703
1704                 for (MapBlock *block : blocks) {
1705                         v3s16 p = block->getPos();
1706                         dst.push_back(p);
1707                 }
1708         }
1709 }
1710
1711 MapDatabase *ServerMap::createDatabase(
1712         const std::string &name,
1713         const std::string &savedir,
1714         Settings &conf)
1715 {
1716         if (name == "sqlite3")
1717                 return new MapDatabaseSQLite3(savedir);
1718         if (name == "dummy")
1719                 return new Database_Dummy();
1720         #if USE_LEVELDB
1721         if (name == "leveldb")
1722                 return new Database_LevelDB(savedir);
1723         #endif
1724         #if USE_REDIS
1725         if (name == "redis")
1726                 return new Database_Redis(conf);
1727         #endif
1728         #if USE_POSTGRESQL
1729         if (name == "postgresql") {
1730                 std::string connect_string;
1731                 conf.getNoEx("pgsql_connection", connect_string);
1732                 return new MapDatabasePostgreSQL(connect_string);
1733         }
1734         #endif
1735
1736         throw BaseException(std::string("Database backend ") + name + " not supported.");
1737 }
1738
1739 void ServerMap::beginSave()
1740 {
1741         dbase->beginSave();
1742 }
1743
1744 void ServerMap::endSave()
1745 {
1746         dbase->endSave();
1747 }
1748
1749 bool ServerMap::saveBlock(MapBlock *block)
1750 {
1751         return saveBlock(block, dbase, m_map_compression_level);
1752 }
1753
1754 bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db, int compression_level)
1755 {
1756         v3s16 p3d = block->getPos();
1757
1758         // Dummy blocks are not written
1759         if (block->isDummy()) {
1760                 warningstream << "saveBlock: Not writing dummy block "
1761                         << PP(p3d) << std::endl;
1762                 return true;
1763         }
1764
1765         // Format used for writing
1766         u8 version = SER_FMT_VER_HIGHEST_WRITE;
1767
1768         /*
1769                 [0] u8 serialization version
1770                 [1] data
1771         */
1772         std::ostringstream o(std::ios_base::binary);
1773         o.write((char*) &version, 1);
1774         block->serialize(o, version, true, compression_level);
1775
1776         bool ret = db->saveBlock(p3d, o.str());
1777         if (ret) {
1778                 // We just wrote it to the disk so clear modified flag
1779                 block->resetModified();
1780         }
1781         return ret;
1782 }
1783
1784 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
1785 {
1786         try {
1787                 std::istringstream is(*blob, std::ios_base::binary);
1788
1789                 u8 version = SER_FMT_VER_INVALID;
1790                 is.read((char*)&version, 1);
1791
1792                 if(is.fail())
1793                         throw SerializationError("ServerMap::loadBlock(): Failed"
1794                                         " to read MapBlock version");
1795
1796                 MapBlock *block = NULL;
1797                 bool created_new = false;
1798                 block = sector->getBlockNoCreateNoEx(p3d.Y);
1799                 if(block == NULL)
1800                 {
1801                         block = sector->createBlankBlockNoInsert(p3d.Y);
1802                         created_new = true;
1803                 }
1804
1805                 // Read basic data
1806                 block->deSerialize(is, version, true);
1807
1808                 // If it's a new block, insert it to the map
1809                 if (created_new) {
1810                         sector->insertBlock(block);
1811                         ReflowScan scanner(this, m_emerge->ndef);
1812                         scanner.scan(block, &m_transforming_liquid);
1813                 }
1814
1815                 /*
1816                         Save blocks loaded in old format in new format
1817                 */
1818
1819                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
1820                 // Only save if asked to; no need to update version
1821                 if(save_after_load)
1822                         saveBlock(block);
1823
1824                 // We just loaded it from, so it's up-to-date.
1825                 block->resetModified();
1826         }
1827         catch(SerializationError &e)
1828         {
1829                 errorstream<<"Invalid block data in database"
1830                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
1831                                 <<" (SerializationError): "<<e.what()<<std::endl;
1832
1833                 // TODO: Block should be marked as invalid in memory so that it is
1834                 // not touched but the game can run
1835
1836                 if(g_settings->getBool("ignore_world_load_errors")){
1837                         errorstream<<"Ignoring block load error. Duck and cover! "
1838                                         <<"(ignore_world_load_errors)"<<std::endl;
1839                 } else {
1840                         throw SerializationError("Invalid block data in database");
1841                 }
1842         }
1843 }
1844
1845 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
1846 {
1847         bool created_new = (getBlockNoCreateNoEx(blockpos) == NULL);
1848
1849         v2s16 p2d(blockpos.X, blockpos.Z);
1850
1851         std::string ret;
1852         dbase->loadBlock(blockpos, &ret);
1853         if (!ret.empty()) {
1854                 loadBlock(&ret, blockpos, createSector(p2d), false);
1855         } else if (dbase_ro) {
1856                 dbase_ro->loadBlock(blockpos, &ret);
1857                 if (!ret.empty()) {
1858                         loadBlock(&ret, blockpos, createSector(p2d), false);
1859                 }
1860         } else {
1861                 return NULL;
1862         }
1863
1864         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1865         if (created_new && (block != NULL)) {
1866                 std::map<v3s16, MapBlock*> modified_blocks;
1867                 // Fix lighting if necessary
1868                 voxalgo::update_block_border_lighting(this, block, modified_blocks);
1869                 if (!modified_blocks.empty()) {
1870                         //Modified lighting, send event
1871                         MapEditEvent event;
1872                         event.type = MEET_OTHER;
1873                         std::map<v3s16, MapBlock *>::iterator it;
1874                         for (it = modified_blocks.begin();
1875                                         it != modified_blocks.end(); ++it)
1876                                 event.modified_blocks.insert(it->first);
1877                         dispatchEvent(event);
1878                 }
1879         }
1880         return block;
1881 }
1882
1883 bool ServerMap::deleteBlock(v3s16 blockpos)
1884 {
1885         if (!dbase->deleteBlock(blockpos))
1886                 return false;
1887
1888         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1889         if (block) {
1890                 v2s16 p2d(blockpos.X, blockpos.Z);
1891                 MapSector *sector = getSectorNoGenerate(p2d);
1892                 if (!sector)
1893                         return false;
1894                 sector->deleteBlock(block);
1895         }
1896
1897         return true;
1898 }
1899
1900 void ServerMap::PrintInfo(std::ostream &out)
1901 {
1902         out<<"ServerMap: ";
1903 }
1904
1905 bool ServerMap::repairBlockLight(v3s16 blockpos,
1906         std::map<v3s16, MapBlock *> *modified_blocks)
1907 {
1908         MapBlock *block = emergeBlock(blockpos, false);
1909         if (!block || !block->isGenerated())
1910                 return false;
1911         voxalgo::repair_block_light(this, block, modified_blocks);
1912         return true;
1913 }
1914
1915 MMVManip::MMVManip(Map *map):
1916                 VoxelManipulator(),
1917                 m_map(map)
1918 {
1919         assert(map);
1920 }
1921
1922 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
1923         bool load_if_inexistent)
1924 {
1925         TimeTaker timer1("initialEmerge", &emerge_time);
1926
1927         assert(m_map);
1928
1929         // Units of these are MapBlocks
1930         v3s16 p_min = blockpos_min;
1931         v3s16 p_max = blockpos_max;
1932
1933         VoxelArea block_area_nodes
1934                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
1935
1936         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
1937         if(size_MB >= 1)
1938         {
1939                 infostream<<"initialEmerge: area: ";
1940                 block_area_nodes.print(infostream);
1941                 infostream<<" ("<<size_MB<<"MB)";
1942                 infostream<<std::endl;
1943         }
1944
1945         addArea(block_area_nodes);
1946
1947         for(s32 z=p_min.Z; z<=p_max.Z; z++)
1948         for(s32 y=p_min.Y; y<=p_max.Y; y++)
1949         for(s32 x=p_min.X; x<=p_max.X; x++)
1950         {
1951                 u8 flags = 0;
1952                 MapBlock *block;
1953                 v3s16 p(x,y,z);
1954                 std::map<v3s16, u8>::iterator n;
1955                 n = m_loaded_blocks.find(p);
1956                 if(n != m_loaded_blocks.end())
1957                         continue;
1958
1959                 bool block_data_inexistent = false;
1960                 {
1961                         TimeTaker timer2("emerge load", &emerge_load_time);
1962
1963                         block = m_map->getBlockNoCreateNoEx(p);
1964                         if (!block || block->isDummy())
1965                                 block_data_inexistent = true;
1966                         else
1967                                 block->copyTo(*this);
1968                 }
1969
1970                 if(block_data_inexistent)
1971                 {
1972
1973                         if (load_if_inexistent && !blockpos_over_max_limit(p)) {
1974                                 ServerMap *svrmap = (ServerMap *)m_map;
1975                                 block = svrmap->emergeBlock(p, false);
1976                                 if (block == NULL)
1977                                         block = svrmap->createBlock(p);
1978                                 block->copyTo(*this);
1979                         } else {
1980                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
1981
1982                                 /*
1983                                         Mark area inexistent
1984                                 */
1985                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
1986                                 // Fill with VOXELFLAG_NO_DATA
1987                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
1988                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
1989                                 {
1990                                         s32 i = m_area.index(a.MinEdge.X,y,z);
1991                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
1992                                 }
1993                         }
1994                 }
1995                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
1996                 {
1997                         // Mark that block was loaded as blank
1998                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
1999                 }*/
2000
2001                 m_loaded_blocks[p] = flags;
2002         }
2003
2004         m_is_dirty = false;
2005 }
2006
2007 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
2008         bool overwrite_generated)
2009 {
2010         if(m_area.getExtent() == v3s16(0,0,0))
2011                 return;
2012         assert(m_map);
2013
2014         /*
2015                 Copy data of all blocks
2016         */
2017         for (auto &loaded_block : m_loaded_blocks) {
2018                 v3s16 p = loaded_block.first;
2019                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
2020                 bool existed = !(loaded_block.second & VMANIP_BLOCK_DATA_INEXIST);
2021                 if (!existed || (block == NULL) ||
2022                         (!overwrite_generated && block->isGenerated()))
2023                         continue;
2024
2025                 block->copyFrom(*this);
2026                 block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_VMANIP);
2027
2028                 if(modified_blocks)
2029                         (*modified_blocks)[p] = block;
2030         }
2031 }
2032
2033 MMVManip *MMVManip::clone() const
2034 {
2035         MMVManip *ret = new MMVManip();
2036
2037         const s32 size = m_area.getVolume();
2038         ret->m_area = m_area;
2039         if (m_data) {
2040                 ret->m_data = new MapNode[size];
2041                 memcpy(ret->m_data, m_data, size * sizeof(MapNode));
2042         }
2043         if (m_flags) {
2044                 ret->m_flags = new u8[size];
2045                 memcpy(ret->m_flags, m_flags, size * sizeof(u8));
2046         }
2047
2048         ret->m_is_dirty = m_is_dirty;
2049         // Even if the copy is disconnected from a map object keep the information
2050         // needed to write it back to one
2051         ret->m_loaded_blocks = m_loaded_blocks;
2052
2053         return ret;
2054 }
2055
2056 void MMVManip::reparent(Map *map)
2057 {
2058         assert(map && !m_map);
2059         m_map = map;
2060 }
2061
2062 //END