]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / src / map.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "mapsector.h"
22 #include "mapblock.h"
23 #include "filesys.h"
24 #include "voxel.h"
25 #include "voxelalgorithms.h"
26 #include "porting.h"
27 #include "serialization.h"
28 #include "nodemetadata.h"
29 #include "settings.h"
30 #include "log.h"
31 #include "profiler.h"
32 #include "nodedef.h"
33 #include "gamedef.h"
34 #include "util/directiontables.h"
35 #include "util/basic_macros.h"
36 #include "rollback_interface.h"
37 #include "environment.h"
38 #include "reflowscan.h"
39 #include "emerge.h"
40 #include "mapgen/mapgen_v6.h"
41 #include "mapgen/mg_biome.h"
42 #include "config.h"
43 #include "server.h"
44 #include "database/database.h"
45 #include "database/database-dummy.h"
46 #include "database/database-sqlite3.h"
47 #include "script/scripting_server.h"
48 #include <deque>
49 #include <queue>
50 #if USE_LEVELDB
51 #include "database/database-leveldb.h"
52 #endif
53 #if USE_REDIS
54 #include "database/database-redis.h"
55 #endif
56 #if USE_POSTGRESQL
57 #include "database/database-postgresql.h"
58 #endif
59
60
61 /*
62         Map
63 */
64
65 Map::Map(IGameDef *gamedef):
66         m_gamedef(gamedef),
67         m_nodedef(gamedef->ndef())
68 {
69 }
70
71 Map::~Map()
72 {
73         /*
74                 Free all MapSectors
75         */
76         for (auto &sector : m_sectors) {
77                 delete sector.second;
78         }
79 }
80
81 void Map::addEventReceiver(MapEventReceiver *event_receiver)
82 {
83         m_event_receivers.insert(event_receiver);
84 }
85
86 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
87 {
88         m_event_receivers.erase(event_receiver);
89 }
90
91 void Map::dispatchEvent(const MapEditEvent &event)
92 {
93         for (MapEventReceiver *event_receiver : m_event_receivers) {
94                 event_receiver->onMapEditEvent(event);
95         }
96 }
97
98 MapSector * Map::getSectorNoGenerateNoLock(v2s16 p)
99 {
100         if(m_sector_cache != NULL && p == m_sector_cache_p){
101                 MapSector * sector = m_sector_cache;
102                 return sector;
103         }
104
105         std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
106
107         if (n == m_sectors.end())
108                 return NULL;
109
110         MapSector *sector = n->second;
111
112         // Cache the last result
113         m_sector_cache_p = p;
114         m_sector_cache = sector;
115
116         return sector;
117 }
118
119 MapSector * Map::getSectorNoGenerate(v2s16 p)
120 {
121         return getSectorNoGenerateNoLock(p);
122 }
123
124 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
125 {
126         v2s16 p2d(p3d.X, p3d.Z);
127         MapSector * sector = getSectorNoGenerate(p2d);
128         if(sector == NULL)
129                 return NULL;
130         MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
131         return block;
132 }
133
134 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
135 {
136         MapBlock *block = getBlockNoCreateNoEx(p3d);
137         if(block == NULL)
138                 throw InvalidPositionException();
139         return block;
140 }
141
142 void Map::listAllLoadedBlocks(std::vector<v3s16> &dst)
143 {
144         for (auto &sector_it : m_sectors) {
145                 MapSector *sector = sector_it.second;
146
147                 MapBlockVect blocks;
148                 sector->getBlocks(blocks);
149
150                 for (MapBlock *block : blocks) {
151                         v3s16 p = block->getPos();
152                         dst.push_back(p);
153                 }
154         }
155 }
156
157 bool Map::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         m_map_compression_level = rangelim(g_settings->getS16("map_compression_level_disk"), -1, 9);
1254
1255         try {
1256                 // If directory exists, check contents and load if possible
1257                 if (fs::PathExists(m_savedir)) {
1258                         // If directory is empty, it is safe to save into it.
1259                         if (fs::GetDirListing(m_savedir).empty()) {
1260                                 infostream<<"ServerMap: Empty save directory is valid."
1261                                                 <<std::endl;
1262                                 m_map_saving_enabled = true;
1263                         }
1264                         else
1265                         {
1266
1267                                 if (settings_mgr.loadMapMeta()) {
1268                                         infostream << "ServerMap: Metadata loaded from "
1269                                                 << savedir << std::endl;
1270                                 } else {
1271                                         infostream << "ServerMap: Metadata could not be loaded "
1272                                                 "from " << savedir << ", assuming valid save "
1273                                                 "directory." << std::endl;
1274                                 }
1275
1276                                 m_map_saving_enabled = true;
1277                                 // Map loaded, not creating new one
1278                                 return;
1279                         }
1280                 }
1281                 // If directory doesn't exist, it is safe to save to it
1282                 else{
1283                         m_map_saving_enabled = true;
1284                 }
1285         }
1286         catch(std::exception &e)
1287         {
1288                 warningstream<<"ServerMap: Failed to load map from "<<savedir
1289                                 <<", exception: "<<e.what()<<std::endl;
1290                 infostream<<"Please remove the map or fix it."<<std::endl;
1291                 warningstream<<"Map saving will be disabled."<<std::endl;
1292         }
1293 }
1294
1295 ServerMap::~ServerMap()
1296 {
1297         verbosestream<<FUNCTION_NAME<<std::endl;
1298
1299         try
1300         {
1301                 if (m_map_saving_enabled) {
1302                         // Save only changed parts
1303                         save(MOD_STATE_WRITE_AT_UNLOAD);
1304                         infostream << "ServerMap: Saved map to " << m_savedir << std::endl;
1305                 } else {
1306                         infostream << "ServerMap: Map not saved" << std::endl;
1307                 }
1308         }
1309         catch(std::exception &e)
1310         {
1311                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
1312                                 <<", exception: "<<e.what()<<std::endl;
1313         }
1314
1315         /*
1316                 Close database if it was opened
1317         */
1318         delete dbase;
1319         delete dbase_ro;
1320
1321 #if 0
1322         /*
1323                 Free all MapChunks
1324         */
1325         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1326         for(; i.atEnd() == false; i++)
1327         {
1328                 MapChunk *chunk = i.getNode()->getValue();
1329                 delete chunk;
1330         }
1331 #endif
1332 }
1333
1334 MapgenParams *ServerMap::getMapgenParams()
1335 {
1336         // getMapgenParams() should only ever be called after Server is initialized
1337         assert(settings_mgr.mapgen_params != NULL);
1338         return settings_mgr.mapgen_params;
1339 }
1340
1341 u64 ServerMap::getSeed()
1342 {
1343         return getMapgenParams()->seed;
1344 }
1345
1346 bool ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1347 {
1348         const s16 mapgen_limit_bp = rangelim(
1349                 getMapgenParams()->mapgen_limit, 0, MAX_MAP_GENERATION_LIMIT) /
1350                 MAP_BLOCKSIZE;
1351         return p.X < -mapgen_limit_bp ||
1352                 p.X >  mapgen_limit_bp ||
1353                 p.Y < -mapgen_limit_bp ||
1354                 p.Y >  mapgen_limit_bp ||
1355                 p.Z < -mapgen_limit_bp ||
1356                 p.Z >  mapgen_limit_bp;
1357 }
1358
1359 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
1360 {
1361         s16 csize = getMapgenParams()->chunksize;
1362         v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
1363         v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
1364
1365         if (!m_chunks_in_progress.insert(bpmin).second)
1366                 return false;
1367
1368         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1369         EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
1370
1371         v3s16 extra_borders(1, 1, 1);
1372         v3s16 full_bpmin = bpmin - extra_borders;
1373         v3s16 full_bpmax = bpmax + extra_borders;
1374
1375         // Do nothing if not inside mapgen limits (+-1 because of neighbors)
1376         if (blockpos_over_mapgen_limit(full_bpmin) ||
1377                         blockpos_over_mapgen_limit(full_bpmax))
1378                 return false;
1379
1380         data->seed = getSeed();
1381         data->blockpos_min = bpmin;
1382         data->blockpos_max = bpmax;
1383         data->nodedef = m_nodedef;
1384
1385         /*
1386                 Create the whole area of this and the neighboring blocks
1387         */
1388         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
1389         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
1390                 v2s16 sectorpos(x, z);
1391                 // Sector metadata is loaded from disk if not already loaded.
1392                 MapSector *sector = createSector(sectorpos);
1393                 FATAL_ERROR_IF(sector == NULL, "createSector() failed");
1394
1395                 for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
1396                         v3s16 p(x, y, z);
1397
1398                         MapBlock *block = emergeBlock(p, false);
1399                         if (block == NULL) {
1400                                 block = createBlock(p);
1401
1402                                 // Block gets sunlight if this is true.
1403                                 // Refer to the map generator heuristics.
1404                                 bool ug = m_emerge->isBlockUnderground(p);
1405                                 block->setIsUnderground(ug);
1406                         }
1407                 }
1408         }
1409
1410         /*
1411                 Now we have a big empty area.
1412
1413                 Make a ManualMapVoxelManipulator that contains this and the
1414                 neighboring blocks
1415         */
1416
1417         data->vmanip = new MMVManip(this);
1418         data->vmanip->initialEmerge(full_bpmin, full_bpmax);
1419
1420         // Note: we may need this again at some point.
1421 #if 0
1422         // Ensure none of the blocks to be generated were marked as
1423         // containing CONTENT_IGNORE
1424         for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
1425                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
1426                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
1427                                 core::map<v3s16, u8>::Node *n;
1428                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
1429                                 if (n == NULL)
1430                                         continue;
1431                                 u8 flags = n->getValue();
1432                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
1433                                 n->setValue(flags);
1434                         }
1435                 }
1436         }
1437 #endif
1438
1439         // Data is ready now.
1440         return true;
1441 }
1442
1443 void ServerMap::finishBlockMake(BlockMakeData *data,
1444         std::map<v3s16, MapBlock*> *changed_blocks)
1445 {
1446         v3s16 bpmin = data->blockpos_min;
1447         v3s16 bpmax = data->blockpos_max;
1448
1449         v3s16 extra_borders(1, 1, 1);
1450
1451         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1452         EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
1453
1454         /*
1455                 Blit generated stuff to map
1456                 NOTE: blitBackAll adds nearly everything to changed_blocks
1457         */
1458         data->vmanip->blitBackAll(changed_blocks);
1459
1460         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
1461                 << changed_blocks->size());
1462
1463         /*
1464                 Copy transforming liquid information
1465         */
1466         while (data->transforming_liquid.size()) {
1467                 m_transforming_liquid.push_back(data->transforming_liquid.front());
1468                 data->transforming_liquid.pop_front();
1469         }
1470
1471         for (auto &changed_block : *changed_blocks) {
1472                 MapBlock *block = changed_block.second;
1473                 if (!block)
1474                         continue;
1475                 /*
1476                         Update day/night difference cache of the MapBlocks
1477                 */
1478                 block->expireDayNightDiff();
1479                 /*
1480                         Set block as modified
1481                 */
1482                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1483                         MOD_REASON_EXPIRE_DAYNIGHTDIFF);
1484         }
1485
1486         /*
1487                 Set central blocks as generated
1488         */
1489         for (s16 x = bpmin.X; x <= bpmax.X; x++)
1490         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
1491         for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
1492                 MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
1493                 if (!block)
1494                         continue;
1495
1496                 block->setGenerated(true);
1497         }
1498
1499         /*
1500                 Save changed parts of map
1501                 NOTE: Will be saved later.
1502         */
1503         //save(MOD_STATE_WRITE_AT_UNLOAD);
1504         m_chunks_in_progress.erase(bpmin);
1505 }
1506
1507 MapSector *ServerMap::createSector(v2s16 p2d)
1508 {
1509         /*
1510                 Check if it exists already in memory
1511         */
1512         MapSector *sector = getSectorNoGenerate(p2d);
1513         if (sector)
1514                 return sector;
1515
1516         /*
1517                 Do not create over max mapgen limit
1518         */
1519         const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
1520         if (p2d.X < -max_limit_bp ||
1521                         p2d.X >  max_limit_bp ||
1522                         p2d.Y < -max_limit_bp ||
1523                         p2d.Y >  max_limit_bp)
1524                 throw InvalidPositionException("createSector(): pos. over max mapgen limit");
1525
1526         /*
1527                 Generate blank sector
1528         */
1529
1530         sector = new MapSector(this, p2d, m_gamedef);
1531
1532         // Sector position on map in nodes
1533         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
1534
1535         /*
1536                 Insert to container
1537         */
1538         m_sectors[p2d] = sector;
1539
1540         return sector;
1541 }
1542
1543 #if 0
1544 /*
1545         This is a quick-hand function for calling makeBlock().
1546 */
1547 MapBlock * ServerMap::generateBlock(
1548                 v3s16 p,
1549                 std::map<v3s16, MapBlock*> &modified_blocks
1550 )
1551 {
1552         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
1553
1554         TimeTaker timer("generateBlock");
1555
1556         //MapBlock *block = original_dummy;
1557
1558         v2s16 p2d(p.X, p.Z);
1559         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
1560
1561         /*
1562                 Do not generate over-limit
1563         */
1564         if(blockpos_over_limit(p))
1565         {
1566                 infostream<<FUNCTION_NAME<<": Block position over limit"<<std::endl;
1567                 throw InvalidPositionException("generateBlock(): pos. over limit");
1568         }
1569
1570         /*
1571                 Create block make data
1572         */
1573         BlockMakeData data;
1574         initBlockMake(&data, p);
1575
1576         /*
1577                 Generate block
1578         */
1579         {
1580                 TimeTaker t("mapgen::make_block()");
1581                 mapgen->makeChunk(&data);
1582                 //mapgen::make_block(&data);
1583
1584                 if(enable_mapgen_debug_info == false)
1585                         t.stop(true); // Hide output
1586         }
1587
1588         /*
1589                 Blit data back on map, update lighting, add mobs and whatever this does
1590         */
1591         finishBlockMake(&data, modified_blocks);
1592
1593         /*
1594                 Get central block
1595         */
1596         MapBlock *block = getBlockNoCreateNoEx(p);
1597
1598 #if 0
1599         /*
1600                 Check result
1601         */
1602         if(block)
1603         {
1604                 bool erroneus_content = false;
1605                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1606                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1607                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1608                 {
1609                         v3s16 p(x0,y0,z0);
1610                         MapNode n = block->getNode(p);
1611                         if(n.getContent() == CONTENT_IGNORE)
1612                         {
1613                                 infostream<<"CONTENT_IGNORE at "
1614                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1615                                                 <<std::endl;
1616                                 erroneus_content = true;
1617                                 assert(0);
1618                         }
1619                 }
1620                 if(erroneus_content)
1621                 {
1622                         assert(0);
1623                 }
1624         }
1625 #endif
1626
1627 #if 0
1628         /*
1629                 Generate a completely empty block
1630         */
1631         if(block)
1632         {
1633                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1634                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1635                 {
1636                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1637                         {
1638                                 MapNode n;
1639                                 n.setContent(CONTENT_AIR);
1640                                 block->setNode(v3s16(x0,y0,z0), n);
1641                         }
1642                 }
1643         }
1644 #endif
1645
1646         if(enable_mapgen_debug_info == false)
1647                 timer.stop(true); // Hide output
1648
1649         return block;
1650 }
1651 #endif
1652
1653 MapBlock * ServerMap::createBlock(v3s16 p)
1654 {
1655         /*
1656                 Do not create over max mapgen limit
1657         */
1658         if (blockpos_over_max_limit(p))
1659                 throw InvalidPositionException("createBlock(): pos. over max mapgen limit");
1660
1661         v2s16 p2d(p.X, p.Z);
1662         s16 block_y = p.Y;
1663         /*
1664                 This will create or load a sector if not found in memory.
1665                 If block exists on disk, it will be loaded.
1666
1667                 NOTE: On old save formats, this will be slow, as it generates
1668                       lighting on blocks for them.
1669         */
1670         MapSector *sector;
1671         try {
1672                 sector = createSector(p2d);
1673         } catch (InvalidPositionException &e) {
1674                 infostream<<"createBlock: createSector() failed"<<std::endl;
1675                 throw e;
1676         }
1677
1678         /*
1679                 Try to get a block from the sector
1680         */
1681
1682         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
1683         if (block) {
1684                 if(block->isDummy())
1685                         block->unDummify();
1686                 return block;
1687         }
1688         // Create blank
1689         block = sector->createBlankBlock(block_y);
1690
1691         return block;
1692 }
1693
1694 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
1695 {
1696         {
1697                 MapBlock *block = getBlockNoCreateNoEx(p);
1698                 if (block && !block->isDummy())
1699                         return block;
1700         }
1701
1702         {
1703                 MapBlock *block = loadBlock(p);
1704                 if(block)
1705                         return block;
1706         }
1707
1708         if (create_blank) {
1709                 MapSector *sector = createSector(v2s16(p.X, p.Z));
1710                 MapBlock *block = sector->createBlankBlock(p.Y);
1711
1712                 return block;
1713         }
1714
1715         return NULL;
1716 }
1717
1718 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
1719 {
1720         MapBlock *block = getBlockNoCreateNoEx(p3d);
1721         if (block == NULL)
1722                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
1723
1724         return block;
1725 }
1726
1727 // N.B.  This requires no synchronization, since data will not be modified unless
1728 // the VoxelManipulator being updated belongs to the same thread.
1729 void ServerMap::updateVManip(v3s16 pos)
1730 {
1731         Mapgen *mg = m_emerge->getCurrentMapgen();
1732         if (!mg)
1733                 return;
1734
1735         MMVManip *vm = mg->vm;
1736         if (!vm)
1737                 return;
1738
1739         if (!vm->m_area.contains(pos))
1740                 return;
1741
1742         s32 idx = vm->m_area.index(pos);
1743         vm->m_data[idx] = getNode(pos);
1744         vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
1745
1746         vm->m_is_dirty = true;
1747 }
1748
1749 void ServerMap::save(ModifiedState save_level)
1750 {
1751         if (!m_map_saving_enabled) {
1752                 warningstream<<"Not saving map, saving disabled."<<std::endl;
1753                 return;
1754         }
1755
1756         u64 start_time = porting::getTimeNs();
1757
1758         if(save_level == MOD_STATE_CLEAN)
1759                 infostream<<"ServerMap: Saving whole map, this can take time."
1760                                 <<std::endl;
1761
1762         if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
1763                 if (settings_mgr.saveMapMeta())
1764                         m_map_metadata_changed = false;
1765         }
1766
1767         // Profile modified reasons
1768         Profiler modprofiler;
1769
1770         u32 block_count = 0;
1771         u32 block_count_all = 0; // Number of blocks in memory
1772
1773         // Don't do anything with sqlite unless something is really saved
1774         bool save_started = false;
1775
1776         for (auto &sector_it : m_sectors) {
1777                 MapSector *sector = sector_it.second;
1778
1779                 MapBlockVect blocks;
1780                 sector->getBlocks(blocks);
1781
1782                 for (MapBlock *block : blocks) {
1783                         block_count_all++;
1784
1785                         if(block->getModified() >= (u32)save_level) {
1786                                 // Lazy beginSave()
1787                                 if(!save_started) {
1788                                         beginSave();
1789                                         save_started = true;
1790                                 }
1791
1792                                 modprofiler.add(block->getModifiedReasonString(), 1);
1793
1794                                 saveBlock(block);
1795                                 block_count++;
1796                         }
1797                 }
1798         }
1799
1800         if(save_started)
1801                 endSave();
1802
1803         /*
1804                 Only print if something happened or saved whole map
1805         */
1806         if(save_level == MOD_STATE_CLEAN
1807                         || block_count != 0) {
1808                 infostream << "ServerMap: Written: "
1809                                 << block_count << " blocks"
1810                                 << ", " << block_count_all << " blocks in memory."
1811                                 << std::endl;
1812                 PrintInfo(infostream); // ServerMap/ClientMap:
1813                 infostream<<"Blocks modified by: "<<std::endl;
1814                 modprofiler.print(infostream);
1815         }
1816
1817         auto end_time = porting::getTimeNs();
1818         m_save_time_counter->increment(end_time - start_time);
1819 }
1820
1821 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
1822 {
1823         dbase->listAllLoadableBlocks(dst);
1824         if (dbase_ro)
1825                 dbase_ro->listAllLoadableBlocks(dst);
1826 }
1827
1828 MapDatabase *ServerMap::createDatabase(
1829         const std::string &name,
1830         const std::string &savedir,
1831         Settings &conf)
1832 {
1833         if (name == "sqlite3")
1834                 return new MapDatabaseSQLite3(savedir);
1835         if (name == "dummy")
1836                 return new Database_Dummy();
1837         #if USE_LEVELDB
1838         if (name == "leveldb")
1839                 return new Database_LevelDB(savedir);
1840         #endif
1841         #if USE_REDIS
1842         if (name == "redis")
1843                 return new Database_Redis(conf);
1844         #endif
1845         #if USE_POSTGRESQL
1846         if (name == "postgresql") {
1847                 std::string connect_string;
1848                 conf.getNoEx("pgsql_connection", connect_string);
1849                 return new MapDatabasePostgreSQL(connect_string);
1850         }
1851         #endif
1852
1853         throw BaseException(std::string("Database backend ") + name + " not supported.");
1854 }
1855
1856 void ServerMap::beginSave()
1857 {
1858         dbase->beginSave();
1859 }
1860
1861 void ServerMap::endSave()
1862 {
1863         dbase->endSave();
1864 }
1865
1866 bool ServerMap::saveBlock(MapBlock *block)
1867 {
1868         return saveBlock(block, dbase, m_map_compression_level);
1869 }
1870
1871 bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db, int compression_level)
1872 {
1873         v3s16 p3d = block->getPos();
1874
1875         // Dummy blocks are not written
1876         if (block->isDummy()) {
1877                 warningstream << "saveBlock: Not writing dummy block "
1878                         << PP(p3d) << std::endl;
1879                 return true;
1880         }
1881
1882         // Format used for writing
1883         u8 version = SER_FMT_VER_HIGHEST_WRITE;
1884
1885         /*
1886                 [0] u8 serialization version
1887                 [1] data
1888         */
1889         std::ostringstream o(std::ios_base::binary);
1890         o.write((char*) &version, 1);
1891         block->serialize(o, version, true, compression_level);
1892
1893         bool ret = db->saveBlock(p3d, o.str());
1894         if (ret) {
1895                 // We just wrote it to the disk so clear modified flag
1896                 block->resetModified();
1897         }
1898         return ret;
1899 }
1900
1901 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
1902 {
1903         try {
1904                 std::istringstream is(*blob, std::ios_base::binary);
1905
1906                 u8 version = SER_FMT_VER_INVALID;
1907                 is.read((char*)&version, 1);
1908
1909                 if(is.fail())
1910                         throw SerializationError("ServerMap::loadBlock(): Failed"
1911                                         " to read MapBlock version");
1912
1913                 MapBlock *block = NULL;
1914                 bool created_new = false;
1915                 block = sector->getBlockNoCreateNoEx(p3d.Y);
1916                 if(block == NULL)
1917                 {
1918                         block = sector->createBlankBlockNoInsert(p3d.Y);
1919                         created_new = true;
1920                 }
1921
1922                 // Read basic data
1923                 block->deSerialize(is, version, true);
1924
1925                 // If it's a new block, insert it to the map
1926                 if (created_new) {
1927                         sector->insertBlock(block);
1928                         ReflowScan scanner(this, m_emerge->ndef);
1929                         scanner.scan(block, &m_transforming_liquid);
1930                 }
1931
1932                 /*
1933                         Save blocks loaded in old format in new format
1934                 */
1935
1936                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
1937                 // Only save if asked to; no need to update version
1938                 if(save_after_load)
1939                         saveBlock(block);
1940
1941                 // We just loaded it from, so it's up-to-date.
1942                 block->resetModified();
1943         }
1944         catch(SerializationError &e)
1945         {
1946                 errorstream<<"Invalid block data in database"
1947                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
1948                                 <<" (SerializationError): "<<e.what()<<std::endl;
1949
1950                 // TODO: Block should be marked as invalid in memory so that it is
1951                 // not touched but the game can run
1952
1953                 if(g_settings->getBool("ignore_world_load_errors")){
1954                         errorstream<<"Ignoring block load error. Duck and cover! "
1955                                         <<"(ignore_world_load_errors)"<<std::endl;
1956                 } else {
1957                         throw SerializationError("Invalid block data in database");
1958                 }
1959         }
1960 }
1961
1962 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
1963 {
1964         bool created_new = (getBlockNoCreateNoEx(blockpos) == NULL);
1965
1966         v2s16 p2d(blockpos.X, blockpos.Z);
1967
1968         std::string ret;
1969         dbase->loadBlock(blockpos, &ret);
1970         if (!ret.empty()) {
1971                 loadBlock(&ret, blockpos, createSector(p2d), false);
1972         } else if (dbase_ro) {
1973                 dbase_ro->loadBlock(blockpos, &ret);
1974                 if (!ret.empty()) {
1975                         loadBlock(&ret, blockpos, createSector(p2d), false);
1976                 }
1977         } else {
1978                 return NULL;
1979         }
1980
1981         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1982         if (created_new && (block != NULL)) {
1983                 std::map<v3s16, MapBlock*> modified_blocks;
1984                 // Fix lighting if necessary
1985                 voxalgo::update_block_border_lighting(this, block, modified_blocks);
1986                 if (!modified_blocks.empty()) {
1987                         //Modified lighting, send event
1988                         MapEditEvent event;
1989                         event.type = MEET_OTHER;
1990                         std::map<v3s16, MapBlock *>::iterator it;
1991                         for (it = modified_blocks.begin();
1992                                         it != modified_blocks.end(); ++it)
1993                                 event.modified_blocks.insert(it->first);
1994                         dispatchEvent(event);
1995                 }
1996         }
1997         return block;
1998 }
1999
2000 bool ServerMap::deleteBlock(v3s16 blockpos)
2001 {
2002         if (!dbase->deleteBlock(blockpos))
2003                 return false;
2004
2005         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2006         if (block) {
2007                 v2s16 p2d(blockpos.X, blockpos.Z);
2008                 MapSector *sector = getSectorNoGenerate(p2d);
2009                 if (!sector)
2010                         return false;
2011                 sector->deleteBlock(block);
2012         }
2013
2014         return true;
2015 }
2016
2017 void ServerMap::PrintInfo(std::ostream &out)
2018 {
2019         out<<"ServerMap: ";
2020 }
2021
2022 bool ServerMap::repairBlockLight(v3s16 blockpos,
2023         std::map<v3s16, MapBlock *> *modified_blocks)
2024 {
2025         MapBlock *block = emergeBlock(blockpos, false);
2026         if (!block || !block->isGenerated())
2027                 return false;
2028         voxalgo::repair_block_light(this, block, modified_blocks);
2029         return true;
2030 }
2031
2032 MMVManip::MMVManip(Map *map):
2033                 VoxelManipulator(),
2034                 m_map(map)
2035 {
2036 }
2037
2038 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
2039         bool load_if_inexistent)
2040 {
2041         TimeTaker timer1("initialEmerge", &emerge_time);
2042
2043         // Units of these are MapBlocks
2044         v3s16 p_min = blockpos_min;
2045         v3s16 p_max = blockpos_max;
2046
2047         VoxelArea block_area_nodes
2048                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
2049
2050         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
2051         if(size_MB >= 1)
2052         {
2053                 infostream<<"initialEmerge: area: ";
2054                 block_area_nodes.print(infostream);
2055                 infostream<<" ("<<size_MB<<"MB)";
2056                 infostream<<std::endl;
2057         }
2058
2059         addArea(block_area_nodes);
2060
2061         for(s32 z=p_min.Z; z<=p_max.Z; z++)
2062         for(s32 y=p_min.Y; y<=p_max.Y; y++)
2063         for(s32 x=p_min.X; x<=p_max.X; x++)
2064         {
2065                 u8 flags = 0;
2066                 MapBlock *block;
2067                 v3s16 p(x,y,z);
2068                 std::map<v3s16, u8>::iterator n;
2069                 n = m_loaded_blocks.find(p);
2070                 if(n != m_loaded_blocks.end())
2071                         continue;
2072
2073                 bool block_data_inexistent = false;
2074                 {
2075                         TimeTaker timer2("emerge load", &emerge_load_time);
2076
2077                         block = m_map->getBlockNoCreateNoEx(p);
2078                         if (!block || block->isDummy())
2079                                 block_data_inexistent = true;
2080                         else
2081                                 block->copyTo(*this);
2082                 }
2083
2084                 if(block_data_inexistent)
2085                 {
2086
2087                         if (load_if_inexistent && !blockpos_over_max_limit(p)) {
2088                                 ServerMap *svrmap = (ServerMap *)m_map;
2089                                 block = svrmap->emergeBlock(p, false);
2090                                 if (block == NULL)
2091                                         block = svrmap->createBlock(p);
2092                                 block->copyTo(*this);
2093                         } else {
2094                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
2095
2096                                 /*
2097                                         Mark area inexistent
2098                                 */
2099                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
2100                                 // Fill with VOXELFLAG_NO_DATA
2101                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
2102                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
2103                                 {
2104                                         s32 i = m_area.index(a.MinEdge.X,y,z);
2105                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
2106                                 }
2107                         }
2108                 }
2109                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
2110                 {
2111                         // Mark that block was loaded as blank
2112                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
2113                 }*/
2114
2115                 m_loaded_blocks[p] = flags;
2116         }
2117
2118         m_is_dirty = false;
2119 }
2120
2121 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
2122         bool overwrite_generated)
2123 {
2124         if(m_area.getExtent() == v3s16(0,0,0))
2125                 return;
2126
2127         /*
2128                 Copy data of all blocks
2129         */
2130         for (auto &loaded_block : m_loaded_blocks) {
2131                 v3s16 p = loaded_block.first;
2132                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
2133                 bool existed = !(loaded_block.second & VMANIP_BLOCK_DATA_INEXIST);
2134                 if (!existed || (block == NULL) ||
2135                         (!overwrite_generated && block->isGenerated()))
2136                         continue;
2137
2138                 block->copyFrom(*this);
2139                 block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_VMANIP);
2140
2141                 if(modified_blocks)
2142                         (*modified_blocks)[p] = block;
2143         }
2144 }
2145
2146 //END