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