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