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