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