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