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