]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
Add support for statbar “off state” icons (#9462)
[minetest.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, MetricsBackend *mb):
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         m_save_time_counter = mb->addCounter("minetest_core_map_save_time", "Map save time (in nanoseconds)");
1225
1226         try {
1227                 // If directory exists, check contents and load if possible
1228                 if (fs::PathExists(m_savedir)) {
1229                         // If directory is empty, it is safe to save into it.
1230                         if (fs::GetDirListing(m_savedir).empty()) {
1231                                 infostream<<"ServerMap: Empty save directory is valid."
1232                                                 <<std::endl;
1233                                 m_map_saving_enabled = true;
1234                         }
1235                         else
1236                         {
1237
1238                                 if (settings_mgr.loadMapMeta()) {
1239                                         infostream << "ServerMap: Metadata loaded from "
1240                                                 << savedir << std::endl;
1241                                 } else {
1242                                         infostream << "ServerMap: Metadata could not be loaded "
1243                                                 "from " << savedir << ", assuming valid save "
1244                                                 "directory." << std::endl;
1245                                 }
1246
1247                                 m_map_saving_enabled = true;
1248                                 // Map loaded, not creating new one
1249                                 return;
1250                         }
1251                 }
1252                 // If directory doesn't exist, it is safe to save to it
1253                 else{
1254                         m_map_saving_enabled = true;
1255                 }
1256         }
1257         catch(std::exception &e)
1258         {
1259                 warningstream<<"ServerMap: Failed to load map from "<<savedir
1260                                 <<", exception: "<<e.what()<<std::endl;
1261                 infostream<<"Please remove the map or fix it."<<std::endl;
1262                 warningstream<<"Map saving will be disabled."<<std::endl;
1263         }
1264 }
1265
1266 ServerMap::~ServerMap()
1267 {
1268         verbosestream<<FUNCTION_NAME<<std::endl;
1269
1270         try
1271         {
1272                 if (m_map_saving_enabled) {
1273                         // Save only changed parts
1274                         save(MOD_STATE_WRITE_AT_UNLOAD);
1275                         infostream << "ServerMap: Saved map to " << m_savedir << std::endl;
1276                 } else {
1277                         infostream << "ServerMap: Map not saved" << std::endl;
1278                 }
1279         }
1280         catch(std::exception &e)
1281         {
1282                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
1283                                 <<", exception: "<<e.what()<<std::endl;
1284         }
1285
1286         /*
1287                 Close database if it was opened
1288         */
1289         delete dbase;
1290         delete dbase_ro;
1291
1292 #if 0
1293         /*
1294                 Free all MapChunks
1295         */
1296         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1297         for(; i.atEnd() == false; i++)
1298         {
1299                 MapChunk *chunk = i.getNode()->getValue();
1300                 delete chunk;
1301         }
1302 #endif
1303 }
1304
1305 MapgenParams *ServerMap::getMapgenParams()
1306 {
1307         // getMapgenParams() should only ever be called after Server is initialized
1308         assert(settings_mgr.mapgen_params != NULL);
1309         return settings_mgr.mapgen_params;
1310 }
1311
1312 u64 ServerMap::getSeed()
1313 {
1314         return getMapgenParams()->seed;
1315 }
1316
1317 s16 ServerMap::getWaterLevel()
1318 {
1319         return getMapgenParams()->water_level;
1320 }
1321
1322 bool ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1323 {
1324         const s16 mapgen_limit_bp = rangelim(
1325                 getMapgenParams()->mapgen_limit, 0, MAX_MAP_GENERATION_LIMIT) /
1326                 MAP_BLOCKSIZE;
1327         return p.X < -mapgen_limit_bp ||
1328                 p.X >  mapgen_limit_bp ||
1329                 p.Y < -mapgen_limit_bp ||
1330                 p.Y >  mapgen_limit_bp ||
1331                 p.Z < -mapgen_limit_bp ||
1332                 p.Z >  mapgen_limit_bp;
1333 }
1334
1335 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
1336 {
1337         s16 csize = getMapgenParams()->chunksize;
1338         v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
1339         v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
1340
1341         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1342         EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
1343
1344         v3s16 extra_borders(1, 1, 1);
1345         v3s16 full_bpmin = bpmin - extra_borders;
1346         v3s16 full_bpmax = bpmax + extra_borders;
1347
1348         // Do nothing if not inside mapgen limits (+-1 because of neighbors)
1349         if (blockpos_over_mapgen_limit(full_bpmin) ||
1350                         blockpos_over_mapgen_limit(full_bpmax))
1351                 return false;
1352
1353         data->seed = getSeed();
1354         data->blockpos_min = bpmin;
1355         data->blockpos_max = bpmax;
1356         data->blockpos_requested = blockpos;
1357         data->nodedef = m_nodedef;
1358
1359         /*
1360                 Create the whole area of this and the neighboring blocks
1361         */
1362         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
1363         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
1364                 v2s16 sectorpos(x, z);
1365                 // Sector metadata is loaded from disk if not already loaded.
1366                 MapSector *sector = createSector(sectorpos);
1367                 FATAL_ERROR_IF(sector == NULL, "createSector() failed");
1368
1369                 for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
1370                         v3s16 p(x, y, z);
1371
1372                         MapBlock *block = emergeBlock(p, false);
1373                         if (block == NULL) {
1374                                 block = createBlock(p);
1375
1376                                 // Block gets sunlight if this is true.
1377                                 // Refer to the map generator heuristics.
1378                                 bool ug = m_emerge->isBlockUnderground(p);
1379                                 block->setIsUnderground(ug);
1380                         }
1381                 }
1382         }
1383
1384         /*
1385                 Now we have a big empty area.
1386
1387                 Make a ManualMapVoxelManipulator that contains this and the
1388                 neighboring blocks
1389         */
1390
1391         data->vmanip = new MMVManip(this);
1392         data->vmanip->initialEmerge(full_bpmin, full_bpmax);
1393
1394         // Note: we may need this again at some point.
1395 #if 0
1396         // Ensure none of the blocks to be generated were marked as
1397         // containing CONTENT_IGNORE
1398         for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
1399                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
1400                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
1401                                 core::map<v3s16, u8>::Node *n;
1402                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
1403                                 if (n == NULL)
1404                                         continue;
1405                                 u8 flags = n->getValue();
1406                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
1407                                 n->setValue(flags);
1408                         }
1409                 }
1410         }
1411 #endif
1412
1413         // Data is ready now.
1414         return true;
1415 }
1416
1417 void ServerMap::finishBlockMake(BlockMakeData *data,
1418         std::map<v3s16, MapBlock*> *changed_blocks)
1419 {
1420         v3s16 bpmin = data->blockpos_min;
1421         v3s16 bpmax = data->blockpos_max;
1422
1423         v3s16 extra_borders(1, 1, 1);
1424
1425         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1426         EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
1427
1428         /*
1429                 Blit generated stuff to map
1430                 NOTE: blitBackAll adds nearly everything to changed_blocks
1431         */
1432         data->vmanip->blitBackAll(changed_blocks);
1433
1434         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
1435                 << changed_blocks->size());
1436
1437         /*
1438                 Copy transforming liquid information
1439         */
1440         while (data->transforming_liquid.size()) {
1441                 m_transforming_liquid.push_back(data->transforming_liquid.front());
1442                 data->transforming_liquid.pop_front();
1443         }
1444
1445         for (auto &changed_block : *changed_blocks) {
1446                 MapBlock *block = changed_block.second;
1447                 if (!block)
1448                         continue;
1449                 /*
1450                         Update day/night difference cache of the MapBlocks
1451                 */
1452                 block->expireDayNightDiff();
1453                 /*
1454                         Set block as modified
1455                 */
1456                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1457                         MOD_REASON_EXPIRE_DAYNIGHTDIFF);
1458         }
1459
1460         /*
1461                 Set central blocks as generated
1462         */
1463         for (s16 x = bpmin.X; x <= bpmax.X; x++)
1464         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
1465         for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
1466                 MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
1467                 if (!block)
1468                         continue;
1469
1470                 block->setGenerated(true);
1471         }
1472
1473         /*
1474                 Save changed parts of map
1475                 NOTE: Will be saved later.
1476         */
1477         //save(MOD_STATE_WRITE_AT_UNLOAD);
1478 }
1479
1480 MapSector *ServerMap::createSector(v2s16 p2d)
1481 {
1482         /*
1483                 Check if it exists already in memory
1484         */
1485         MapSector *sector = getSectorNoGenerate(p2d);
1486         if (sector)
1487                 return sector;
1488
1489         /*
1490                 Do not create over max mapgen limit
1491         */
1492         const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
1493         if (p2d.X < -max_limit_bp ||
1494                         p2d.X >  max_limit_bp ||
1495                         p2d.Y < -max_limit_bp ||
1496                         p2d.Y >  max_limit_bp)
1497                 throw InvalidPositionException("createSector(): pos. over max mapgen limit");
1498
1499         /*
1500                 Generate blank sector
1501         */
1502
1503         sector = new MapSector(this, p2d, m_gamedef);
1504
1505         // Sector position on map in nodes
1506         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
1507
1508         /*
1509                 Insert to container
1510         */
1511         m_sectors[p2d] = sector;
1512
1513         return sector;
1514 }
1515
1516 #if 0
1517 /*
1518         This is a quick-hand function for calling makeBlock().
1519 */
1520 MapBlock * ServerMap::generateBlock(
1521                 v3s16 p,
1522                 std::map<v3s16, MapBlock*> &modified_blocks
1523 )
1524 {
1525         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
1526
1527         TimeTaker timer("generateBlock");
1528
1529         //MapBlock *block = original_dummy;
1530
1531         v2s16 p2d(p.X, p.Z);
1532         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
1533
1534         /*
1535                 Do not generate over-limit
1536         */
1537         if(blockpos_over_limit(p))
1538         {
1539                 infostream<<FUNCTION_NAME<<": Block position over limit"<<std::endl;
1540                 throw InvalidPositionException("generateBlock(): pos. over limit");
1541         }
1542
1543         /*
1544                 Create block make data
1545         */
1546         BlockMakeData data;
1547         initBlockMake(&data, p);
1548
1549         /*
1550                 Generate block
1551         */
1552         {
1553                 TimeTaker t("mapgen::make_block()");
1554                 mapgen->makeChunk(&data);
1555                 //mapgen::make_block(&data);
1556
1557                 if(enable_mapgen_debug_info == false)
1558                         t.stop(true); // Hide output
1559         }
1560
1561         /*
1562                 Blit data back on map, update lighting, add mobs and whatever this does
1563         */
1564         finishBlockMake(&data, modified_blocks);
1565
1566         /*
1567                 Get central block
1568         */
1569         MapBlock *block = getBlockNoCreateNoEx(p);
1570
1571 #if 0
1572         /*
1573                 Check result
1574         */
1575         if(block)
1576         {
1577                 bool erroneus_content = false;
1578                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1579                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1580                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1581                 {
1582                         v3s16 p(x0,y0,z0);
1583                         MapNode n = block->getNode(p);
1584                         if(n.getContent() == CONTENT_IGNORE)
1585                         {
1586                                 infostream<<"CONTENT_IGNORE at "
1587                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1588                                                 <<std::endl;
1589                                 erroneus_content = true;
1590                                 assert(0);
1591                         }
1592                 }
1593                 if(erroneus_content)
1594                 {
1595                         assert(0);
1596                 }
1597         }
1598 #endif
1599
1600 #if 0
1601         /*
1602                 Generate a completely empty block
1603         */
1604         if(block)
1605         {
1606                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1607                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1608                 {
1609                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1610                         {
1611                                 MapNode n;
1612                                 n.setContent(CONTENT_AIR);
1613                                 block->setNode(v3s16(x0,y0,z0), n);
1614                         }
1615                 }
1616         }
1617 #endif
1618
1619         if(enable_mapgen_debug_info == false)
1620                 timer.stop(true); // Hide output
1621
1622         return block;
1623 }
1624 #endif
1625
1626 MapBlock * ServerMap::createBlock(v3s16 p)
1627 {
1628         /*
1629                 Do not create over max mapgen limit
1630         */
1631         if (blockpos_over_max_limit(p))
1632                 throw InvalidPositionException("createBlock(): pos. over max mapgen limit");
1633
1634         v2s16 p2d(p.X, p.Z);
1635         s16 block_y = p.Y;
1636         /*
1637                 This will create or load a sector if not found in memory.
1638                 If block exists on disk, it will be loaded.
1639
1640                 NOTE: On old save formats, this will be slow, as it generates
1641                       lighting on blocks for them.
1642         */
1643         MapSector *sector;
1644         try {
1645                 sector = createSector(p2d);
1646         } catch (InvalidPositionException &e) {
1647                 infostream<<"createBlock: createSector() failed"<<std::endl;
1648                 throw e;
1649         }
1650
1651         /*
1652                 Try to get a block from the sector
1653         */
1654
1655         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
1656         if (block) {
1657                 if(block->isDummy())
1658                         block->unDummify();
1659                 return block;
1660         }
1661         // Create blank
1662         block = sector->createBlankBlock(block_y);
1663
1664         return block;
1665 }
1666
1667 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
1668 {
1669         {
1670                 MapBlock *block = getBlockNoCreateNoEx(p);
1671                 if (block && !block->isDummy())
1672                         return block;
1673         }
1674
1675         {
1676                 MapBlock *block = loadBlock(p);
1677                 if(block)
1678                         return block;
1679         }
1680
1681         if (create_blank) {
1682                 MapSector *sector = createSector(v2s16(p.X, p.Z));
1683                 MapBlock *block = sector->createBlankBlock(p.Y);
1684
1685                 return block;
1686         }
1687
1688         return NULL;
1689 }
1690
1691 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
1692 {
1693         MapBlock *block = getBlockNoCreateNoEx(p3d);
1694         if (block == NULL)
1695                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
1696
1697         return block;
1698 }
1699
1700 // N.B.  This requires no synchronization, since data will not be modified unless
1701 // the VoxelManipulator being updated belongs to the same thread.
1702 void ServerMap::updateVManip(v3s16 pos)
1703 {
1704         Mapgen *mg = m_emerge->getCurrentMapgen();
1705         if (!mg)
1706                 return;
1707
1708         MMVManip *vm = mg->vm;
1709         if (!vm)
1710                 return;
1711
1712         if (!vm->m_area.contains(pos))
1713                 return;
1714
1715         s32 idx = vm->m_area.index(pos);
1716         vm->m_data[idx] = getNode(pos);
1717         vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
1718
1719         vm->m_is_dirty = true;
1720 }
1721
1722 s16 ServerMap::findGroundLevel(v2s16 p2d)
1723 {
1724 #if 0
1725         /*
1726                 Uh, just do something random...
1727         */
1728         // Find existing map from top to down
1729         s16 max=63;
1730         s16 min=-64;
1731         v3s16 p(p2d.X, max, p2d.Y);
1732         for(; p.Y>min; p.Y--)
1733         {
1734                 MapNode n = getNodeNoEx(p);
1735                 if(n.getContent() != CONTENT_IGNORE)
1736                         break;
1737         }
1738         if(p.Y == min)
1739                 goto plan_b;
1740         // If this node is not air, go to plan b
1741         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
1742                 goto plan_b;
1743         // Search existing walkable and return it
1744         for(; p.Y>min; p.Y--)
1745         {
1746                 MapNode n = getNodeNoEx(p);
1747                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
1748                         return p.Y;
1749         }
1750
1751         // Move to plan b
1752 plan_b:
1753 #endif
1754
1755         /*
1756                 Determine from map generator noise functions
1757         */
1758
1759         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
1760         return level;
1761
1762         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
1763         //return (s16)level;
1764 }
1765
1766 void ServerMap::createDirs(const std::string &path)
1767 {
1768         if (!fs::CreateAllDirs(path)) {
1769                 m_dout<<"ServerMap: Failed to create directory "
1770                                 <<"\""<<path<<"\""<<std::endl;
1771                 throw BaseException("ServerMap failed to create directory");
1772         }
1773 }
1774
1775 void ServerMap::save(ModifiedState save_level)
1776 {
1777         if (!m_map_saving_enabled) {
1778                 warningstream<<"Not saving map, saving disabled."<<std::endl;
1779                 return;
1780         }
1781
1782         u64 start_time = porting::getTimeNs();
1783
1784         if(save_level == MOD_STATE_CLEAN)
1785                 infostream<<"ServerMap: Saving whole map, this can take time."
1786                                 <<std::endl;
1787
1788         if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
1789                 if (settings_mgr.saveMapMeta())
1790                         m_map_metadata_changed = false;
1791         }
1792
1793         // Profile modified reasons
1794         Profiler modprofiler;
1795
1796         u32 block_count = 0;
1797         u32 block_count_all = 0; // Number of blocks in memory
1798
1799         // Don't do anything with sqlite unless something is really saved
1800         bool save_started = false;
1801
1802         for (auto &sector_it : m_sectors) {
1803                 MapSector *sector = sector_it.second;
1804
1805                 MapBlockVect blocks;
1806                 sector->getBlocks(blocks);
1807
1808                 for (MapBlock *block : blocks) {
1809                         block_count_all++;
1810
1811                         if(block->getModified() >= (u32)save_level) {
1812                                 // Lazy beginSave()
1813                                 if(!save_started) {
1814                                         beginSave();
1815                                         save_started = true;
1816                                 }
1817
1818                                 modprofiler.add(block->getModifiedReasonString(), 1);
1819
1820                                 saveBlock(block);
1821                                 block_count++;
1822                         }
1823                 }
1824         }
1825
1826         if(save_started)
1827                 endSave();
1828
1829         /*
1830                 Only print if something happened or saved whole map
1831         */
1832         if(save_level == MOD_STATE_CLEAN
1833                         || block_count != 0) {
1834                 infostream << "ServerMap: Written: "
1835                                 << block_count << " blocks"
1836                                 << ", " << block_count_all << " blocks in memory."
1837                                 << std::endl;
1838                 PrintInfo(infostream); // ServerMap/ClientMap:
1839                 infostream<<"Blocks modified by: "<<std::endl;
1840                 modprofiler.print(infostream);
1841         }
1842
1843         auto end_time = porting::getTimeNs();
1844         m_save_time_counter->increment(end_time - start_time);
1845 }
1846
1847 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
1848 {
1849         dbase->listAllLoadableBlocks(dst);
1850         if (dbase_ro)
1851                 dbase_ro->listAllLoadableBlocks(dst);
1852 }
1853
1854 void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
1855 {
1856         for (auto &sector_it : m_sectors) {
1857                 MapSector *sector = sector_it.second;
1858
1859                 MapBlockVect blocks;
1860                 sector->getBlocks(blocks);
1861
1862                 for (MapBlock *block : blocks) {
1863                         v3s16 p = block->getPos();
1864                         dst.push_back(p);
1865                 }
1866         }
1867 }
1868
1869 MapDatabase *ServerMap::createDatabase(
1870         const std::string &name,
1871         const std::string &savedir,
1872         Settings &conf)
1873 {
1874         if (name == "sqlite3")
1875                 return new MapDatabaseSQLite3(savedir);
1876         if (name == "dummy")
1877                 return new Database_Dummy();
1878         #if USE_LEVELDB
1879         if (name == "leveldb")
1880                 return new Database_LevelDB(savedir);
1881         #endif
1882         #if USE_REDIS
1883         if (name == "redis")
1884                 return new Database_Redis(conf);
1885         #endif
1886         #if USE_POSTGRESQL
1887         if (name == "postgresql") {
1888                 std::string connect_string;
1889                 conf.getNoEx("pgsql_connection", connect_string);
1890                 return new MapDatabasePostgreSQL(connect_string);
1891         }
1892         #endif
1893
1894         throw BaseException(std::string("Database backend ") + name + " not supported.");
1895 }
1896
1897 void ServerMap::pingDatabase()
1898 {
1899         dbase->pingDatabase();
1900 }
1901
1902 void ServerMap::beginSave()
1903 {
1904         dbase->beginSave();
1905 }
1906
1907 void ServerMap::endSave()
1908 {
1909         dbase->endSave();
1910 }
1911
1912 bool ServerMap::saveBlock(MapBlock *block)
1913 {
1914         return saveBlock(block, dbase);
1915 }
1916
1917 bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db)
1918 {
1919         v3s16 p3d = block->getPos();
1920
1921         // Dummy blocks are not written
1922         if (block->isDummy()) {
1923                 warningstream << "saveBlock: Not writing dummy block "
1924                         << PP(p3d) << std::endl;
1925                 return true;
1926         }
1927
1928         // Format used for writing
1929         u8 version = SER_FMT_VER_HIGHEST_WRITE;
1930
1931         /*
1932                 [0] u8 serialization version
1933                 [1] data
1934         */
1935         std::ostringstream o(std::ios_base::binary);
1936         o.write((char*) &version, 1);
1937         block->serialize(o, version, true);
1938
1939         bool ret = db->saveBlock(p3d, o.str());
1940         if (ret) {
1941                 // We just wrote it to the disk so clear modified flag
1942                 block->resetModified();
1943         }
1944         return ret;
1945 }
1946
1947 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
1948 {
1949         try {
1950                 std::istringstream is(*blob, std::ios_base::binary);
1951
1952                 u8 version = SER_FMT_VER_INVALID;
1953                 is.read((char*)&version, 1);
1954
1955                 if(is.fail())
1956                         throw SerializationError("ServerMap::loadBlock(): Failed"
1957                                         " to read MapBlock version");
1958
1959                 MapBlock *block = NULL;
1960                 bool created_new = false;
1961                 block = sector->getBlockNoCreateNoEx(p3d.Y);
1962                 if(block == NULL)
1963                 {
1964                         block = sector->createBlankBlockNoInsert(p3d.Y);
1965                         created_new = true;
1966                 }
1967
1968                 // Read basic data
1969                 block->deSerialize(is, version, true);
1970
1971                 // If it's a new block, insert it to the map
1972                 if (created_new) {
1973                         sector->insertBlock(block);
1974                         ReflowScan scanner(this, m_emerge->ndef);
1975                         scanner.scan(block, &m_transforming_liquid);
1976                 }
1977
1978                 /*
1979                         Save blocks loaded in old format in new format
1980                 */
1981
1982                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
1983                 // Only save if asked to; no need to update version
1984                 if(save_after_load)
1985                         saveBlock(block);
1986
1987                 // We just loaded it from, so it's up-to-date.
1988                 block->resetModified();
1989         }
1990         catch(SerializationError &e)
1991         {
1992                 errorstream<<"Invalid block data in database"
1993                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
1994                                 <<" (SerializationError): "<<e.what()<<std::endl;
1995
1996                 // TODO: Block should be marked as invalid in memory so that it is
1997                 // not touched but the game can run
1998
1999                 if(g_settings->getBool("ignore_world_load_errors")){
2000                         errorstream<<"Ignoring block load error. Duck and cover! "
2001                                         <<"(ignore_world_load_errors)"<<std::endl;
2002                 } else {
2003                         throw SerializationError("Invalid block data in database");
2004                 }
2005         }
2006 }
2007
2008 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
2009 {
2010         bool created_new = (getBlockNoCreateNoEx(blockpos) == NULL);
2011
2012         v2s16 p2d(blockpos.X, blockpos.Z);
2013
2014         std::string ret;
2015         dbase->loadBlock(blockpos, &ret);
2016         if (!ret.empty()) {
2017                 loadBlock(&ret, blockpos, createSector(p2d), false);
2018         } else if (dbase_ro) {
2019                 dbase_ro->loadBlock(blockpos, &ret);
2020                 if (!ret.empty()) {
2021                         loadBlock(&ret, blockpos, createSector(p2d), false);
2022                 }
2023         } else {
2024                 return NULL;
2025         }
2026
2027         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2028         if (created_new && (block != NULL)) {
2029                 std::map<v3s16, MapBlock*> modified_blocks;
2030                 // Fix lighting if necessary
2031                 voxalgo::update_block_border_lighting(this, block, modified_blocks);
2032                 if (!modified_blocks.empty()) {
2033                         //Modified lighting, send event
2034                         MapEditEvent event;
2035                         event.type = MEET_OTHER;
2036                         std::map<v3s16, MapBlock *>::iterator it;
2037                         for (it = modified_blocks.begin();
2038                                         it != modified_blocks.end(); ++it)
2039                                 event.modified_blocks.insert(it->first);
2040                         dispatchEvent(event);
2041                 }
2042         }
2043         return block;
2044 }
2045
2046 bool ServerMap::deleteBlock(v3s16 blockpos)
2047 {
2048         if (!dbase->deleteBlock(blockpos))
2049                 return false;
2050
2051         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2052         if (block) {
2053                 v2s16 p2d(blockpos.X, blockpos.Z);
2054                 MapSector *sector = getSectorNoGenerate(p2d);
2055                 if (!sector)
2056                         return false;
2057                 sector->deleteBlock(block);
2058         }
2059
2060         return true;
2061 }
2062
2063 void ServerMap::PrintInfo(std::ostream &out)
2064 {
2065         out<<"ServerMap: ";
2066 }
2067
2068 bool ServerMap::repairBlockLight(v3s16 blockpos,
2069         std::map<v3s16, MapBlock *> *modified_blocks)
2070 {
2071         MapBlock *block = emergeBlock(blockpos, false);
2072         if (!block || !block->isGenerated())
2073                 return false;
2074         voxalgo::repair_block_light(this, block, modified_blocks);
2075         return true;
2076 }
2077
2078 MMVManip::MMVManip(Map *map):
2079                 VoxelManipulator(),
2080                 m_map(map)
2081 {
2082 }
2083
2084 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
2085         bool load_if_inexistent)
2086 {
2087         TimeTaker timer1("initialEmerge", &emerge_time);
2088
2089         // Units of these are MapBlocks
2090         v3s16 p_min = blockpos_min;
2091         v3s16 p_max = blockpos_max;
2092
2093         VoxelArea block_area_nodes
2094                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
2095
2096         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
2097         if(size_MB >= 1)
2098         {
2099                 infostream<<"initialEmerge: area: ";
2100                 block_area_nodes.print(infostream);
2101                 infostream<<" ("<<size_MB<<"MB)";
2102                 infostream<<std::endl;
2103         }
2104
2105         addArea(block_area_nodes);
2106
2107         for(s32 z=p_min.Z; z<=p_max.Z; z++)
2108         for(s32 y=p_min.Y; y<=p_max.Y; y++)
2109         for(s32 x=p_min.X; x<=p_max.X; x++)
2110         {
2111                 u8 flags = 0;
2112                 MapBlock *block;
2113                 v3s16 p(x,y,z);
2114                 std::map<v3s16, u8>::iterator n;
2115                 n = m_loaded_blocks.find(p);
2116                 if(n != m_loaded_blocks.end())
2117                         continue;
2118
2119                 bool block_data_inexistent = false;
2120                 {
2121                         TimeTaker timer2("emerge load", &emerge_load_time);
2122
2123                         block = m_map->getBlockNoCreateNoEx(p);
2124                         if (!block || block->isDummy())
2125                                 block_data_inexistent = true;
2126                         else
2127                                 block->copyTo(*this);
2128                 }
2129
2130                 if(block_data_inexistent)
2131                 {
2132
2133                         if (load_if_inexistent && !blockpos_over_max_limit(p)) {
2134                                 ServerMap *svrmap = (ServerMap *)m_map;
2135                                 block = svrmap->emergeBlock(p, false);
2136                                 if (block == NULL)
2137                                         block = svrmap->createBlock(p);
2138                                 block->copyTo(*this);
2139                         } else {
2140                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
2141
2142                                 /*
2143                                         Mark area inexistent
2144                                 */
2145                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
2146                                 // Fill with VOXELFLAG_NO_DATA
2147                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
2148                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
2149                                 {
2150                                         s32 i = m_area.index(a.MinEdge.X,y,z);
2151                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
2152                                 }
2153                         }
2154                 }
2155                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
2156                 {
2157                         // Mark that block was loaded as blank
2158                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
2159                 }*/
2160
2161                 m_loaded_blocks[p] = flags;
2162         }
2163
2164         m_is_dirty = false;
2165 }
2166
2167 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
2168         bool overwrite_generated)
2169 {
2170         if(m_area.getExtent() == v3s16(0,0,0))
2171                 return;
2172
2173         /*
2174                 Copy data of all blocks
2175         */
2176         for (auto &loaded_block : m_loaded_blocks) {
2177                 v3s16 p = loaded_block.first;
2178                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
2179                 bool existed = !(loaded_block.second & VMANIP_BLOCK_DATA_INEXIST);
2180                 if (!existed || (block == NULL) ||
2181                         (!overwrite_generated && block->isGenerated()))
2182                         continue;
2183
2184                 block->copyFrom(*this);
2185                 block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_VMANIP);
2186
2187                 if(modified_blocks)
2188                         (*modified_blocks)[p] = block;
2189         }
2190 }
2191
2192 //END