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