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