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