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