]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
Improve undersampling settings
[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(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 fucks up stuff
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 bit 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 bool ServerMap::loadFromFolders() {
1766         if (!dbase->initialized() &&
1767                         !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
1768                 return true;
1769         return false;
1770 }
1771
1772 void ServerMap::createDirs(const std::string &path)
1773 {
1774         if (!fs::CreateAllDirs(path)) {
1775                 m_dout<<"ServerMap: Failed to create directory "
1776                                 <<"\""<<path<<"\""<<std::endl;
1777                 throw BaseException("ServerMap failed to create directory");
1778         }
1779 }
1780
1781 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
1782 {
1783         char cc[9];
1784         switch(layout)
1785         {
1786                 case 1:
1787                         porting::mt_snprintf(cc, sizeof(cc), "%.4x%.4x",
1788                                 (unsigned int) pos.X & 0xffff,
1789                                 (unsigned int) pos.Y & 0xffff);
1790
1791                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
1792                 case 2:
1793                         porting::mt_snprintf(cc, sizeof(cc), (std::string("%.3x") + DIR_DELIM + "%.3x").c_str(),
1794                                 (unsigned int) pos.X & 0xfff,
1795                                 (unsigned int) pos.Y & 0xfff);
1796
1797                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
1798                 default:
1799                         assert(false);
1800                         return "";
1801         }
1802 }
1803
1804 v2s16 ServerMap::getSectorPos(const std::string &dirname)
1805 {
1806         unsigned int x = 0, y = 0;
1807         int r;
1808         std::string component;
1809         fs::RemoveLastPathComponent(dirname, &component, 1);
1810         if(component.size() == 8)
1811         {
1812                 // Old layout
1813                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
1814         }
1815         else if(component.size() == 3)
1816         {
1817                 // New layout
1818                 fs::RemoveLastPathComponent(dirname, &component, 2);
1819                 r = sscanf(component.c_str(), (std::string("%3x") + DIR_DELIM + "%3x").c_str(), &x, &y);
1820                 // Sign-extend the 12 bit values up to 16 bits...
1821                 if(x & 0x800) x |= 0xF000;
1822                 if(y & 0x800) y |= 0xF000;
1823         }
1824         else
1825         {
1826                 r = -1;
1827         }
1828
1829         FATAL_ERROR_IF(r != 2, "getSectorPos()");
1830         v2s16 pos((s16)x, (s16)y);
1831         return pos;
1832 }
1833
1834 v3s16 ServerMap::getBlockPos(const std::string &sectordir, const std::string &blockfile)
1835 {
1836         v2s16 p2d = getSectorPos(sectordir);
1837
1838         if(blockfile.size() != 4){
1839                 throw InvalidFilenameException("Invalid block filename");
1840         }
1841         unsigned int y;
1842         int r = sscanf(blockfile.c_str(), "%4x", &y);
1843         if(r != 1)
1844                 throw InvalidFilenameException("Invalid block filename");
1845         return v3s16(p2d.X, y, p2d.Y);
1846 }
1847
1848 std::string ServerMap::getBlockFilename(v3s16 p)
1849 {
1850         char cc[5];
1851         porting::mt_snprintf(cc, sizeof(cc), "%.4x", (unsigned int)p.Y&0xffff);
1852         return cc;
1853 }
1854
1855 void ServerMap::save(ModifiedState save_level)
1856 {
1857         if (!m_map_saving_enabled) {
1858                 warningstream<<"Not saving map, saving disabled."<<std::endl;
1859                 return;
1860         }
1861
1862         if(save_level == MOD_STATE_CLEAN)
1863                 infostream<<"ServerMap: Saving whole map, this can take time."
1864                                 <<std::endl;
1865
1866         if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
1867                 if (settings_mgr.saveMapMeta())
1868                         m_map_metadata_changed = false;
1869         }
1870
1871         // Profile modified reasons
1872         Profiler modprofiler;
1873
1874         u32 block_count = 0;
1875         u32 block_count_all = 0; // Number of blocks in memory
1876
1877         // Don't do anything with sqlite unless something is really saved
1878         bool save_started = false;
1879
1880         for (auto &sector_it : m_sectors) {
1881                 MapSector *sector = sector_it.second;
1882
1883                 MapBlockVect blocks;
1884                 sector->getBlocks(blocks);
1885
1886                 for (MapBlock *block : blocks) {
1887                         block_count_all++;
1888
1889                         if(block->getModified() >= (u32)save_level) {
1890                                 // Lazy beginSave()
1891                                 if(!save_started) {
1892                                         beginSave();
1893                                         save_started = true;
1894                                 }
1895
1896                                 modprofiler.add(block->getModifiedReasonString(), 1);
1897
1898                                 saveBlock(block);
1899                                 block_count++;
1900                         }
1901                 }
1902         }
1903
1904         if(save_started)
1905                 endSave();
1906
1907         /*
1908                 Only print if something happened or saved whole map
1909         */
1910         if(save_level == MOD_STATE_CLEAN
1911                         || block_count != 0) {
1912                 infostream<<"ServerMap: Written: "
1913                                 <<block_count<<" block files"
1914                                 <<", "<<block_count_all<<" blocks in memory."
1915                                 <<std::endl;
1916                 PrintInfo(infostream); // ServerMap/ClientMap:
1917                 infostream<<"Blocks modified by: "<<std::endl;
1918                 modprofiler.print(infostream);
1919         }
1920 }
1921
1922 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
1923 {
1924         if (loadFromFolders()) {
1925                 errorstream << "Map::listAllLoadableBlocks(): Result will be missing "
1926                                 << "all blocks that are stored in flat files." << std::endl;
1927         }
1928         dbase->listAllLoadableBlocks(dst);
1929         if (dbase_ro)
1930                 dbase_ro->listAllLoadableBlocks(dst);
1931 }
1932
1933 void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
1934 {
1935         for (auto &sector_it : m_sectors) {
1936                 MapSector *sector = sector_it.second;
1937
1938                 MapBlockVect blocks;
1939                 sector->getBlocks(blocks);
1940
1941                 for (MapBlock *block : blocks) {
1942                         v3s16 p = block->getPos();
1943                         dst.push_back(p);
1944                 }
1945         }
1946 }
1947
1948 MapDatabase *ServerMap::createDatabase(
1949         const std::string &name,
1950         const std::string &savedir,
1951         Settings &conf)
1952 {
1953         if (name == "sqlite3")
1954                 return new MapDatabaseSQLite3(savedir);
1955         if (name == "dummy")
1956                 return new Database_Dummy();
1957         #if USE_LEVELDB
1958         if (name == "leveldb")
1959                 return new Database_LevelDB(savedir);
1960         #endif
1961         #if USE_REDIS
1962         if (name == "redis")
1963                 return new Database_Redis(conf);
1964         #endif
1965         #if USE_POSTGRESQL
1966         if (name == "postgresql") {
1967                 std::string connect_string;
1968                 conf.getNoEx("pgsql_connection", connect_string);
1969                 return new MapDatabasePostgreSQL(connect_string);
1970         }
1971         #endif
1972
1973         throw BaseException(std::string("Database backend ") + name + " not supported.");
1974 }
1975
1976 void ServerMap::beginSave()
1977 {
1978         dbase->beginSave();
1979 }
1980
1981 void ServerMap::endSave()
1982 {
1983         dbase->endSave();
1984 }
1985
1986 bool ServerMap::saveBlock(MapBlock *block)
1987 {
1988         return saveBlock(block, dbase);
1989 }
1990
1991 bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db)
1992 {
1993         v3s16 p3d = block->getPos();
1994
1995         // Dummy blocks are not written
1996         if (block->isDummy()) {
1997                 warningstream << "saveBlock: Not writing dummy block "
1998                         << PP(p3d) << std::endl;
1999                 return true;
2000         }
2001
2002         // Format used for writing
2003         u8 version = SER_FMT_VER_HIGHEST_WRITE;
2004
2005         /*
2006                 [0] u8 serialization version
2007                 [1] data
2008         */
2009         std::ostringstream o(std::ios_base::binary);
2010         o.write((char*) &version, 1);
2011         block->serialize(o, version, true);
2012
2013         bool ret = db->saveBlock(p3d, o.str());
2014         if (ret) {
2015                 // We just wrote it to the disk so clear modified flag
2016                 block->resetModified();
2017         }
2018         return ret;
2019 }
2020
2021 void ServerMap::loadBlock(const std::string &sectordir, const std::string &blockfile,
2022                 MapSector *sector, bool save_after_load)
2023 {
2024         std::string fullpath = sectordir + DIR_DELIM + blockfile;
2025         try {
2026                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2027                 if (!is.good())
2028                         throw FileNotGoodException("Cannot open block file");
2029
2030                 v3s16 p3d = getBlockPos(sectordir, blockfile);
2031                 v2s16 p2d(p3d.X, p3d.Z);
2032
2033                 assert(sector->getPos() == p2d);
2034
2035                 u8 version = SER_FMT_VER_INVALID;
2036                 is.read((char*)&version, 1);
2037
2038                 if(is.fail())
2039                         throw SerializationError("ServerMap::loadBlock(): Failed"
2040                                         " to read MapBlock version");
2041
2042                 /*u32 block_size = MapBlock::serializedLength(version);
2043                 SharedBuffer<u8> data(block_size);
2044                 is.read((char*)*data, block_size);*/
2045
2046                 // This will always return a sector because we're the server
2047                 //MapSector *sector = emergeSector(p2d);
2048
2049                 MapBlock *block = NULL;
2050                 bool created_new = false;
2051                 block = sector->getBlockNoCreateNoEx(p3d.Y);
2052                 if(block == NULL)
2053                 {
2054                         block = sector->createBlankBlockNoInsert(p3d.Y);
2055                         created_new = true;
2056                 }
2057
2058                 // Read basic data
2059                 block->deSerialize(is, version, true);
2060
2061                 // If it's a new block, insert it to the map
2062                 if (created_new) {
2063                         sector->insertBlock(block);
2064                         ReflowScan scanner(this, m_emerge->ndef);
2065                         scanner.scan(block, &m_transforming_liquid);
2066                 }
2067
2068                 /*
2069                         Save blocks loaded in old format in new format
2070                 */
2071
2072                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
2073                 {
2074                         saveBlock(block);
2075
2076                         // Should be in database now, so delete the old file
2077                         fs::RecursiveDelete(fullpath);
2078                 }
2079
2080                 // We just loaded it from the disk, so it's up-to-date.
2081                 block->resetModified();
2082
2083         }
2084         catch(SerializationError &e)
2085         {
2086                 warningstream<<"Invalid block data on disk "
2087                                 <<"fullpath="<<fullpath
2088                                 <<" (SerializationError). "
2089                                 <<"what()="<<e.what()
2090                                 <<std::endl;
2091                                 // Ignoring. A new one will be generated.
2092                 abort();
2093
2094                 // TODO: Backup file; name is in fullpath.
2095         }
2096 }
2097
2098 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
2099 {
2100         try {
2101                 std::istringstream is(*blob, std::ios_base::binary);
2102
2103                 u8 version = SER_FMT_VER_INVALID;
2104                 is.read((char*)&version, 1);
2105
2106                 if(is.fail())
2107                         throw SerializationError("ServerMap::loadBlock(): Failed"
2108                                         " to read MapBlock version");
2109
2110                 MapBlock *block = NULL;
2111                 bool created_new = false;
2112                 block = sector->getBlockNoCreateNoEx(p3d.Y);
2113                 if(block == NULL)
2114                 {
2115                         block = sector->createBlankBlockNoInsert(p3d.Y);
2116                         created_new = true;
2117                 }
2118
2119                 // Read basic data
2120                 block->deSerialize(is, version, true);
2121
2122                 // If it's a new block, insert it to the map
2123                 if (created_new) {
2124                         sector->insertBlock(block);
2125                         ReflowScan scanner(this, m_emerge->ndef);
2126                         scanner.scan(block, &m_transforming_liquid);
2127                 }
2128
2129                 /*
2130                         Save blocks loaded in old format in new format
2131                 */
2132
2133                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
2134                 // Only save if asked to; no need to update version
2135                 if(save_after_load)
2136                         saveBlock(block);
2137
2138                 // We just loaded it from, so it's up-to-date.
2139                 block->resetModified();
2140         }
2141         catch(SerializationError &e)
2142         {
2143                 errorstream<<"Invalid block data in database"
2144                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
2145                                 <<" (SerializationError): "<<e.what()<<std::endl;
2146
2147                 // TODO: Block should be marked as invalid in memory so that it is
2148                 // not touched but the game can run
2149
2150                 if(g_settings->getBool("ignore_world_load_errors")){
2151                         errorstream<<"Ignoring block load error. Duck and cover! "
2152                                         <<"(ignore_world_load_errors)"<<std::endl;
2153                 } else {
2154                         throw SerializationError("Invalid block data in database");
2155                 }
2156         }
2157 }
2158
2159 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
2160 {
2161         bool created_new = (getBlockNoCreateNoEx(blockpos) == NULL);
2162
2163         v2s16 p2d(blockpos.X, blockpos.Z);
2164
2165         std::string ret;
2166         dbase->loadBlock(blockpos, &ret);
2167         if (!ret.empty()) {
2168                 loadBlock(&ret, blockpos, createSector(p2d), false);
2169         } else if (dbase_ro) {
2170                 dbase_ro->loadBlock(blockpos, &ret);
2171                 if (!ret.empty()) {
2172                         loadBlock(&ret, blockpos, createSector(p2d), false);
2173                 }
2174         } else {
2175                 // Not found in database, try the files
2176
2177                 // The directory layout we're going to load from.
2178                 //  1 - original sectors/xxxxzzzz/
2179                 //  2 - new sectors2/xxx/zzz/
2180                 //  If we load from anything but the latest structure, we will
2181                 //  immediately save to the new one, and remove the old.
2182                 std::string sectordir1 = getSectorDir(p2d, 1);
2183                 std::string sectordir;
2184                 if (fs::PathExists(sectordir1)) {
2185                         sectordir = sectordir1;
2186                 } else {
2187                         sectordir = getSectorDir(p2d, 2);
2188                 }
2189
2190                 /*
2191                 Make sure sector is loaded
2192                  */
2193
2194                 MapSector *sector = getSectorNoGenerate(p2d);
2195
2196                 /*
2197                 Make sure file exists
2198                  */
2199
2200                 std::string blockfilename = getBlockFilename(blockpos);
2201                 if (!fs::PathExists(sectordir + DIR_DELIM + blockfilename))
2202                         return NULL;
2203
2204                 /*
2205                 Load block and save it to the database
2206                  */
2207                 loadBlock(sectordir, blockfilename, sector, true);
2208         }
2209
2210         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2211         if (created_new && (block != NULL)) {
2212                 std::map<v3s16, MapBlock*> modified_blocks;
2213                 // Fix lighting if necessary
2214                 voxalgo::update_block_border_lighting(this, block, modified_blocks);
2215                 if (!modified_blocks.empty()) {
2216                         //Modified lighting, send event
2217                         MapEditEvent event;
2218                         event.type = MEET_OTHER;
2219                         std::map<v3s16, MapBlock *>::iterator it;
2220                         for (it = modified_blocks.begin();
2221                                         it != modified_blocks.end(); ++it)
2222                                 event.modified_blocks.insert(it->first);
2223                         dispatchEvent(&event);
2224                 }
2225         }
2226         return block;
2227 }
2228
2229 bool ServerMap::deleteBlock(v3s16 blockpos)
2230 {
2231         if (!dbase->deleteBlock(blockpos))
2232                 return false;
2233
2234         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2235         if (block) {
2236                 v2s16 p2d(blockpos.X, blockpos.Z);
2237                 MapSector *sector = getSectorNoGenerate(p2d);
2238                 if (!sector)
2239                         return false;
2240                 sector->deleteBlock(block);
2241         }
2242
2243         return true;
2244 }
2245
2246 void ServerMap::PrintInfo(std::ostream &out)
2247 {
2248         out<<"ServerMap: ";
2249 }
2250
2251 bool ServerMap::repairBlockLight(v3s16 blockpos,
2252         std::map<v3s16, MapBlock *> *modified_blocks)
2253 {
2254         MapBlock *block = emergeBlock(blockpos, false);
2255         if (!block || !block->isGenerated())
2256                 return false;
2257         voxalgo::repair_block_light(this, block, modified_blocks);
2258         return true;
2259 }
2260
2261 MMVManip::MMVManip(Map *map):
2262                 VoxelManipulator(),
2263                 m_map(map)
2264 {
2265 }
2266
2267 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
2268         bool load_if_inexistent)
2269 {
2270         TimeTaker timer1("initialEmerge", &emerge_time);
2271
2272         // Units of these are MapBlocks
2273         v3s16 p_min = blockpos_min;
2274         v3s16 p_max = blockpos_max;
2275
2276         VoxelArea block_area_nodes
2277                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
2278
2279         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
2280         if(size_MB >= 1)
2281         {
2282                 infostream<<"initialEmerge: area: ";
2283                 block_area_nodes.print(infostream);
2284                 infostream<<" ("<<size_MB<<"MB)";
2285                 infostream<<std::endl;
2286         }
2287
2288         addArea(block_area_nodes);
2289
2290         for(s32 z=p_min.Z; z<=p_max.Z; z++)
2291         for(s32 y=p_min.Y; y<=p_max.Y; y++)
2292         for(s32 x=p_min.X; x<=p_max.X; x++)
2293         {
2294                 u8 flags = 0;
2295                 MapBlock *block;
2296                 v3s16 p(x,y,z);
2297                 std::map<v3s16, u8>::iterator n;
2298                 n = m_loaded_blocks.find(p);
2299                 if(n != m_loaded_blocks.end())
2300                         continue;
2301
2302                 bool block_data_inexistent = false;
2303                 {
2304                         TimeTaker timer2("emerge load", &emerge_load_time);
2305
2306                         block = m_map->getBlockNoCreateNoEx(p);
2307                         if (!block || block->isDummy())
2308                                 block_data_inexistent = true;
2309                         else
2310                                 block->copyTo(*this);
2311                 }
2312
2313                 if(block_data_inexistent)
2314                 {
2315
2316                         if (load_if_inexistent && !blockpos_over_max_limit(p)) {
2317                                 ServerMap *svrmap = (ServerMap *)m_map;
2318                                 block = svrmap->emergeBlock(p, false);
2319                                 if (block == NULL)
2320                                         block = svrmap->createBlock(p);
2321                                 block->copyTo(*this);
2322                         } else {
2323                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
2324
2325                                 /*
2326                                         Mark area inexistent
2327                                 */
2328                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
2329                                 // Fill with VOXELFLAG_NO_DATA
2330                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
2331                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
2332                                 {
2333                                         s32 i = m_area.index(a.MinEdge.X,y,z);
2334                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
2335                                 }
2336                         }
2337                 }
2338                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
2339                 {
2340                         // Mark that block was loaded as blank
2341                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
2342                 }*/
2343
2344                 m_loaded_blocks[p] = flags;
2345         }
2346
2347         m_is_dirty = false;
2348 }
2349
2350 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
2351         bool overwrite_generated)
2352 {
2353         if(m_area.getExtent() == v3s16(0,0,0))
2354                 return;
2355
2356         /*
2357                 Copy data of all blocks
2358         */
2359         for (auto &loaded_block : m_loaded_blocks) {
2360                 v3s16 p = loaded_block.first;
2361                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
2362                 bool existed = !(loaded_block.second & VMANIP_BLOCK_DATA_INEXIST);
2363                 if (!existed || (block == NULL) ||
2364                         (!overwrite_generated && block->isGenerated()))
2365                         continue;
2366
2367                 block->copyFrom(*this);
2368                 block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_VMANIP);
2369
2370                 if(modified_blocks)
2371                         (*modified_blocks)[p] = block;
2372         }
2373 }
2374
2375 //END