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