Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenu
[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 "main.h"
24 #include "filesys.h"
25 #include "voxel.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 "rollback_interface.h"
37 #include "environment.h"
38 #include "emerge.h"
39 #include "mapgen_v6.h"
40 #include "biome.h"
41
42 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
43
44 /*
45         SQLite format specification:
46         - Initially only replaces sectors/ and sectors2/
47
48         If map.sqlite does not exist in the save dir
49         or the block was not found in the database
50         the map will try to load from sectors folder.
51         In either case, map.sqlite will be created
52         and all future saves will save there.
53
54         Structure of map.sqlite:
55         Tables:
56                 blocks
57                         (PK) INT pos
58                         BLOB data
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 {
70         /*m_sector_mutex.Init();
71         assert(m_sector_mutex.IsInitialized());*/
72 }
73
74 Map::~Map()
75 {
76         /*
77                 Free all MapSectors
78         */
79         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
80                 i != m_sectors.end(); ++i)
81         {
82                 delete i->second;
83         }
84 }
85
86 void Map::addEventReceiver(MapEventReceiver *event_receiver)
87 {
88         m_event_receivers.insert(event_receiver);
89 }
90
91 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
92 {
93         m_event_receivers.erase(event_receiver);
94 }
95
96 void Map::dispatchEvent(MapEditEvent *event)
97 {
98         for(std::set<MapEventReceiver*>::iterator
99                         i = m_event_receivers.begin();
100                         i != m_event_receivers.end(); ++i)
101         {
102                 (*i)->onMapEditEvent(event);
103         }
104 }
105
106 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
107 {
108         if(m_sector_cache != NULL && p == m_sector_cache_p){
109                 MapSector * sector = m_sector_cache;
110                 return sector;
111         }
112
113         std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
114
115         if(n == m_sectors.end())
116                 return NULL;
117
118         MapSector *sector = n->second;
119
120         // Cache the last result
121         m_sector_cache_p = p;
122         m_sector_cache = sector;
123
124         return sector;
125 }
126
127 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
128 {
129         return getSectorNoGenerateNoExNoLock(p);
130 }
131
132 MapSector * Map::getSectorNoGenerate(v2s16 p)
133 {
134         MapSector *sector = getSectorNoGenerateNoEx(p);
135         if(sector == NULL)
136                 throw InvalidPositionException();
137
138         return sector;
139 }
140
141 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
142 {
143         v2s16 p2d(p3d.X, p3d.Z);
144         MapSector * sector = getSectorNoGenerateNoEx(p2d);
145         if(sector == NULL)
146                 return NULL;
147         MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
148         return block;
149 }
150
151 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
152 {
153         MapBlock *block = getBlockNoCreateNoEx(p3d);
154         if(block == NULL)
155                 throw InvalidPositionException();
156         return block;
157 }
158
159 bool Map::isNodeUnderground(v3s16 p)
160 {
161         v3s16 blockpos = getNodeBlockPos(p);
162         try{
163                 MapBlock * block = getBlockNoCreate(blockpos);
164                 return block->getIsUnderground();
165         }
166         catch(InvalidPositionException &e)
167         {
168                 return false;
169         }
170 }
171
172 bool Map::isValidPosition(v3s16 p)
173 {
174         v3s16 blockpos = getNodeBlockPos(p);
175         MapBlock *block = getBlockNoCreate(blockpos);
176         return (block != NULL);
177 }
178
179 // Returns a CONTENT_IGNORE node if not found
180 MapNode Map::getNodeNoEx(v3s16 p)
181 {
182         v3s16 blockpos = getNodeBlockPos(p);
183         MapBlock *block = getBlockNoCreateNoEx(blockpos);
184         if(block == NULL)
185                 return MapNode(CONTENT_IGNORE);
186         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
187         return block->getNodeNoCheck(relpos);
188 }
189
190 // throws InvalidPositionException if not found
191 MapNode Map::getNode(v3s16 p)
192 {
193         v3s16 blockpos = getNodeBlockPos(p);
194         MapBlock *block = getBlockNoCreateNoEx(blockpos);
195         if(block == NULL)
196                 throw InvalidPositionException();
197         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
198         return block->getNodeNoCheck(relpos);
199 }
200
201 // throws InvalidPositionException if not found
202 void Map::setNode(v3s16 p, MapNode & n)
203 {
204         v3s16 blockpos = getNodeBlockPos(p);
205         MapBlock *block = getBlockNoCreate(blockpos);
206         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
207         // Never allow placing CONTENT_IGNORE, it fucks up stuff
208         if(n.getContent() == CONTENT_IGNORE){
209                 errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE"
210                                 <<" while trying to replace \""
211                                 <<m_gamedef->ndef()->get(block->getNodeNoCheck(relpos)).name
212                                 <<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
213                 debug_stacks_print_to(infostream);
214                 return;
215         }
216         block->setNodeNoCheck(relpos, n);
217 }
218
219
220 /*
221         Goes recursively through the neighbours of the node.
222
223         Alters only transparent nodes.
224
225         If the lighting of the neighbour is lower than the lighting of
226         the node was (before changing it to 0 at the step before), the
227         lighting of the neighbour is set to 0 and then the same stuff
228         repeats for the neighbour.
229
230         The ending nodes of the routine are stored in light_sources.
231         This is useful when a light is removed. In such case, this
232         routine can be called for the light node and then again for
233         light_sources to re-light the area without the removed light.
234
235         values of from_nodes are lighting values.
236 */
237 void Map::unspreadLight(enum LightBank bank,
238                 std::map<v3s16, u8> & from_nodes,
239                 std::set<v3s16> & light_sources,
240                 std::map<v3s16, MapBlock*>  & modified_blocks)
241 {
242         INodeDefManager *nodemgr = m_gamedef->ndef();
243
244         v3s16 dirs[6] = {
245                 v3s16(0,0,1), // back
246                 v3s16(0,1,0), // top
247                 v3s16(1,0,0), // right
248                 v3s16(0,0,-1), // front
249                 v3s16(0,-1,0), // bottom
250                 v3s16(-1,0,0), // left
251         };
252
253         if(from_nodes.size() == 0)
254                 return;
255
256         u32 blockchangecount = 0;
257
258         std::map<v3s16, u8> unlighted_nodes;
259
260         /*
261                 Initialize block cache
262         */
263         v3s16 blockpos_last;
264         MapBlock *block = NULL;
265         // Cache this a bit, too
266         bool block_checked_in_modified = false;
267
268         for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
269                 j != from_nodes.end(); ++j)
270         {
271                 v3s16 pos = j->first;
272                 v3s16 blockpos = getNodeBlockPos(pos);
273
274                 // Only fetch a new block if the block position has changed
275                 try{
276                         if(block == NULL || blockpos != blockpos_last){
277                                 block = getBlockNoCreate(blockpos);
278                                 blockpos_last = blockpos;
279
280                                 block_checked_in_modified = false;
281                                 blockchangecount++;
282                         }
283                 }
284                 catch(InvalidPositionException &e)
285                 {
286                         continue;
287                 }
288
289                 if(block->isDummy())
290                         continue;
291
292                 // Calculate relative position in block
293                 //v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
294
295                 // Get node straight from the block
296                 //MapNode n = block->getNode(relpos);
297
298                 u8 oldlight = j->second;
299
300                 // Loop through 6 neighbors
301                 for(u16 i=0; i<6; i++)
302                 {
303                         // Get the position of the neighbor node
304                         v3s16 n2pos = pos + dirs[i];
305
306                         // Get the block where the node is located
307                         v3s16 blockpos = getNodeBlockPos(n2pos);
308
309                         try
310                         {
311                                 // Only fetch a new block if the block position has changed
312                                 try{
313                                         if(block == NULL || blockpos != blockpos_last){
314                                                 block = getBlockNoCreate(blockpos);
315                                                 blockpos_last = blockpos;
316
317                                                 block_checked_in_modified = false;
318                                                 blockchangecount++;
319                                         }
320                                 }
321                                 catch(InvalidPositionException &e)
322                                 {
323                                         continue;
324                                 }
325
326                                 // Calculate relative position in block
327                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
328                                 // Get node straight from the block
329                                 MapNode n2 = block->getNode(relpos);
330
331                                 bool changed = false;
332
333                                 //TODO: Optimize output by optimizing light_sources?
334
335                                 /*
336                                         If the neighbor is dimmer than what was specified
337                                         as oldlight (the light of the previous node)
338                                 */
339                                 if(n2.getLight(bank, nodemgr) < oldlight)
340                                 {
341                                         /*
342                                                 And the neighbor is transparent and it has some light
343                                         */
344                                         if(nodemgr->get(n2).light_propagates
345                                                         && n2.getLight(bank, nodemgr) != 0)
346                                         {
347                                                 /*
348                                                         Set light to 0 and add to queue
349                                                 */
350
351                                                 u8 current_light = n2.getLight(bank, nodemgr);
352                                                 n2.setLight(bank, 0, nodemgr);
353                                                 block->setNode(relpos, n2);
354
355                                                 unlighted_nodes[n2pos] = current_light;
356                                                 changed = true;
357
358                                                 /*
359                                                         Remove from light_sources if it is there
360                                                         NOTE: This doesn't happen nearly at all
361                                                 */
362                                                 /*if(light_sources.find(n2pos))
363                                                 {
364                                                         infostream<<"Removed from light_sources"<<std::endl;
365                                                         light_sources.remove(n2pos);
366                                                 }*/
367                                         }
368
369                                         /*// DEBUG
370                                         if(light_sources.find(n2pos) != NULL)
371                                                 light_sources.remove(n2pos);*/
372                                 }
373                                 else{
374                                         light_sources.insert(n2pos);
375                                 }
376
377                                 // Add to modified_blocks
378                                 if(changed == true && block_checked_in_modified == false)
379                                 {
380                                         // If the block is not found in modified_blocks, add.
381                                         if(modified_blocks.find(blockpos) == modified_blocks.end())
382                                         {
383                                                 modified_blocks[blockpos] = block;
384                                         }
385                                         block_checked_in_modified = true;
386                                 }
387                         }
388                         catch(InvalidPositionException &e)
389                         {
390                                 continue;
391                         }
392                 }
393         }
394
395         /*infostream<<"unspreadLight(): Changed block "
396                         <<blockchangecount<<" times"
397                         <<" for "<<from_nodes.size()<<" nodes"
398                         <<std::endl;*/
399
400         if(unlighted_nodes.size() > 0)
401                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
402 }
403
404 /*
405         A single-node wrapper of the above
406 */
407 void Map::unLightNeighbors(enum LightBank bank,
408                 v3s16 pos, u8 lightwas,
409                 std::set<v3s16> & light_sources,
410                 std::map<v3s16, MapBlock*>  & modified_blocks)
411 {
412         std::map<v3s16, u8> from_nodes;
413         from_nodes[pos] = lightwas;
414
415         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
416 }
417
418 /*
419         Lights neighbors of from_nodes, collects all them and then
420         goes on recursively.
421 */
422 void Map::spreadLight(enum LightBank bank,
423                 std::set<v3s16> & from_nodes,
424                 std::map<v3s16, MapBlock*> & modified_blocks)
425 {
426         INodeDefManager *nodemgr = m_gamedef->ndef();
427
428         const v3s16 dirs[6] = {
429                 v3s16(0,0,1), // back
430                 v3s16(0,1,0), // top
431                 v3s16(1,0,0), // right
432                 v3s16(0,0,-1), // front
433                 v3s16(0,-1,0), // bottom
434                 v3s16(-1,0,0), // left
435         };
436
437         if(from_nodes.size() == 0)
438                 return;
439
440         u32 blockchangecount = 0;
441
442         std::set<v3s16> lighted_nodes;
443
444         /*
445                 Initialize block cache
446         */
447         v3s16 blockpos_last;
448         MapBlock *block = NULL;
449         // Cache this a bit, too
450         bool block_checked_in_modified = false;
451
452         for(std::set<v3s16>::iterator j = from_nodes.begin();
453                 j != from_nodes.end(); ++j)
454         {
455                 v3s16 pos = *j;
456                 v3s16 blockpos = getNodeBlockPos(pos);
457
458                 // Only fetch a new block if the block position has changed
459                 try{
460                         if(block == NULL || blockpos != blockpos_last){
461                                 block = getBlockNoCreate(blockpos);
462                                 blockpos_last = blockpos;
463
464                                 block_checked_in_modified = false;
465                                 blockchangecount++;
466                         }
467                 }
468                 catch(InvalidPositionException &e)
469                 {
470                         continue;
471                 }
472
473                 if(block->isDummy())
474                         continue;
475
476                 // Calculate relative position in block
477                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
478
479                 // Get node straight from the block
480                 MapNode n = block->getNode(relpos);
481
482                 u8 oldlight = n.getLight(bank, nodemgr);
483                 u8 newlight = diminish_light(oldlight);
484
485                 // Loop through 6 neighbors
486                 for(u16 i=0; i<6; i++){
487                         // Get the position of the neighbor node
488                         v3s16 n2pos = pos + dirs[i];
489
490                         // Get the block where the node is located
491                         v3s16 blockpos = getNodeBlockPos(n2pos);
492
493                         try
494                         {
495                                 // Only fetch a new block if the block position has changed
496                                 try{
497                                         if(block == NULL || blockpos != blockpos_last){
498                                                 block = getBlockNoCreate(blockpos);
499                                                 blockpos_last = blockpos;
500
501                                                 block_checked_in_modified = false;
502                                                 blockchangecount++;
503                                         }
504                                 }
505                                 catch(InvalidPositionException &e)
506                                 {
507                                         continue;
508                                 }
509
510                                 // Calculate relative position in block
511                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
512                                 // Get node straight from the block
513                                 MapNode n2 = block->getNode(relpos);
514
515                                 bool changed = false;
516                                 /*
517                                         If the neighbor is brighter than the current node,
518                                         add to list (it will light up this node on its turn)
519                                 */
520                                 if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
521                                 {
522                                         lighted_nodes.insert(n2pos);
523                                         changed = true;
524                                 }
525                                 /*
526                                         If the neighbor is dimmer than how much light this node
527                                         would spread on it, add to list
528                                 */
529                                 if(n2.getLight(bank, nodemgr) < newlight)
530                                 {
531                                         if(nodemgr->get(n2).light_propagates)
532                                         {
533                                                 n2.setLight(bank, newlight, nodemgr);
534                                                 block->setNode(relpos, n2);
535                                                 lighted_nodes.insert(n2pos);
536                                                 changed = true;
537                                         }
538                                 }
539
540                                 // Add to modified_blocks
541                                 if(changed == true && block_checked_in_modified == false)
542                                 {
543                                         // If the block is not found in modified_blocks, add.
544                                         if(modified_blocks.find(blockpos) == modified_blocks.end())
545                                         {
546                                                 modified_blocks[blockpos] = block;
547                                         }
548                                         block_checked_in_modified = true;
549                                 }
550                         }
551                         catch(InvalidPositionException &e)
552                         {
553                                 continue;
554                         }
555                 }
556         }
557
558         /*infostream<<"spreadLight(): Changed block "
559                         <<blockchangecount<<" times"
560                         <<" for "<<from_nodes.size()<<" nodes"
561                         <<std::endl;*/
562
563         if(lighted_nodes.size() > 0)
564                 spreadLight(bank, lighted_nodes, modified_blocks);
565 }
566
567 /*
568         A single-node source variation of the above.
569 */
570 void Map::lightNeighbors(enum LightBank bank,
571                 v3s16 pos,
572                 std::map<v3s16, MapBlock*> & modified_blocks)
573 {
574         std::set<v3s16> from_nodes;
575         from_nodes.insert(pos);
576         spreadLight(bank, from_nodes, modified_blocks);
577 }
578
579 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
580 {
581         INodeDefManager *nodemgr = m_gamedef->ndef();
582
583         v3s16 dirs[6] = {
584                 v3s16(0,0,1), // back
585                 v3s16(0,1,0), // top
586                 v3s16(1,0,0), // right
587                 v3s16(0,0,-1), // front
588                 v3s16(0,-1,0), // bottom
589                 v3s16(-1,0,0), // left
590         };
591
592         u8 brightest_light = 0;
593         v3s16 brightest_pos(0,0,0);
594         bool found_something = false;
595
596         // Loop through 6 neighbors
597         for(u16 i=0; i<6; i++){
598                 // Get the position of the neighbor node
599                 v3s16 n2pos = p + dirs[i];
600                 MapNode n2;
601                 try{
602                         n2 = getNode(n2pos);
603                 }
604                 catch(InvalidPositionException &e)
605                 {
606                         continue;
607                 }
608                 if(n2.getLight(bank, nodemgr) > brightest_light || found_something == false){
609                         brightest_light = n2.getLight(bank, nodemgr);
610                         brightest_pos = n2pos;
611                         found_something = true;
612                 }
613         }
614
615         if(found_something == false)
616                 throw InvalidPositionException();
617
618         return brightest_pos;
619 }
620
621 /*
622         Propagates sunlight down from a node.
623         Starting point gets sunlight.
624
625         Returns the lowest y value of where the sunlight went.
626
627         Mud is turned into grass in where the sunlight stops.
628 */
629 s16 Map::propagateSunlight(v3s16 start,
630                 std::map<v3s16, MapBlock*> & modified_blocks)
631 {
632         INodeDefManager *nodemgr = m_gamedef->ndef();
633
634         s16 y = start.Y;
635         for(; ; y--)
636         {
637                 v3s16 pos(start.X, y, start.Z);
638
639                 v3s16 blockpos = getNodeBlockPos(pos);
640                 MapBlock *block;
641                 try{
642                         block = getBlockNoCreate(blockpos);
643                 }
644                 catch(InvalidPositionException &e)
645                 {
646                         break;
647                 }
648
649                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
650                 MapNode n = block->getNode(relpos);
651
652                 if(nodemgr->get(n).sunlight_propagates)
653                 {
654                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
655                         block->setNode(relpos, n);
656
657                         modified_blocks[blockpos] = block;
658                 }
659                 else
660                 {
661                         // Sunlight goes no further
662                         break;
663                 }
664         }
665         return y + 1;
666 }
667
668 void Map::updateLighting(enum LightBank bank,
669                 std::map<v3s16, MapBlock*> & a_blocks,
670                 std::map<v3s16, MapBlock*> & modified_blocks)
671 {
672         INodeDefManager *nodemgr = m_gamedef->ndef();
673
674         /*m_dout<<DTIME<<"Map::updateLighting(): "
675                         <<a_blocks.size()<<" blocks."<<std::endl;*/
676
677         //TimeTaker timer("updateLighting");
678
679         // For debugging
680         //bool debug=true;
681         //u32 count_was = modified_blocks.size();
682
683         std::map<v3s16, MapBlock*> blocks_to_update;
684
685         std::set<v3s16> light_sources;
686
687         std::map<v3s16, u8> unlight_from;
688
689         int num_bottom_invalid = 0;
690
691         {
692         //TimeTaker t("first stuff");
693
694         for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
695                 i != a_blocks.end(); ++i)
696         {
697                 MapBlock *block = i->second;
698
699                 for(;;)
700                 {
701                         // Don't bother with dummy blocks.
702                         if(block->isDummy())
703                                 break;
704
705                         v3s16 pos = block->getPos();
706                         v3s16 posnodes = block->getPosRelative();
707                         modified_blocks[pos] = block;
708                         blocks_to_update[pos] = block;
709
710                         /*
711                                 Clear all light from block
712                         */
713                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
714                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
715                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
716                         {
717
718                                 try{
719                                         v3s16 p(x,y,z);
720                                         MapNode n = block->getNode(p);
721                                         u8 oldlight = n.getLight(bank, nodemgr);
722                                         n.setLight(bank, 0, nodemgr);
723                                         block->setNode(p, n);
724
725                                         // If node sources light, add to list
726                                         u8 source = nodemgr->get(n).light_source;
727                                         if(source != 0)
728                                                 light_sources.insert(p + posnodes);
729
730                                         // Collect borders for unlighting
731                                         if((x==0 || x == MAP_BLOCKSIZE-1
732                                         || y==0 || y == MAP_BLOCKSIZE-1
733                                         || z==0 || z == MAP_BLOCKSIZE-1)
734                                         && oldlight != 0)
735                                         {
736                                                 v3s16 p_map = p + posnodes;
737                                                 unlight_from[p_map] = oldlight;
738                                         }
739                                 }
740                                 catch(InvalidPositionException &e)
741                                 {
742                                         /*
743                                                 This would happen when dealing with a
744                                                 dummy block.
745                                         */
746                                         //assert(0);
747                                         infostream<<"updateLighting(): InvalidPositionException"
748                                                         <<std::endl;
749                                 }
750                         }
751
752                         if(bank == LIGHTBANK_DAY)
753                         {
754                                 bool bottom_valid = block->propagateSunlight(light_sources);
755
756                                 if(!bottom_valid)
757                                         num_bottom_invalid++;
758
759                                 // If bottom is valid, we're done.
760                                 if(bottom_valid)
761                                         break;
762                         }
763                         else if(bank == LIGHTBANK_NIGHT)
764                         {
765                                 // For night lighting, sunlight is not propagated
766                                 break;
767                         }
768                         else
769                         {
770                                 // Invalid lighting bank
771                                 assert(0);
772                         }
773
774                         /*infostream<<"Bottom for sunlight-propagated block ("
775                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
776                                         <<std::endl;*/
777
778                         // Bottom sunlight is not valid; get the block and loop to it
779
780                         pos.Y--;
781                         try{
782                                 block = getBlockNoCreate(pos);
783                         }
784                         catch(InvalidPositionException &e)
785                         {
786                                 assert(0);
787                         }
788
789                 }
790         }
791
792         }
793
794         /*
795                 Enable this to disable proper lighting for speeding up map
796                 generation for testing or whatever
797         */
798 #if 0
799         //if(g_settings->get(""))
800         {
801                 core::map<v3s16, MapBlock*>::Iterator i;
802                 i = blocks_to_update.getIterator();
803                 for(; i.atEnd() == false; i++)
804                 {
805                         MapBlock *block = i.getNode()->getValue();
806                         v3s16 p = block->getPos();
807                         block->setLightingExpired(false);
808                 }
809                 return;
810         }
811 #endif
812
813 #if 1
814         {
815                 //TimeTaker timer("unspreadLight");
816                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
817         }
818
819         /*if(debug)
820         {
821                 u32 diff = modified_blocks.size() - count_was;
822                 count_was = modified_blocks.size();
823                 infostream<<"unspreadLight modified "<<diff<<std::endl;
824         }*/
825
826         {
827                 //TimeTaker timer("spreadLight");
828                 spreadLight(bank, light_sources, modified_blocks);
829         }
830
831         /*if(debug)
832         {
833                 u32 diff = modified_blocks.size() - count_was;
834                 count_was = modified_blocks.size();
835                 infostream<<"spreadLight modified "<<diff<<std::endl;
836         }*/
837 #endif
838
839 #if 0
840         {
841                 //MapVoxelManipulator vmanip(this);
842
843                 // Make a manual voxel manipulator and load all the blocks
844                 // that touch the requested blocks
845                 ManualMapVoxelManipulator vmanip(this);
846
847                 {
848                 //TimeTaker timer("initialEmerge");
849
850                 core::map<v3s16, MapBlock*>::Iterator i;
851                 i = blocks_to_update.getIterator();
852                 for(; i.atEnd() == false; i++)
853                 {
854                         MapBlock *block = i.getNode()->getValue();
855                         v3s16 p = block->getPos();
856
857                         // Add all surrounding blocks
858                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
859
860                         /*
861                                 Add all surrounding blocks that have up-to-date lighting
862                                 NOTE: This doesn't quite do the job (not everything
863                                           appropriate is lighted)
864                         */
865                         /*for(s16 z=-1; z<=1; z++)
866                         for(s16 y=-1; y<=1; y++)
867                         for(s16 x=-1; x<=1; x++)
868                         {
869                                 v3s16 p2 = p + v3s16(x,y,z);
870                                 MapBlock *block = getBlockNoCreateNoEx(p2);
871                                 if(block == NULL)
872                                         continue;
873                                 if(block->isDummy())
874                                         continue;
875                                 if(block->getLightingExpired())
876                                         continue;
877                                 vmanip.initialEmerge(p2, p2);
878                         }*/
879
880                         // Lighting of block will be updated completely
881                         block->setLightingExpired(false);
882                 }
883                 }
884
885                 {
886                         //TimeTaker timer("unSpreadLight");
887                         vmanip.unspreadLight(bank, unlight_from, light_sources, nodemgr);
888                 }
889                 {
890                         //TimeTaker timer("spreadLight");
891                         vmanip.spreadLight(bank, light_sources, nodemgr);
892                 }
893                 {
894                         //TimeTaker timer("blitBack");
895                         vmanip.blitBack(modified_blocks);
896                 }
897                 /*infostream<<"emerge_time="<<emerge_time<<std::endl;
898                 emerge_time = 0;*/
899         }
900 #endif
901
902         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
903 }
904
905 void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
906                 std::map<v3s16, MapBlock*> & modified_blocks)
907 {
908         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
909         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
910
911         /*
912                 Update information about whether day and night light differ
913         */
914         for(std::map<v3s16, MapBlock*>::iterator
915                         i = modified_blocks.begin();
916                         i != modified_blocks.end(); ++i)
917         {
918                 MapBlock *block = i->second;
919                 block->expireDayNightDiff();
920         }
921 }
922
923 /*
924 */
925 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
926                 std::map<v3s16, MapBlock*> &modified_blocks)
927 {
928         INodeDefManager *ndef = m_gamedef->ndef();
929
930         /*PrintInfo(m_dout);
931         m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
932                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
933
934         /*
935                 From this node to nodes underneath:
936                 If lighting is sunlight (1.0), unlight neighbours and
937                 set lighting to 0.
938                 Else discontinue.
939         */
940
941         v3s16 toppos = p + v3s16(0,1,0);
942         //v3s16 bottompos = p + v3s16(0,-1,0);
943
944         bool node_under_sunlight = true;
945         std::set<v3s16> light_sources;
946
947         /*
948                 Collect old node for rollback
949         */
950         RollbackNode rollback_oldnode(this, p, m_gamedef);
951
952         /*
953                 If there is a node at top and it doesn't have sunlight,
954                 there has not been any sunlight going down.
955
956                 Otherwise there probably is.
957         */
958         try{
959                 MapNode topnode = getNode(toppos);
960
961                 if(topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
962                         node_under_sunlight = false;
963         }
964         catch(InvalidPositionException &e)
965         {
966         }
967
968         /*
969                 Remove all light that has come out of this node
970         */
971
972         enum LightBank banks[] =
973         {
974                 LIGHTBANK_DAY,
975                 LIGHTBANK_NIGHT
976         };
977         for(s32 i=0; i<2; i++)
978         {
979                 enum LightBank bank = banks[i];
980
981                 u8 lightwas = getNode(p).getLight(bank, ndef);
982
983                 // Add the block of the added node to modified_blocks
984                 v3s16 blockpos = getNodeBlockPos(p);
985                 MapBlock * block = getBlockNoCreate(blockpos);
986                 assert(block != NULL);
987                 modified_blocks[blockpos] = block;
988
989                 assert(isValidPosition(p));
990
991                 // Unlight neighbours of node.
992                 // This means setting light of all consequent dimmer nodes
993                 // to 0.
994                 // This also collects the nodes at the border which will spread
995                 // light again into this.
996                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
997
998                 n.setLight(bank, 0, ndef);
999         }
1000
1001         /*
1002                 If node lets sunlight through and is under sunlight, it has
1003                 sunlight too.
1004         */
1005         if(node_under_sunlight && ndef->get(n).sunlight_propagates)
1006         {
1007                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN, ndef);
1008         }
1009
1010         /*
1011                 Remove node metadata
1012         */
1013
1014         removeNodeMetadata(p);
1015
1016         /*
1017                 Set the node on the map
1018         */
1019
1020         setNode(p, n);
1021
1022         /*
1023                 If node is under sunlight and doesn't let sunlight through,
1024                 take all sunlighted nodes under it and clear light from them
1025                 and from where the light has been spread.
1026                 TODO: This could be optimized by mass-unlighting instead
1027                           of looping
1028         */
1029         if(node_under_sunlight && !ndef->get(n).sunlight_propagates)
1030         {
1031                 s16 y = p.Y - 1;
1032                 for(;; y--){
1033                         //m_dout<<DTIME<<"y="<<y<<std::endl;
1034                         v3s16 n2pos(p.X, y, p.Z);
1035
1036                         MapNode n2;
1037                         try{
1038                                 n2 = getNode(n2pos);
1039                         }
1040                         catch(InvalidPositionException &e)
1041                         {
1042                                 break;
1043                         }
1044
1045                         if(n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
1046                         {
1047                                 unLightNeighbors(LIGHTBANK_DAY,
1048                                                 n2pos, n2.getLight(LIGHTBANK_DAY, ndef),
1049                                                 light_sources, modified_blocks);
1050                                 n2.setLight(LIGHTBANK_DAY, 0, ndef);
1051                                 setNode(n2pos, n2);
1052                         }
1053                         else
1054                                 break;
1055                 }
1056         }
1057
1058         for(s32 i=0; i<2; i++)
1059         {
1060                 enum LightBank bank = banks[i];
1061
1062                 /*
1063                         Spread light from all nodes that might be capable of doing so
1064                 */
1065                 spreadLight(bank, light_sources, modified_blocks);
1066         }
1067
1068         /*
1069                 Update information about whether day and night light differ
1070         */
1071         for(std::map<v3s16, MapBlock*>::iterator
1072                         i = modified_blocks.begin();
1073                         i != modified_blocks.end(); ++i)
1074         {
1075                 i->second->expireDayNightDiff();
1076         }
1077
1078         /*
1079                 Report for rollback
1080         */
1081         if(m_gamedef->rollback())
1082         {
1083                 RollbackNode rollback_newnode(this, p, m_gamedef);
1084                 RollbackAction action;
1085                 action.setSetNode(p, rollback_oldnode, rollback_newnode);
1086                 m_gamedef->rollback()->reportAction(action);
1087         }
1088
1089         /*
1090                 Add neighboring liquid nodes and the node itself if it is
1091                 liquid (=water node was added) to transform queue.
1092                 note: todo: for liquid_finite enough to add only self node
1093         */
1094         v3s16 dirs[7] = {
1095                 v3s16(0,0,0), // self
1096                 v3s16(0,0,1), // back
1097                 v3s16(0,1,0), // top
1098                 v3s16(1,0,0), // right
1099                 v3s16(0,0,-1), // front
1100                 v3s16(0,-1,0), // bottom
1101                 v3s16(-1,0,0), // left
1102         };
1103         for(u16 i=0; i<7; i++)
1104         {
1105                 try
1106                 {
1107
1108                 v3s16 p2 = p + dirs[i];
1109
1110                 MapNode n2 = getNode(p2);
1111                 if(ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)
1112                 {
1113                         m_transforming_liquid.push_back(p2);
1114                 }
1115
1116                 }catch(InvalidPositionException &e)
1117                 {
1118                 }
1119         }
1120 }
1121
1122 /*
1123 */
1124 void Map::removeNodeAndUpdate(v3s16 p,
1125                 std::map<v3s16, MapBlock*> &modified_blocks)
1126 {
1127         INodeDefManager *ndef = m_gamedef->ndef();
1128
1129         /*PrintInfo(m_dout);
1130         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1131                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1132
1133         bool node_under_sunlight = true;
1134
1135         v3s16 toppos = p + v3s16(0,1,0);
1136
1137         // Node will be replaced with this
1138         content_t replace_material = CONTENT_AIR;
1139
1140         /*
1141                 Collect old node for rollback
1142         */
1143         RollbackNode rollback_oldnode(this, p, m_gamedef);
1144
1145         /*
1146                 If there is a node at top and it doesn't have sunlight,
1147                 there will be no sunlight going down.
1148         */
1149         try{
1150                 MapNode topnode = getNode(toppos);
1151
1152                 if(topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
1153                         node_under_sunlight = false;
1154         }
1155         catch(InvalidPositionException &e)
1156         {
1157         }
1158
1159         std::set<v3s16> light_sources;
1160
1161         enum LightBank banks[] =
1162         {
1163                 LIGHTBANK_DAY,
1164                 LIGHTBANK_NIGHT
1165         };
1166         for(s32 i=0; i<2; i++)
1167         {
1168                 enum LightBank bank = banks[i];
1169
1170                 /*
1171                         Unlight neighbors (in case the node is a light source)
1172                 */
1173                 unLightNeighbors(bank, p,
1174                                 getNode(p).getLight(bank, ndef),
1175                                 light_sources, modified_blocks);
1176         }
1177
1178         /*
1179                 Remove node metadata
1180         */
1181
1182         removeNodeMetadata(p);
1183
1184         /*
1185                 Remove the node.
1186                 This also clears the lighting.
1187         */
1188
1189         MapNode n;
1190         n.setContent(replace_material);
1191         setNode(p, n);
1192
1193         for(s32 i=0; i<2; i++)
1194         {
1195                 enum LightBank bank = banks[i];
1196
1197                 /*
1198                         Recalculate lighting
1199                 */
1200                 spreadLight(bank, light_sources, modified_blocks);
1201         }
1202
1203         // Add the block of the removed node to modified_blocks
1204         v3s16 blockpos = getNodeBlockPos(p);
1205         MapBlock * block = getBlockNoCreate(blockpos);
1206         assert(block != NULL);
1207         modified_blocks[blockpos] = block;
1208
1209         /*
1210                 If the removed node was under sunlight, propagate the
1211                 sunlight down from it and then light all neighbors
1212                 of the propagated blocks.
1213         */
1214         if(node_under_sunlight)
1215         {
1216                 s16 ybottom = propagateSunlight(p, modified_blocks);
1217                 /*m_dout<<DTIME<<"Node was under sunlight. "
1218                                 "Propagating sunlight";
1219                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1220                 s16 y = p.Y;
1221                 for(; y >= ybottom; y--)
1222                 {
1223                         v3s16 p2(p.X, y, p.Z);
1224                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1225                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1226                                         <<std::endl;*/
1227                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1228                 }
1229         }
1230         else
1231         {
1232                 // Set the lighting of this node to 0
1233                 // TODO: Is this needed? Lighting is cleared up there already.
1234                 try{
1235                         MapNode n = getNode(p);
1236                         n.setLight(LIGHTBANK_DAY, 0, ndef);
1237                         setNode(p, n);
1238                 }
1239                 catch(InvalidPositionException &e)
1240                 {
1241                         assert(0);
1242                 }
1243         }
1244
1245         for(s32 i=0; i<2; i++)
1246         {
1247                 enum LightBank bank = banks[i];
1248
1249                 // Get the brightest neighbour node and propagate light from it
1250                 v3s16 n2p = getBrightestNeighbour(bank, p);
1251                 try{
1252                         //MapNode n2 = getNode(n2p);
1253                         lightNeighbors(bank, n2p, modified_blocks);
1254                 }
1255                 catch(InvalidPositionException &e)
1256                 {
1257                 }
1258         }
1259
1260         /*
1261                 Update information about whether day and night light differ
1262         */
1263         for(std::map<v3s16, MapBlock*>::iterator
1264                         i = modified_blocks.begin();
1265                         i != modified_blocks.end(); ++i)
1266         {
1267                 i->second->expireDayNightDiff();
1268         }
1269
1270         /*
1271                 Report for rollback
1272         */
1273         if(m_gamedef->rollback())
1274         {
1275                 RollbackNode rollback_newnode(this, p, m_gamedef);
1276                 RollbackAction action;
1277                 action.setSetNode(p, rollback_oldnode, rollback_newnode);
1278                 m_gamedef->rollback()->reportAction(action);
1279         }
1280
1281         /*
1282                 Add neighboring liquid nodes and this node to transform queue.
1283                 (it's vital for the node itself to get updated last.)
1284                 note: todo: for liquid_finite enough to add only self node
1285         */
1286         v3s16 dirs[7] = {
1287                 v3s16(0,0,1), // back
1288                 v3s16(0,1,0), // top
1289                 v3s16(1,0,0), // right
1290                 v3s16(0,0,-1), // front
1291                 v3s16(0,-1,0), // bottom
1292                 v3s16(-1,0,0), // left
1293                 v3s16(0,0,0), // self
1294         };
1295         for(u16 i=0; i<7; i++)
1296         {
1297                 try
1298                 {
1299
1300                 v3s16 p2 = p + dirs[i];
1301
1302                 MapNode n2 = getNode(p2);
1303                 if(ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)
1304                 {
1305                         m_transforming_liquid.push_back(p2);
1306                 }
1307
1308                 }catch(InvalidPositionException &e)
1309                 {
1310                 }
1311         }
1312 }
1313
1314 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1315 {
1316         MapEditEvent event;
1317         event.type = MEET_ADDNODE;
1318         event.p = p;
1319         event.n = n;
1320
1321         bool succeeded = true;
1322         try{
1323                 std::map<v3s16, MapBlock*> modified_blocks;
1324                 addNodeAndUpdate(p, n, modified_blocks);
1325
1326                 // Copy modified_blocks to event
1327                 for(std::map<v3s16, MapBlock*>::iterator
1328                                 i = modified_blocks.begin();
1329                                 i != modified_blocks.end(); ++i)
1330                 {
1331                         event.modified_blocks.insert(i->first);
1332                 }
1333         }
1334         catch(InvalidPositionException &e){
1335                 succeeded = false;
1336         }
1337
1338         dispatchEvent(&event);
1339
1340         return succeeded;
1341 }
1342
1343 bool Map::removeNodeWithEvent(v3s16 p)
1344 {
1345         MapEditEvent event;
1346         event.type = MEET_REMOVENODE;
1347         event.p = p;
1348
1349         bool succeeded = true;
1350         try{
1351                 std::map<v3s16, MapBlock*> modified_blocks;
1352                 removeNodeAndUpdate(p, modified_blocks);
1353
1354                 // Copy modified_blocks to event
1355                 for(std::map<v3s16, MapBlock*>::iterator
1356                                 i = modified_blocks.begin();
1357                                 i != modified_blocks.end(); ++i)
1358                 {
1359                         event.modified_blocks.insert(i->first);
1360                 }
1361         }
1362         catch(InvalidPositionException &e){
1363                 succeeded = false;
1364         }
1365
1366         dispatchEvent(&event);
1367
1368         return succeeded;
1369 }
1370
1371 bool Map::getDayNightDiff(v3s16 blockpos)
1372 {
1373         try{
1374                 v3s16 p = blockpos + v3s16(0,0,0);
1375                 MapBlock *b = getBlockNoCreate(p);
1376                 if(b->getDayNightDiff())
1377                         return true;
1378         }
1379         catch(InvalidPositionException &e){}
1380         // Leading edges
1381         try{
1382                 v3s16 p = blockpos + v3s16(-1,0,0);
1383                 MapBlock *b = getBlockNoCreate(p);
1384                 if(b->getDayNightDiff())
1385                         return true;
1386         }
1387         catch(InvalidPositionException &e){}
1388         try{
1389                 v3s16 p = blockpos + v3s16(0,-1,0);
1390                 MapBlock *b = getBlockNoCreate(p);
1391                 if(b->getDayNightDiff())
1392                         return true;
1393         }
1394         catch(InvalidPositionException &e){}
1395         try{
1396                 v3s16 p = blockpos + v3s16(0,0,-1);
1397                 MapBlock *b = getBlockNoCreate(p);
1398                 if(b->getDayNightDiff())
1399                         return true;
1400         }
1401         catch(InvalidPositionException &e){}
1402         // Trailing edges
1403         try{
1404                 v3s16 p = blockpos + v3s16(1,0,0);
1405                 MapBlock *b = getBlockNoCreate(p);
1406                 if(b->getDayNightDiff())
1407                         return true;
1408         }
1409         catch(InvalidPositionException &e){}
1410         try{
1411                 v3s16 p = blockpos + v3s16(0,1,0);
1412                 MapBlock *b = getBlockNoCreate(p);
1413                 if(b->getDayNightDiff())
1414                         return true;
1415         }
1416         catch(InvalidPositionException &e){}
1417         try{
1418                 v3s16 p = blockpos + v3s16(0,0,1);
1419                 MapBlock *b = getBlockNoCreate(p);
1420                 if(b->getDayNightDiff())
1421                         return true;
1422         }
1423         catch(InvalidPositionException &e){}
1424
1425         return false;
1426 }
1427
1428 /*
1429         Updates usage timers
1430 */
1431 void Map::timerUpdate(float dtime, float unload_timeout,
1432                 std::list<v3s16> *unloaded_blocks)
1433 {
1434         bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
1435
1436         // Profile modified reasons
1437         Profiler modprofiler;
1438
1439         std::list<v2s16> sector_deletion_queue;
1440         u32 deleted_blocks_count = 0;
1441         u32 saved_blocks_count = 0;
1442         u32 block_count_all = 0;
1443
1444         beginSave();
1445         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1446                 si != m_sectors.end(); ++si)
1447         {
1448                 MapSector *sector = si->second;
1449
1450                 bool all_blocks_deleted = true;
1451
1452                 std::list<MapBlock*> blocks;
1453                 sector->getBlocks(blocks);
1454
1455                 for(std::list<MapBlock*>::iterator i = blocks.begin();
1456                                 i != blocks.end(); ++i)
1457                 {
1458                         MapBlock *block = (*i);
1459
1460                         block->incrementUsageTimer(dtime);
1461
1462                         if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout)
1463                         {
1464                                 v3s16 p = block->getPos();
1465
1466                                 // Save if modified
1467                                 if(block->getModified() != MOD_STATE_CLEAN
1468                                                 && save_before_unloading)
1469                                 {
1470                                         modprofiler.add(block->getModifiedReason(), 1);
1471                                         saveBlock(block);
1472                                         saved_blocks_count++;
1473                                 }
1474
1475                                 // Delete from memory
1476                                 sector->deleteBlock(block);
1477
1478                                 if(unloaded_blocks)
1479                                         unloaded_blocks->push_back(p);
1480
1481                                 deleted_blocks_count++;
1482                         }
1483                         else
1484                         {
1485                                 all_blocks_deleted = false;
1486                                 block_count_all++;
1487                         }
1488                 }
1489
1490                 if(all_blocks_deleted)
1491                 {
1492                         sector_deletion_queue.push_back(si->first);
1493                 }
1494         }
1495         endSave();
1496
1497         // Finally delete the empty sectors
1498         deleteSectors(sector_deletion_queue);
1499
1500         if(deleted_blocks_count != 0)
1501         {
1502                 PrintInfo(infostream); // ServerMap/ClientMap:
1503                 infostream<<"Unloaded "<<deleted_blocks_count
1504                                 <<" blocks from memory";
1505                 if(save_before_unloading)
1506                         infostream<<", of which "<<saved_blocks_count<<" were written";
1507                 infostream<<", "<<block_count_all<<" blocks in memory";
1508                 infostream<<"."<<std::endl;
1509                 if(saved_blocks_count != 0){
1510                         PrintInfo(infostream); // ServerMap/ClientMap:
1511                         infostream<<"Blocks modified by: "<<std::endl;
1512                         modprofiler.print(infostream);
1513                 }
1514         }
1515 }
1516
1517 void Map::unloadUnreferencedBlocks(std::list<v3s16> *unloaded_blocks)
1518 {
1519         timerUpdate(0.0, -1.0, unloaded_blocks);
1520 }
1521
1522 void Map::deleteSectors(std::list<v2s16> &list)
1523 {
1524         for(std::list<v2s16>::iterator j = list.begin();
1525                 j != list.end(); ++j)
1526         {
1527                 MapSector *sector = m_sectors[*j];
1528                 // If sector is in sector cache, remove it from there
1529                 if(m_sector_cache == sector)
1530                         m_sector_cache = NULL;
1531                 // Remove from map and delete
1532                 m_sectors.erase(*j);
1533                 delete sector;
1534         }
1535 }
1536
1537 #if 0
1538 void Map::unloadUnusedData(float timeout,
1539                 core::list<v3s16> *deleted_blocks)
1540 {
1541         core::list<v2s16> sector_deletion_queue;
1542         u32 deleted_blocks_count = 0;
1543         u32 saved_blocks_count = 0;
1544
1545         core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
1546         for(; si.atEnd() == false; si++)
1547         {
1548                 MapSector *sector = si.getNode()->getValue();
1549
1550                 bool all_blocks_deleted = true;
1551
1552                 core::list<MapBlock*> blocks;
1553                 sector->getBlocks(blocks);
1554                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1555                                 i != blocks.end(); i++)
1556                 {
1557                         MapBlock *block = (*i);
1558
1559                         if(block->getUsageTimer() > timeout)
1560                         {
1561                                 // Save if modified
1562                                 if(block->getModified() != MOD_STATE_CLEAN)
1563                                 {
1564                                         saveBlock(block);
1565                                         saved_blocks_count++;
1566                                 }
1567                                 // Delete from memory
1568                                 sector->deleteBlock(block);
1569                                 deleted_blocks_count++;
1570                         }
1571                         else
1572                         {
1573                                 all_blocks_deleted = false;
1574                         }
1575                 }
1576
1577                 if(all_blocks_deleted)
1578                 {
1579                         sector_deletion_queue.push_back(si.getNode()->getKey());
1580                 }
1581         }
1582
1583         deleteSectors(sector_deletion_queue);
1584
1585         infostream<<"Map: Unloaded "<<deleted_blocks_count<<" blocks from memory"
1586                         <<", of which "<<saved_blocks_count<<" were wr."
1587                         <<std::endl;
1588
1589         //return sector_deletion_queue.getSize();
1590         //return deleted_blocks_count;
1591 }
1592 #endif
1593
1594 void Map::PrintInfo(std::ostream &out)
1595 {
1596         out<<"Map: ";
1597 }
1598
1599 #define WATER_DROP_BOOST 4
1600
1601 enum NeighborType {
1602         NEIGHBOR_UPPER,
1603         NEIGHBOR_SAME_LEVEL,
1604         NEIGHBOR_LOWER
1605 };
1606 struct NodeNeighbor {
1607         MapNode n;
1608         NeighborType t;
1609         v3s16 p;
1610         bool l; //can liquid
1611         bool i; //infinity
1612 };
1613
1614 void Map::transforming_liquid_add(v3s16 p) {
1615         m_transforming_liquid.push_back(p);
1616 }
1617
1618 s32 Map::transforming_liquid_size() {
1619         return m_transforming_liquid.size();
1620 }
1621
1622 const v3s16 g_7dirs[7] =
1623 {
1624         // +right, +top, +back
1625         v3s16( 0,-1, 0), // bottom
1626         v3s16( 0, 0, 0), // self
1627         v3s16( 0, 0, 1), // back
1628         v3s16( 0, 0,-1), // front
1629         v3s16( 1, 0, 0), // right
1630         v3s16(-1, 0, 0), // left
1631         v3s16( 0, 1, 0)  // top
1632 };
1633
1634 #define D_BOTTOM 0
1635 #define D_TOP 6
1636 #define D_SELF 1
1637
1638 void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
1639 {
1640         INodeDefManager *nodemgr = m_gamedef->ndef();
1641
1642         DSTACK(__FUNCTION_NAME);
1643         //TimeTaker timer("transformLiquids()");
1644
1645         u32 loopcount = 0;
1646         u32 initial_size = m_transforming_liquid.size();
1647
1648         u8 relax = g_settings->getS16("liquid_relax");
1649         bool fast_flood = g_settings->getS16("liquid_fast_flood");
1650         int water_level = g_settings->getS16("water_level");
1651
1652         // list of nodes that due to viscosity have not reached their max level height
1653         UniqueQueue<v3s16> must_reflow, must_reflow_second;
1654
1655         // List of MapBlocks that will require a lighting update (due to lava)
1656         std::map<v3s16, MapBlock*> lighting_modified_blocks;
1657
1658         u16 loop_max = g_settings->getU16("liquid_loop_max");
1659
1660         //if (m_transforming_liquid.size() > 0) errorstream << "Liquid queue size="<<m_transforming_liquid.size()<<std::endl;
1661
1662         while (m_transforming_liquid.size() > 0)
1663         {
1664                 // This should be done here so that it is done when continue is used
1665                 if (loopcount >= initial_size || loopcount >= loop_max)
1666                         break;
1667                 loopcount++;
1668                 /*
1669                         Get a queued transforming liquid node
1670                 */
1671                 v3s16 p0 = m_transforming_liquid.pop_front();
1672                 u16 total_level = 0;
1673                 // surrounding flowing liquid nodes
1674                 NodeNeighbor neighbors[7]; 
1675                 // current level of every block
1676                 s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1};
1677                  // target levels
1678                 s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1};
1679                 s8 can_liquid_same_level = 0;
1680                 content_t liquid_kind = CONTENT_IGNORE;
1681                 content_t liquid_kind_flowing = CONTENT_IGNORE;
1682                 /*
1683                         Collect information about the environment
1684                  */
1685                 const v3s16 *dirs = g_7dirs;
1686                 for (u16 i = 0; i < 7; i++) {
1687                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1688                         switch (i) {
1689                                 case D_TOP:
1690                                         nt = NEIGHBOR_UPPER;
1691                                         break;
1692                                 case D_BOTTOM:
1693                                         nt = NEIGHBOR_LOWER;
1694                                         break;
1695                         }
1696                         v3s16 npos = p0 + dirs[i];
1697
1698                         neighbors[i].n = getNodeNoEx(npos);
1699                         neighbors[i].t = nt;
1700                         neighbors[i].p = npos;
1701                         neighbors[i].l = 0;
1702                         neighbors[i].i = 0;
1703                         NodeNeighbor & nb = neighbors[i];
1704
1705                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
1706                                 case LIQUID_NONE:
1707                                         if (nb.n.getContent() == CONTENT_AIR) {
1708                                                 liquid_levels[i] = 0;
1709                                                 nb.l = 1;
1710                                         }
1711                                         break;
1712                                 case LIQUID_SOURCE:
1713                                         // if this node is not (yet) of a liquid type,
1714                                         // choose the first liquid type we encounter
1715                                         if (liquid_kind_flowing == CONTENT_IGNORE)
1716                                                 liquid_kind_flowing = nodemgr->getId(
1717                                                         nodemgr->get(nb.n).liquid_alternative_flowing);
1718                                         if (liquid_kind == CONTENT_IGNORE)
1719                                                 liquid_kind = nb.n.getContent();
1720                                         if (nb.n.getContent() == liquid_kind) {
1721                                                 liquid_levels[i] = nb.n.getLevel(nodemgr); //LIQUID_LEVEL_SOURCE;
1722                                                 nb.l = 1;
1723                                                 nb.i = (nb.n.param2 & LIQUID_INFINITY_MASK);
1724                                         }
1725                                         break;
1726                                 case LIQUID_FLOWING:
1727                                         // if this node is not (yet) of a liquid type,
1728                                         // choose the first liquid type we encounter
1729                                         if (liquid_kind_flowing == CONTENT_IGNORE)
1730                                                 liquid_kind_flowing = nb.n.getContent();
1731                                         if (liquid_kind == CONTENT_IGNORE)
1732                                                 liquid_kind = nodemgr->getId(
1733                                                         nodemgr->get(nb.n).liquid_alternative_source);
1734                                         if (nb.n.getContent() == liquid_kind_flowing) {
1735                                                 liquid_levels[i] = nb.n.getLevel(nodemgr); //(nb.n.param2 & LIQUID_LEVEL_MASK);
1736                                                 nb.l = 1;
1737                                         }
1738                                         break;
1739                         }
1740                         
1741                         if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL)
1742                                 ++can_liquid_same_level;
1743                         if (liquid_levels[i] > 0)
1744                                 total_level += liquid_levels[i];
1745
1746                         /*
1747                         infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c="
1748                         << nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1="
1749                         << (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt="
1750                         << nodemgr->get(nb.n.getContent()).liquid_type
1751                         //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing
1752                         << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i]
1753                         << " tlevel=" << (int)total_level << " cansame="
1754                         << (int)can_liquid_same_level << std::endl;
1755                         */
1756                 }
1757
1758                 if (liquid_kind == CONTENT_IGNORE ||
1759                         !neighbors[D_SELF].l ||
1760                         total_level <= 0)
1761                         continue;
1762
1763                 // fill bottom block
1764                 if (neighbors[D_BOTTOM].l) {
1765                         liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ?
1766                                 LIQUID_LEVEL_SOURCE : total_level;
1767                         total_level -= liquid_levels_want[D_BOTTOM];
1768                 }
1769
1770                 //relax up
1771                 if (relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && liquid_levels[D_TOP] == 0 &&
1772                         liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE &&
1773                         total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level-
1774                         (can_liquid_same_level - relax) &&
1775                         can_liquid_same_level >= relax + 1) { 
1776                         total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level; 
1777                 }
1778
1779                 // prevent lakes in air above unloaded blocks
1780                 if (liquid_levels[D_TOP] == 0 && (p0.Y > water_level) && neighbors[D_BOTTOM].n.getContent() == CONTENT_IGNORE && !(loopcount % 3)) {
1781                         --total_level;
1782                 }
1783
1784                 // calculate self level 5 blocks
1785                 u8 want_level = 
1786                           total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level
1787                         ? LIQUID_LEVEL_SOURCE 
1788                         : total_level / can_liquid_same_level;
1789                 total_level -= want_level * can_liquid_same_level;
1790
1791                 //relax down
1792                 if (relax && p0.Y == water_level + 1 && liquid_levels[D_TOP] == 0 &&
1793                         liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 &&
1794                         total_level <= (can_liquid_same_level - relax) &&
1795                         can_liquid_same_level >= relax + 1) {
1796                         total_level = 0;
1797                 }
1798
1799                 for (u16 ii = D_SELF; ii < D_TOP; ++ii) { // fill only same level
1800                         if (!neighbors[ii].l)
1801                                 continue;
1802                         liquid_levels_want[ii] = want_level;
1803                         if (liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE && total_level > 0) {
1804                                 if (loopcount % 3 || liquid_levels[ii] <= 0){
1805                                         if (liquid_levels[ii] > liquid_levels_want[ii]) {
1806                                                 ++liquid_levels_want[ii];
1807                                                 --total_level;
1808                                         }
1809                                 } else if (neighbors[ii].l > 0){
1810                                                 ++liquid_levels_want[ii];
1811                                                 --total_level;
1812                                 }
1813                         }
1814                 }
1815
1816                 for (u16 ii = 0; ii < 7; ++ii) {
1817                         if (total_level < 1) break;
1818                         if (liquid_levels_want[ii] >= 0 &&
1819                                 liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) {
1820                                 ++liquid_levels_want[ii];
1821                                 --total_level;
1822                         }
1823                 }
1824
1825                 // fill top block if can
1826                 if (neighbors[D_TOP].l) {
1827                         liquid_levels_want[D_TOP] = total_level > LIQUID_LEVEL_SOURCE ?
1828                                 LIQUID_LEVEL_SOURCE : total_level;
1829                         total_level -= liquid_levels_want[D_TOP];
1830                 }
1831
1832                 for (u16 ii = 0; ii < 7; ii++) // infinity and cave flood optimization
1833                         if (    neighbors[ii].i ||
1834                                 (liquid_levels_want[ii] >= 0 &&
1835                                  (fast_flood && p0.Y < water_level &&
1836                                   (initial_size >= 1000
1837                                    && ii != D_TOP
1838                                    && want_level >= LIQUID_LEVEL_SOURCE/4
1839                                    && can_liquid_same_level >= 5
1840                                    && liquid_levels[D_TOP] >= LIQUID_LEVEL_SOURCE))))
1841                                 liquid_levels_want[ii] = LIQUID_LEVEL_SOURCE;
1842
1843                 /*
1844                 if (total_level > 0) //|| flowed != volume)
1845                         infostream <<" AFTER level=" << (int)total_level 
1846                         //<< " flowed="<<flowed<< " volume=" << volume
1847                         << " wantsame="<<(int)want_level<< " top="
1848                         << (int)liquid_levels_want[D_TOP]<< " topwas="
1849                         << (int)liquid_levels[D_TOP]<< " bot="
1850                         << (int)liquid_levels_want[D_BOTTOM]<<std::endl;
1851                 */
1852
1853                 //u8 changed = 0;
1854                 for (u16 i = 0; i < 7; i++) {
1855                         if (liquid_levels_want[i] < 0 || !neighbors[i].l) 
1856                                 continue;
1857                         MapNode & n0 = neighbors[i].n;
1858                         p0 = neighbors[i].p;
1859                         /*
1860                                 decide on the type (and possibly level) of the current node
1861                         */
1862                         content_t new_node_content;
1863                         s8 new_node_level = -1;
1864                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1865                         if (viscosity > 1 && liquid_levels_want[i] != liquid_levels[i]) {
1866                                 // amount to gain, limited by viscosity
1867                                 // must be at least 1 in absolute value
1868                                 s8 level_inc = liquid_levels_want[i] - liquid_levels[i];
1869                                 if (level_inc < -viscosity || level_inc > viscosity)
1870                                         new_node_level = liquid_levels[i] + level_inc/viscosity;
1871                                 else if (level_inc < 0)
1872                                         new_node_level = liquid_levels[i] - 1;
1873                                 else if (level_inc > 0)
1874                                         new_node_level = liquid_levels[i] + 1;
1875                         } else {
1876                                 new_node_level = liquid_levels_want[i];
1877                         }
1878                         
1879                         if (new_node_level >= LIQUID_LEVEL_SOURCE)
1880                                 new_node_content = liquid_kind;
1881                         else if (new_node_level > 0)
1882                                 new_node_content = liquid_kind_flowing;
1883                         else
1884                                 new_node_content = CONTENT_AIR;
1885                         
1886                         // last level must flow down on stairs
1887                         if (liquid_levels_want[i] != liquid_levels[i] &&
1888                                 liquid_levels[D_TOP] <= 0 && !neighbors[D_BOTTOM].l &&
1889                                 new_node_level >= 1 && new_node_level <= 2) {
1890                                 for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
1891                                         if (neighbors[ii].l)
1892                                                 must_reflow_second.push_back(p0 + dirs[ii]);
1893                                 }
1894                         }
1895
1896                         /*
1897                                 check if anything has changed.
1898                                 if not, just continue with the next node.
1899                          */
1900                         /*
1901                         if (
1902                                  new_node_content == n0.getContent() 
1903                                 && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1904                                  (n0.getLevel(nodemgr) == (u8)new_node_level
1905                                  //&& ((n0.param2 & LIQUID_FLOW_DOWN_MASK) ==
1906                                  //LIQUID_FLOW_DOWN_MASK) == flowing_down
1907                                  ))
1908                                 &&
1909                                  (nodemgr->get(n0.getContent()).liquid_type != LIQUID_SOURCE ||
1910                                  (((n0.param2 & LIQUID_INFINITY_MASK) ==
1911                                         LIQUID_INFINITY_MASK) == neighbors[i].i
1912                                  ))
1913                            )*/
1914                         if (liquid_levels[i] == new_node_level)
1915                         {
1916                                 continue;
1917                         }
1918                         
1919                         //++changed;
1920
1921                         /*
1922                                 update the current node
1923                          */
1924                         /*
1925                         if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1926                                 // set level to last 3 bits, flowing down bit to 4th bit
1927                                 n0.param2 = (new_node_level & LIQUID_LEVEL_MASK);
1928                         } else if (nodemgr->get(new_node_content).liquid_type == LIQUID_SOURCE) {
1929                                 //n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1930                                 n0.param2 = (neighbors[i].i ? LIQUID_INFINITY_MASK : 0x00);
1931                         }
1932                         */
1933                         /*
1934                         infostream << "set node i=" <<(int)i<<" "<< PP(p0)<< " nc="
1935                         <<new_node_content<< " p2="<<(int)n0.param2<< " nl="
1936                         <<(int)new_node_level<<std::endl;
1937                         */
1938                         
1939                         n0.setContent(liquid_kind_flowing);
1940                         n0.setLevel(nodemgr, new_node_level);
1941                         // Find out whether there is a suspect for this action
1942                         std::string suspect;
1943                         if(m_gamedef->rollback()){
1944                                 suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
1945                         }
1946
1947                         if(!suspect.empty()){
1948                                 // Blame suspect
1949                                 RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
1950                                 // Get old node for rollback
1951                                 RollbackNode rollback_oldnode(this, p0, m_gamedef);
1952                                 // Set node
1953                                 setNode(p0, n0);
1954                                 // Report
1955                                 RollbackNode rollback_newnode(this, p0, m_gamedef);
1956                                 RollbackAction action;
1957                                 action.setSetNode(p0, rollback_oldnode, rollback_newnode);
1958                                 m_gamedef->rollback()->reportAction(action);
1959                         } else {
1960                                 // Set node
1961                                 setNode(p0, n0);
1962                         }
1963
1964                         v3s16 blockpos = getNodeBlockPos(p0);
1965                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1966                         if(block != NULL) {
1967                                 modified_blocks[blockpos] = block;
1968                                 // If node emits light, MapBlock requires lighting update
1969                                 if(nodemgr->get(n0).light_source != 0)
1970                                         lighting_modified_blocks[block->getPos()] = block;
1971                         }
1972                         must_reflow.push_back(neighbors[i].p);
1973                 }
1974                 /* //for better relax  only same level
1975                 if (changed)  for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) {
1976                         if (!neighbors[ii].l) continue;
1977                         must_reflow.push_back(p0 + dirs[ii]);
1978                 }*/
1979         }
1980         /*
1981         if (loopcount)
1982                 infostream<<"Map::transformLiquids(): loopcount="<<loopcount
1983                 <<" reflow="<<must_reflow.size()
1984                 <<" queue="<< m_transforming_liquid.size()<<std::endl;
1985         */
1986         while (must_reflow.size() > 0)
1987                 m_transforming_liquid.push_back(must_reflow.pop_front());
1988         while (must_reflow_second.size() > 0)
1989                 m_transforming_liquid.push_back(must_reflow_second.pop_front());
1990         updateLighting(lighting_modified_blocks, modified_blocks);
1991 }
1992
1993 void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
1994 {
1995
1996         if (g_settings->getBool("liquid_finite"))
1997                 return Map::transformLiquidsFinite(modified_blocks);
1998
1999         INodeDefManager *nodemgr = m_gamedef->ndef();
2000
2001         DSTACK(__FUNCTION_NAME);
2002         //TimeTaker timer("transformLiquids()");
2003
2004         u32 loopcount = 0;
2005         u32 initial_size = m_transforming_liquid.size();
2006
2007         /*if(initial_size != 0)
2008                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
2009
2010         // list of nodes that due to viscosity have not reached their max level height
2011         UniqueQueue<v3s16> must_reflow;
2012
2013         // List of MapBlocks that will require a lighting update (due to lava)
2014         std::map<v3s16, MapBlock*> lighting_modified_blocks;
2015
2016         u16 loop_max = g_settings->getU16("liquid_loop_max");
2017
2018         while(m_transforming_liquid.size() != 0)
2019         {
2020                 // This should be done here so that it is done when continue is used
2021                 if(loopcount >= initial_size || loopcount >= loop_max)
2022                         break;
2023                 loopcount++;
2024
2025                 /*
2026                         Get a queued transforming liquid node
2027                 */
2028                 v3s16 p0 = m_transforming_liquid.pop_front();
2029
2030                 MapNode n0 = getNodeNoEx(p0);
2031
2032                 /*
2033                         Collect information about current node
2034                  */
2035                 s8 liquid_level = -1;
2036                 content_t liquid_kind = CONTENT_IGNORE;
2037                 LiquidType liquid_type = nodemgr->get(n0).liquid_type;
2038                 switch (liquid_type) {
2039                         case LIQUID_SOURCE:
2040                                 liquid_level = LIQUID_LEVEL_SOURCE;
2041                                 liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
2042                                 break;
2043                         case LIQUID_FLOWING:
2044                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
2045                                 liquid_kind = n0.getContent();
2046                                 break;
2047                         case LIQUID_NONE:
2048                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
2049                                 // continue with the next node.
2050                                 if (n0.getContent() != CONTENT_AIR)
2051                                         continue;
2052                                 liquid_kind = CONTENT_AIR;
2053                                 break;
2054                 }
2055
2056                 /*
2057                         Collect information about the environment
2058                  */
2059                 const v3s16 *dirs = g_6dirs;
2060                 NodeNeighbor sources[6]; // surrounding sources
2061                 int num_sources = 0;
2062                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
2063                 int num_flows = 0;
2064                 NodeNeighbor airs[6]; // surrounding air
2065                 int num_airs = 0;
2066                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
2067                 int num_neutrals = 0;
2068                 bool flowing_down = false;
2069                 for (u16 i = 0; i < 6; i++) {
2070                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
2071                         switch (i) {
2072                                 case 1:
2073                                         nt = NEIGHBOR_UPPER;
2074                                         break;
2075                                 case 4:
2076                                         nt = NEIGHBOR_LOWER;
2077                                         break;
2078                         }
2079                         v3s16 npos = p0 + dirs[i];
2080                         NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
2081                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
2082                                 case LIQUID_NONE:
2083                                         if (nb.n.getContent() == CONTENT_AIR) {
2084                                                 airs[num_airs++] = nb;
2085                                                 // if the current node is a water source the neighbor
2086                                                 // should be enqueded for transformation regardless of whether the
2087                                                 // current node changes or not.
2088                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
2089                                                         m_transforming_liquid.push_back(npos);
2090                                                 // if the current node happens to be a flowing node, it will start to flow down here.
2091                                                 if (nb.t == NEIGHBOR_LOWER) {
2092                                                         flowing_down = true;
2093                                                 }
2094                                         } else {
2095                                                 neutrals[num_neutrals++] = nb;
2096                                         }
2097                                         break;
2098                                 case LIQUID_SOURCE:
2099                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
2100                                         if (liquid_kind == CONTENT_AIR)
2101                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
2102                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
2103                                                 neutrals[num_neutrals++] = nb;
2104                                         } else {
2105                                                 // Do not count bottom source, it will screw things up
2106                                                 if(dirs[i].Y != -1)
2107                                                         sources[num_sources++] = nb;
2108                                         }
2109                                         break;
2110                                 case LIQUID_FLOWING:
2111                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
2112                                         if (liquid_kind == CONTENT_AIR)
2113                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
2114                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
2115                                                 neutrals[num_neutrals++] = nb;
2116                                         } else {
2117                                                 flows[num_flows++] = nb;
2118                                                 if (nb.t == NEIGHBOR_LOWER)
2119                                                         flowing_down = true;
2120                                         }
2121                                         break;
2122                         }
2123                 }
2124
2125                 /*
2126                         decide on the type (and possibly level) of the current node
2127                  */
2128                 content_t new_node_content;
2129                 s8 new_node_level = -1;
2130                 s8 max_node_level = -1;
2131                 if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
2132                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
2133                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
2134                         // it's perfectly safe to use liquid_kind here to determine the new node content.
2135                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
2136                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
2137                         // liquid_kind is set properly, see above
2138                         new_node_content = liquid_kind;
2139                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
2140                 } else {
2141                         // no surrounding sources, so get the maximum level that can flow into this node
2142                         for (u16 i = 0; i < num_flows; i++) {
2143                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
2144                                 switch (flows[i].t) {
2145                                         case NEIGHBOR_UPPER:
2146                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
2147                                                         max_node_level = LIQUID_LEVEL_MAX;
2148                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
2149                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
2150                                                 } else if (nb_liquid_level > max_node_level)
2151                                                         max_node_level = nb_liquid_level;
2152                                                 break;
2153                                         case NEIGHBOR_LOWER:
2154                                                 break;
2155                                         case NEIGHBOR_SAME_LEVEL:
2156                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
2157                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
2158                                                         max_node_level = nb_liquid_level - 1;
2159                                                 }
2160                                                 break;
2161                                 }
2162                         }
2163
2164                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
2165                         if (viscosity > 1 && max_node_level != liquid_level) {
2166                                 // amount to gain, limited by viscosity
2167                                 // must be at least 1 in absolute value
2168                                 s8 level_inc = max_node_level - liquid_level;
2169                                 if (level_inc < -viscosity || level_inc > viscosity)
2170                                         new_node_level = liquid_level + level_inc/viscosity;
2171                                 else if (level_inc < 0)
2172                                         new_node_level = liquid_level - 1;
2173                                 else if (level_inc > 0)
2174                                         new_node_level = liquid_level + 1;
2175                                 if (new_node_level != max_node_level)
2176                                         must_reflow.push_back(p0);
2177                         } else
2178                                 new_node_level = max_node_level;
2179
2180                         u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1);
2181                         if (new_node_level >= (LIQUID_LEVEL_MAX+1-range))
2182                                 new_node_content = liquid_kind;
2183                         else
2184                                 new_node_content = CONTENT_AIR;
2185
2186                 }
2187
2188                 /*
2189                         check if anything has changed. if not, just continue with the next node.
2190                  */
2191                 if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
2192                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
2193                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
2194                                                                                  == flowing_down)))
2195                         continue;
2196
2197
2198                 /*
2199                         update the current node
2200                  */
2201                 MapNode n00 = n0;
2202                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
2203                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
2204                         // set level to last 3 bits, flowing down bit to 4th bit
2205                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
2206                 } else {
2207                         // set the liquid level and flow bit to 0
2208                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
2209                 }
2210                 n0.setContent(new_node_content);
2211
2212                 // Find out whether there is a suspect for this action
2213                 std::string suspect;
2214                 if(m_gamedef->rollback()){
2215                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
2216                 }
2217
2218                 if(!suspect.empty()){
2219                         // Blame suspect
2220                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
2221                         // Get old node for rollback
2222                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
2223                         // Set node
2224                         setNode(p0, n0);
2225                         // Report
2226                         RollbackNode rollback_newnode(this, p0, m_gamedef);
2227                         RollbackAction action;
2228                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
2229                         m_gamedef->rollback()->reportAction(action);
2230                 } else {
2231                         // Set node
2232                         setNode(p0, n0);
2233                 }
2234
2235                 v3s16 blockpos = getNodeBlockPos(p0);
2236                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
2237                 if(block != NULL) {
2238                         modified_blocks[blockpos] =  block;
2239                         // If new or old node emits light, MapBlock requires lighting update
2240                         if(nodemgr->get(n0).light_source != 0 ||
2241                                         nodemgr->get(n00).light_source != 0)
2242                                 lighting_modified_blocks[block->getPos()] = block;
2243                 }
2244
2245                 /*
2246                         enqueue neighbors for update if neccessary
2247                  */
2248                 switch (nodemgr->get(n0.getContent()).liquid_type) {
2249                         case LIQUID_SOURCE:
2250                         case LIQUID_FLOWING:
2251                                 // make sure source flows into all neighboring nodes
2252                                 for (u16 i = 0; i < num_flows; i++)
2253                                         if (flows[i].t != NEIGHBOR_UPPER)
2254                                                 m_transforming_liquid.push_back(flows[i].p);
2255                                 for (u16 i = 0; i < num_airs; i++)
2256                                         if (airs[i].t != NEIGHBOR_UPPER)
2257                                                 m_transforming_liquid.push_back(airs[i].p);
2258                                 break;
2259                         case LIQUID_NONE:
2260                                 // this flow has turned to air; neighboring flows might need to do the same
2261                                 for (u16 i = 0; i < num_flows; i++)
2262                                         m_transforming_liquid.push_back(flows[i].p);
2263                                 break;
2264                 }
2265         }
2266         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
2267         while (must_reflow.size() > 0)
2268                 m_transforming_liquid.push_back(must_reflow.pop_front());
2269         updateLighting(lighting_modified_blocks, modified_blocks);
2270 }
2271
2272 NodeMetadata* Map::getNodeMetadata(v3s16 p)
2273 {
2274         v3s16 blockpos = getNodeBlockPos(p);
2275         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2276         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2277         if(!block){
2278                 infostream<<"Map::getNodeMetadata(): Need to emerge "
2279                                 <<PP(blockpos)<<std::endl;
2280                 block = emergeBlock(blockpos, false);
2281         }
2282         if(!block)
2283         {
2284                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
2285                                 <<std::endl;
2286                 return NULL;
2287         }
2288         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
2289         return meta;
2290 }
2291
2292 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
2293 {
2294         v3s16 blockpos = getNodeBlockPos(p);
2295         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2296         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2297         if(!block){
2298                 infostream<<"Map::setNodeMetadata(): Need to emerge "
2299                                 <<PP(blockpos)<<std::endl;
2300                 block = emergeBlock(blockpos, false);
2301         }
2302         if(!block)
2303         {
2304                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
2305                                 <<std::endl;
2306                 return;
2307         }
2308         block->m_node_metadata.set(p_rel, meta);
2309 }
2310
2311 void Map::removeNodeMetadata(v3s16 p)
2312 {
2313         v3s16 blockpos = getNodeBlockPos(p);
2314         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2315         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2316         if(block == NULL)
2317         {
2318                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
2319                                 <<std::endl;
2320                 return;
2321         }
2322         block->m_node_metadata.remove(p_rel);
2323 }
2324
2325 NodeTimer Map::getNodeTimer(v3s16 p)
2326 {
2327         v3s16 blockpos = getNodeBlockPos(p);
2328         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2329         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2330         if(!block){
2331                 infostream<<"Map::getNodeTimer(): Need to emerge "
2332                                 <<PP(blockpos)<<std::endl;
2333                 block = emergeBlock(blockpos, false);
2334         }
2335         if(!block)
2336         {
2337                 infostream<<"WARNING: Map::getNodeTimer(): Block not found"
2338                                 <<std::endl;
2339                 return NodeTimer();
2340         }
2341         NodeTimer t = block->m_node_timers.get(p_rel);
2342         return t;
2343 }
2344
2345 void Map::setNodeTimer(v3s16 p, NodeTimer t)
2346 {
2347         v3s16 blockpos = getNodeBlockPos(p);
2348         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2349         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2350         if(!block){
2351                 infostream<<"Map::setNodeTimer(): Need to emerge "
2352                                 <<PP(blockpos)<<std::endl;
2353                 block = emergeBlock(blockpos, false);
2354         }
2355         if(!block)
2356         {
2357                 infostream<<"WARNING: Map::setNodeTimer(): Block not found"
2358                                 <<std::endl;
2359                 return;
2360         }
2361         block->m_node_timers.set(p_rel, t);
2362 }
2363
2364 void Map::removeNodeTimer(v3s16 p)
2365 {
2366         v3s16 blockpos = getNodeBlockPos(p);
2367         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2368         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2369         if(block == NULL)
2370         {
2371                 infostream<<"WARNING: Map::removeNodeTimer(): Block not found"
2372                                 <<std::endl;
2373                 return;
2374         }
2375         block->m_node_timers.remove(p_rel);
2376 }
2377
2378 s16 Map::getHeat(v3s16 p)
2379 {
2380         MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
2381         if(block != NULL) {
2382                 return block->heat;
2383         }
2384         //errorstream << "No heat for " << p.X<<"," << p.Z << std::endl;
2385         return 0;
2386 }
2387
2388 s16 Map::getHumidity(v3s16 p)
2389 {
2390         MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
2391         if(block != NULL) {
2392                 return block->humidity;
2393         }
2394         //errorstream << "No humidity for " << p.X<<"," << p.Z << std::endl;
2395         return 0;
2396 }
2397
2398 /*
2399         ServerMap
2400 */
2401 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
2402         Map(dout_server, gamedef),
2403         m_seed(0),
2404         m_map_metadata_changed(true),
2405         m_database(NULL),
2406         m_database_read(NULL),
2407         m_database_write(NULL)
2408 {
2409         verbosestream<<__FUNCTION_NAME<<std::endl;
2410
2411         m_emerge = emerge;
2412         m_mgparams = m_emerge->getParamsFromSettings(g_settings);
2413         if (!m_mgparams)
2414                 m_mgparams = new MapgenV6Params();
2415
2416         m_seed = m_mgparams->seed;
2417
2418         if (g_settings->get("fixed_map_seed").empty())
2419         {
2420                 m_seed = (((u64)(myrand() & 0xffff) << 0)
2421                                 | ((u64)(myrand() & 0xffff) << 16)
2422                                 | ((u64)(myrand() & 0xffff) << 32)
2423                                 | ((u64)(myrand() & 0xffff) << 48));
2424                 m_mgparams->seed = m_seed;
2425         }
2426
2427         /*
2428                 Experimental and debug stuff
2429         */
2430
2431         {
2432         }
2433
2434         /*
2435                 Try to load map; if not found, create a new one.
2436         */
2437
2438         m_savedir = savedir;
2439         m_map_saving_enabled = false;
2440
2441         try
2442         {
2443                 // If directory exists, check contents and load if possible
2444                 if(fs::PathExists(m_savedir))
2445                 {
2446                         // If directory is empty, it is safe to save into it.
2447                         if(fs::GetDirListing(m_savedir).size() == 0)
2448                         {
2449                                 infostream<<"ServerMap: Empty save directory is valid."
2450                                                 <<std::endl;
2451                                 m_map_saving_enabled = true;
2452                         }
2453                         else
2454                         {
2455                                 try{
2456                                         // Load map metadata (seed, chunksize)
2457                                         loadMapMeta();
2458                                 }
2459                                 catch(SettingNotFoundException &e){
2460                                         infostream<<"ServerMap:  Some metadata not found."
2461                                                           <<" Using default settings."<<std::endl;
2462                                 }
2463                                 catch(FileNotGoodException &e){
2464                                         infostream<<"WARNING: Could not load map metadata"
2465                                                         //<<" Disabling chunk-based generator."
2466                                                         <<std::endl;
2467                                         //m_chunksize = 0;
2468                                 }
2469
2470                                 infostream<<"ServerMap: Successfully loaded map "
2471                                                 <<"metadata from "<<savedir
2472                                                 <<", assuming valid save directory."
2473                                                 <<" seed="<<m_seed<<"."
2474                                                 <<std::endl;
2475
2476                                 m_map_saving_enabled = true;
2477                                 // Map loaded, not creating new one
2478                                 return;
2479                         }
2480                 }
2481                 // If directory doesn't exist, it is safe to save to it
2482                 else{
2483                         m_map_saving_enabled = true;
2484                 }
2485         }
2486         catch(std::exception &e)
2487         {
2488                 infostream<<"WARNING: ServerMap: Failed to load map from "<<savedir
2489                                 <<", exception: "<<e.what()<<std::endl;
2490                 infostream<<"Please remove the map or fix it."<<std::endl;
2491                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
2492         }
2493
2494         infostream<<"Initializing new map."<<std::endl;
2495
2496         // Create zero sector
2497         emergeSector(v2s16(0,0));
2498
2499         // Initially write whole map
2500         save(MOD_STATE_CLEAN);
2501 }
2502
2503 ServerMap::~ServerMap()
2504 {
2505         verbosestream<<__FUNCTION_NAME<<std::endl;
2506
2507         try
2508         {
2509                 if(m_map_saving_enabled)
2510                 {
2511                         // Save only changed parts
2512                         save(MOD_STATE_WRITE_AT_UNLOAD);
2513                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2514                 }
2515                 else
2516                 {
2517                         infostream<<"ServerMap: Map not saved"<<std::endl;
2518                 }
2519         }
2520         catch(std::exception &e)
2521         {
2522                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2523                                 <<", exception: "<<e.what()<<std::endl;
2524         }
2525
2526         /*
2527                 Close database if it was opened
2528         */
2529         if(m_database_read)
2530                 sqlite3_finalize(m_database_read);
2531         if(m_database_write)
2532                 sqlite3_finalize(m_database_write);
2533         if(m_database)
2534                 sqlite3_close(m_database);
2535
2536 #if 0
2537         /*
2538                 Free all MapChunks
2539         */
2540         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2541         for(; i.atEnd() == false; i++)
2542         {
2543                 MapChunk *chunk = i.getNode()->getValue();
2544                 delete chunk;
2545         }
2546 #endif
2547
2548         delete m_mgparams;
2549 }
2550
2551 bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
2552 {
2553         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2554         EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
2555
2556         s16 chunksize = m_mgparams->chunksize;
2557         s16 coffset = -chunksize / 2;
2558         v3s16 chunk_offset(coffset, coffset, coffset);
2559         v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
2560         v3s16 blockpos_min = blockpos_div * chunksize;
2561         v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
2562         blockpos_min += chunk_offset;
2563         blockpos_max += chunk_offset;
2564
2565         v3s16 extra_borders(1,1,1);
2566
2567         // Do nothing if not inside limits (+-1 because of neighbors)
2568         if(blockpos_over_limit(blockpos_min - extra_borders) ||
2569                 blockpos_over_limit(blockpos_max + extra_borders))
2570                 return false;
2571
2572         data->seed = m_seed;
2573         data->blockpos_min = blockpos_min;
2574         data->blockpos_max = blockpos_max;
2575         data->blockpos_requested = blockpos;
2576         data->nodedef = m_gamedef->ndef();
2577
2578         /*
2579                 Create the whole area of this and the neighboring blocks
2580         */
2581         {
2582                 //TimeTaker timer("initBlockMake() create area");
2583
2584                 for(s16 x=blockpos_min.X-extra_borders.X;
2585                                 x<=blockpos_max.X+extra_borders.X; x++)
2586                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2587                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2588                 {
2589                         v2s16 sectorpos(x, z);
2590                         // Sector metadata is loaded from disk if not already loaded.
2591                         ServerMapSector *sector = createSector(sectorpos);
2592                         assert(sector);
2593
2594                         for(s16 y=blockpos_min.Y-extra_borders.Y;
2595                                         y<=blockpos_max.Y+extra_borders.Y; y++)
2596                         {
2597                                 v3s16 p(x,y,z);
2598                                 //MapBlock *block = createBlock(p);
2599                                 // 1) get from memory, 2) load from disk
2600                                 MapBlock *block = emergeBlock(p, false);
2601                                 // 3) create a blank one
2602                                 if(block == NULL)
2603                                 {
2604                                         block = createBlock(p);
2605
2606                                         /*
2607                                                 Block gets sunlight if this is true.
2608
2609                                                 Refer to the map generator heuristics.
2610                                         */
2611                                         bool ug = m_emerge->isBlockUnderground(p);
2612                                         block->setIsUnderground(ug);
2613                                 }
2614
2615                                 // Lighting will not be valid after make_chunk is called
2616                                 block->setLightingExpired(true);
2617                                 // Lighting will be calculated
2618                                 //block->setLightingExpired(false);
2619                         }
2620                 }
2621         }
2622
2623         /*
2624                 Now we have a big empty area.
2625
2626                 Make a ManualMapVoxelManipulator that contains this and the
2627                 neighboring blocks
2628         */
2629
2630         // The area that contains this block and it's neighbors
2631         v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
2632         v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
2633
2634         data->vmanip = new ManualMapVoxelManipulator(this);
2635         //data->vmanip->setMap(this);
2636
2637         // Add the area
2638         {
2639                 //TimeTaker timer("initBlockMake() initialEmerge");
2640                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max, false);
2641         }
2642         
2643         // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
2644 /*      for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
2645                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
2646                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
2647                                 core::map<v3s16, u8>::Node *n;
2648                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
2649                                 if (n == NULL)
2650                                         continue;
2651                                 u8 flags = n->getValue();
2652                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
2653                                 n->setValue(flags);
2654                         }
2655                 }
2656         }*/
2657
2658         // Data is ready now.
2659         return true;
2660 }
2661
2662 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
2663                 std::map<v3s16, MapBlock*> &changed_blocks)
2664 {
2665         v3s16 blockpos_min = data->blockpos_min;
2666         v3s16 blockpos_max = data->blockpos_max;
2667         v3s16 blockpos_requested = data->blockpos_requested;
2668         /*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
2669                         <<blockpos_requested.Y<<","
2670                         <<blockpos_requested.Z<<")"<<std::endl;*/
2671
2672         v3s16 extra_borders(1,1,1);
2673
2674         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2675
2676         /*infostream<<"Resulting vmanip:"<<std::endl;
2677         data->vmanip.print(infostream);*/
2678
2679         // Make sure affected blocks are loaded
2680         for(s16 x=blockpos_min.X-extra_borders.X;
2681                         x<=blockpos_max.X+extra_borders.X; x++)
2682         for(s16 z=blockpos_min.Z-extra_borders.Z;
2683                         z<=blockpos_max.Z+extra_borders.Z; z++)
2684         for(s16 y=blockpos_min.Y-extra_borders.Y;
2685                         y<=blockpos_max.Y+extra_borders.Y; y++)
2686         {
2687                 v3s16 p(x, y, z);
2688                 // Load from disk if not already in memory
2689                 emergeBlock(p, false);
2690         }
2691
2692         /*
2693                 Blit generated stuff to map
2694                 NOTE: blitBackAll adds nearly everything to changed_blocks
2695         */
2696         {
2697                 // 70ms @cs=8
2698                 //TimeTaker timer("finishBlockMake() blitBackAll");
2699                 data->vmanip->blitBackAll(&changed_blocks);
2700         }
2701
2702         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
2703
2704         /*
2705                 Copy transforming liquid information
2706         */
2707         while(data->transforming_liquid.size() > 0)
2708         {
2709                 v3s16 p = data->transforming_liquid.pop_front();
2710                 m_transforming_liquid.push_back(p);
2711         }
2712
2713         /*
2714                 Do stuff in central blocks
2715         */
2716
2717         /*
2718                 Update lighting
2719         */
2720         {
2721 #if 0
2722                 TimeTaker t("finishBlockMake lighting update");
2723
2724                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2725
2726                 // Center blocks
2727                 for(s16 x=blockpos_min.X-extra_borders.X;
2728                                 x<=blockpos_max.X+extra_borders.X; x++)
2729                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2730                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2731                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2732                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2733                 {
2734                         v3s16 p(x, y, z);
2735                         MapBlock *block = getBlockNoCreateNoEx(p);
2736                         assert(block);
2737                         lighting_update_blocks.insert(block->getPos(), block);
2738                 }
2739
2740                 updateLighting(lighting_update_blocks, changed_blocks);
2741 #endif
2742
2743                 /*
2744                         Set lighting to non-expired state in all of them.
2745                         This is cheating, but it is not fast enough if all of them
2746                         would actually be updated.
2747                 */
2748                 for(s16 x=blockpos_min.X-extra_borders.X;
2749                                 x<=blockpos_max.X+extra_borders.X; x++)
2750                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2751                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2752                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2753                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2754                 {
2755                         v3s16 p(x, y, z);
2756                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2757                 }
2758
2759 #if 0
2760                 if(enable_mapgen_debug_info == false)
2761                         t.stop(true); // Hide output
2762 #endif
2763         }
2764
2765         /*
2766                 Go through changed blocks
2767         */
2768         for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
2769                         i != changed_blocks.end(); ++i)
2770         {
2771                 MapBlock *block = i->second;
2772                 assert(block);
2773                 /*
2774                         Update day/night difference cache of the MapBlocks
2775                 */
2776                 block->expireDayNightDiff();
2777                 /*
2778                         Set block as modified
2779                 */
2780                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2781                                 "finishBlockMake expireDayNightDiff");
2782         }
2783
2784         /*
2785                 Set central blocks as generated
2786         */
2787         for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
2788         for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
2789         for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
2790         {
2791                 v3s16 p(x, y, z);
2792                 MapBlock *block = getBlockNoCreateNoEx(p);
2793                 assert(block);
2794                 block->setGenerated(true);
2795         }
2796
2797         /*
2798                 Save changed parts of map
2799                 NOTE: Will be saved later.
2800         */
2801         //save(MOD_STATE_WRITE_AT_UNLOAD);
2802
2803         /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
2804                         <<","<<blockpos_requested.Y<<","
2805                         <<blockpos_requested.Z<<")"<<std::endl;*/
2806 #if 0
2807         if(enable_mapgen_debug_info)
2808         {
2809                 /*
2810                         Analyze resulting blocks
2811                 */
2812                 /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
2813                 for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
2814                 for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
2815                 for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
2816                 for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
2817                 for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
2818                 {
2819                         v3s16 p = v3s16(x,y,z);
2820                         MapBlock *block = getBlockNoCreateNoEx(p);
2821                         char spos[20];
2822                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2823                         infostream<<"Generated "<<spos<<": "
2824                                         <<analyze_block(block)<<std::endl;
2825                 }
2826         }
2827 #endif
2828
2829         MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);
2830         assert(block);
2831
2832         return block;
2833 }
2834
2835 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2836 {
2837         DSTACKF("%s: p2d=(%d,%d)",
2838                         __FUNCTION_NAME,
2839                         p2d.X, p2d.Y);
2840
2841         /*
2842                 Check if it exists already in memory
2843         */
2844         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2845         if(sector != NULL)
2846                 return sector;
2847
2848         /*
2849                 Try to load it from disk (with blocks)
2850         */
2851         //if(loadSectorFull(p2d) == true)
2852
2853         /*
2854                 Try to load metadata from disk
2855         */
2856 #if 0
2857         if(loadSectorMeta(p2d) == true)
2858         {
2859                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2860                 if(sector == NULL)
2861                 {
2862                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2863                         throw InvalidPositionException("");
2864                 }
2865                 return sector;
2866         }
2867 #endif
2868         /*
2869                 Do not create over-limit
2870         */
2871         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2872         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2873         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2874         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2875                 throw InvalidPositionException("createSector(): pos. over limit");
2876
2877         /*
2878                 Generate blank sector
2879         */
2880
2881         sector = new ServerMapSector(this, p2d, m_gamedef);
2882
2883         // Sector position on map in nodes
2884         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2885
2886         /*
2887                 Insert to container
2888         */
2889         m_sectors[p2d] = sector;
2890
2891         return sector;
2892 }
2893
2894 #if 0
2895 /*
2896         This is a quick-hand function for calling makeBlock().
2897 */
2898 MapBlock * ServerMap::generateBlock(
2899                 v3s16 p,
2900                 std::map<v3s16, MapBlock*> &modified_blocks
2901 )
2902 {
2903         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2904
2905         /*infostream<<"generateBlock(): "
2906                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2907                         <<std::endl;*/
2908
2909         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2910
2911         TimeTaker timer("generateBlock");
2912
2913         //MapBlock *block = original_dummy;
2914
2915         v2s16 p2d(p.X, p.Z);
2916         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2917
2918         /*
2919                 Do not generate over-limit
2920         */
2921         if(blockpos_over_limit(p))
2922         {
2923                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2924                 throw InvalidPositionException("generateBlock(): pos. over limit");
2925         }
2926
2927         /*
2928                 Create block make data
2929         */
2930         BlockMakeData data;
2931         initBlockMake(&data, p);
2932
2933         /*
2934                 Generate block
2935         */
2936         {
2937                 TimeTaker t("mapgen::make_block()");
2938                 mapgen->makeChunk(&data);
2939                 //mapgen::make_block(&data);
2940
2941                 if(enable_mapgen_debug_info == false)
2942                         t.stop(true); // Hide output
2943         }
2944
2945         /*
2946                 Blit data back on map, update lighting, add mobs and whatever this does
2947         */
2948         finishBlockMake(&data, modified_blocks);
2949
2950         /*
2951                 Get central block
2952         */
2953         MapBlock *block = getBlockNoCreateNoEx(p);
2954
2955 #if 0
2956         /*
2957                 Check result
2958         */
2959         if(block)
2960         {
2961                 bool erroneus_content = false;
2962                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2963                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2964                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2965                 {
2966                         v3s16 p(x0,y0,z0);
2967                         MapNode n = block->getNode(p);
2968                         if(n.getContent() == CONTENT_IGNORE)
2969                         {
2970                                 infostream<<"CONTENT_IGNORE at "
2971                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2972                                                 <<std::endl;
2973                                 erroneus_content = true;
2974                                 assert(0);
2975                         }
2976                 }
2977                 if(erroneus_content)
2978                 {
2979                         assert(0);
2980                 }
2981         }
2982 #endif
2983
2984 #if 0
2985         /*
2986                 Generate a completely empty block
2987         */
2988         if(block)
2989         {
2990                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2991                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2992                 {
2993                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2994                         {
2995                                 MapNode n;
2996                                 n.setContent(CONTENT_AIR);
2997                                 block->setNode(v3s16(x0,y0,z0), n);
2998                         }
2999                 }
3000         }
3001 #endif
3002
3003         if(enable_mapgen_debug_info == false)
3004                 timer.stop(true); // Hide output
3005
3006         return block;
3007 }
3008 #endif
3009
3010 MapBlock * ServerMap::createBlock(v3s16 p)
3011 {
3012         DSTACKF("%s: p=(%d,%d,%d)",
3013                         __FUNCTION_NAME, p.X, p.Y, p.Z);
3014
3015         /*
3016                 Do not create over-limit
3017         */
3018         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3019         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3020         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3021         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3022         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3023         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
3024                 throw InvalidPositionException("createBlock(): pos. over limit");
3025
3026         v2s16 p2d(p.X, p.Z);
3027         s16 block_y = p.Y;
3028         /*
3029                 This will create or load a sector if not found in memory.
3030                 If block exists on disk, it will be loaded.
3031
3032                 NOTE: On old save formats, this will be slow, as it generates
3033                       lighting on blocks for them.
3034         */
3035         ServerMapSector *sector;
3036         try{
3037                 sector = (ServerMapSector*)createSector(p2d);
3038                 assert(sector->getId() == MAPSECTOR_SERVER);
3039         }
3040         catch(InvalidPositionException &e)
3041         {
3042                 infostream<<"createBlock: createSector() failed"<<std::endl;
3043                 throw e;
3044         }
3045         /*
3046                 NOTE: This should not be done, or at least the exception
3047                 should not be passed on as std::exception, because it
3048                 won't be catched at all.
3049         */
3050         /*catch(std::exception &e)
3051         {
3052                 infostream<<"createBlock: createSector() failed: "
3053                                 <<e.what()<<std::endl;
3054                 throw e;
3055         }*/
3056
3057         /*
3058                 Try to get a block from the sector
3059         */
3060
3061         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
3062         if(block)
3063         {
3064                 if(block->isDummy())
3065                         block->unDummify();
3066                 return block;
3067         }
3068         // Create blank
3069         block = sector->createBlankBlock(block_y);
3070
3071         return block;
3072 }
3073
3074 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
3075 {
3076         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
3077                         __FUNCTION_NAME,
3078                         p.X, p.Y, p.Z, create_blank);
3079
3080         {
3081                 MapBlock *block = getBlockNoCreateNoEx(p);
3082                 if(block && block->isDummy() == false)
3083                         return block;
3084         }
3085
3086         {
3087                 MapBlock *block = loadBlock(p);
3088                 if(block)
3089                         return block;
3090         }
3091
3092         if (create_blank) {
3093                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
3094                 MapBlock *block = sector->createBlankBlock(p.Y);
3095
3096                 return block;
3097         }
3098         /*if(allow_generate)
3099         {
3100                 std::map<v3s16, MapBlock*> modified_blocks;
3101                 MapBlock *block = generateBlock(p, modified_blocks);
3102                 if(block)
3103                 {
3104                         MapEditEvent event;
3105                         event.type = MEET_OTHER;
3106                         event.p = p;
3107
3108                         // Copy modified_blocks to event
3109                         for(std::map<v3s16, MapBlock*>::iterator
3110                                         i = modified_blocks.begin();
3111                                         i != modified_blocks.end(); ++i)
3112                         {
3113                                 event.modified_blocks.insert(i->first);
3114                         }
3115
3116                         // Queue event
3117                         dispatchEvent(&event);
3118
3119                         return block;
3120                 }
3121         }*/
3122
3123         return NULL;
3124 }
3125
3126 s16 ServerMap::findGroundLevel(v2s16 p2d)
3127 {
3128 #if 0
3129         /*
3130                 Uh, just do something random...
3131         */
3132         // Find existing map from top to down
3133         s16 max=63;
3134         s16 min=-64;
3135         v3s16 p(p2d.X, max, p2d.Y);
3136         for(; p.Y>min; p.Y--)
3137         {
3138                 MapNode n = getNodeNoEx(p);
3139                 if(n.getContent() != CONTENT_IGNORE)
3140                         break;
3141         }
3142         if(p.Y == min)
3143                 goto plan_b;
3144         // If this node is not air, go to plan b
3145         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
3146                 goto plan_b;
3147         // Search existing walkable and return it
3148         for(; p.Y>min; p.Y--)
3149         {
3150                 MapNode n = getNodeNoEx(p);
3151                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
3152                         return p.Y;
3153         }
3154
3155         // Move to plan b
3156 plan_b:
3157 #endif
3158
3159         /*
3160                 Determine from map generator noise functions
3161         */
3162
3163         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
3164         return level;
3165
3166         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
3167         //return (s16)level;
3168 }
3169
3170 void ServerMap::createDatabase() {
3171         int e;
3172         assert(m_database);
3173         e = sqlite3_exec(m_database,
3174                 "CREATE TABLE IF NOT EXISTS `blocks` ("
3175                         "`pos` INT NOT NULL PRIMARY KEY,"
3176                         "`data` BLOB"
3177                 ");"
3178         , NULL, NULL, NULL);
3179         if(e == SQLITE_ABORT)
3180                 throw FileNotGoodException("Could not create database structure");
3181         else
3182                 infostream<<"ServerMap: Database structure was created";
3183 }
3184
3185 void ServerMap::verifyDatabase() {
3186         if(m_database)
3187                 return;
3188
3189         {
3190                 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
3191                 bool needs_create = false;
3192                 int d;
3193
3194                 /*
3195                         Open the database connection
3196                 */
3197
3198                 createDirs(m_savedir);
3199
3200                 if(!fs::PathExists(dbp))
3201                         needs_create = true;
3202
3203                 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
3204                 if(d != SQLITE_OK) {
3205                         infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
3206                         throw FileNotGoodException("Cannot open database file");
3207                 }
3208
3209                 if(needs_create)
3210                         createDatabase();
3211
3212                 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
3213                 if(d != SQLITE_OK) {
3214                         infostream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3215                         throw FileNotGoodException("Cannot prepare read statement");
3216                 }
3217
3218                 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
3219                 if(d != SQLITE_OK) {
3220                         infostream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3221                         throw FileNotGoodException("Cannot prepare write statement");
3222                 }
3223
3224                 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
3225                 if(d != SQLITE_OK) {
3226                         infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3227                         throw FileNotGoodException("Cannot prepare read statement");
3228                 }
3229
3230                 infostream<<"ServerMap: Database opened"<<std::endl;
3231         }
3232 }
3233
3234 bool ServerMap::loadFromFolders() {
3235         if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
3236                 return true;
3237         return false;
3238 }
3239
3240 sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
3241         return (sqlite3_int64)pos.Z*16777216 +
3242                 (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
3243 }
3244
3245 void ServerMap::createDirs(std::string path)
3246 {
3247         if(fs::CreateAllDirs(path) == false)
3248         {
3249                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
3250                                 <<"\""<<path<<"\""<<std::endl;
3251                 throw BaseException("ServerMap failed to create directory");
3252         }
3253 }
3254
3255 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
3256 {
3257         char cc[9];
3258         switch(layout)
3259         {
3260                 case 1:
3261                         snprintf(cc, 9, "%.4x%.4x",
3262                                 (unsigned int)pos.X&0xffff,
3263                                 (unsigned int)pos.Y&0xffff);
3264
3265                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
3266                 case 2:
3267                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
3268                                 (unsigned int)pos.X&0xfff,
3269                                 (unsigned int)pos.Y&0xfff);
3270
3271                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
3272                 default:
3273                         assert(false);
3274         }
3275 }
3276
3277 v2s16 ServerMap::getSectorPos(std::string dirname)
3278 {
3279         unsigned int x, y;
3280         int r;
3281         std::string component;
3282         fs::RemoveLastPathComponent(dirname, &component, 1);
3283         if(component.size() == 8)
3284         {
3285                 // Old layout
3286                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
3287         }
3288         else if(component.size() == 3)
3289         {
3290                 // New layout
3291                 fs::RemoveLastPathComponent(dirname, &component, 2);
3292                 r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
3293                 // Sign-extend the 12 bit values up to 16 bits...
3294                 if(x&0x800) x|=0xF000;
3295                 if(y&0x800) y|=0xF000;
3296         }
3297         else
3298         {
3299                 assert(false);
3300         }
3301         assert(r == 2);
3302         v2s16 pos((s16)x, (s16)y);
3303         return pos;
3304 }
3305
3306 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
3307 {
3308         v2s16 p2d = getSectorPos(sectordir);
3309
3310         if(blockfile.size() != 4){
3311                 throw InvalidFilenameException("Invalid block filename");
3312         }
3313         unsigned int y;
3314         int r = sscanf(blockfile.c_str(), "%4x", &y);
3315         if(r != 1)
3316                 throw InvalidFilenameException("Invalid block filename");
3317         return v3s16(p2d.X, y, p2d.Y);
3318 }
3319
3320 std::string ServerMap::getBlockFilename(v3s16 p)
3321 {
3322         char cc[5];
3323         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
3324         return cc;
3325 }
3326
3327 void ServerMap::save(ModifiedState save_level)
3328 {
3329         DSTACK(__FUNCTION_NAME);
3330         if(m_map_saving_enabled == false)
3331         {
3332                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
3333                 return;
3334         }
3335
3336         if(save_level == MOD_STATE_CLEAN)
3337                 infostream<<"ServerMap: Saving whole map, this can take time."
3338                                 <<std::endl;
3339
3340         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
3341         {
3342                 saveMapMeta();
3343         }
3344
3345         // Profile modified reasons
3346         Profiler modprofiler;
3347
3348         u32 sector_meta_count = 0;
3349         u32 block_count = 0;
3350         u32 block_count_all = 0; // Number of blocks in memory
3351
3352         // Don't do anything with sqlite unless something is really saved
3353         bool save_started = false;
3354
3355         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
3356                 i != m_sectors.end(); ++i)
3357         {
3358                 ServerMapSector *sector = (ServerMapSector*)i->second;
3359                 assert(sector->getId() == MAPSECTOR_SERVER);
3360
3361                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
3362                 {
3363                         saveSectorMeta(sector);
3364                         sector_meta_count++;
3365                 }
3366                 std::list<MapBlock*> blocks;
3367                 sector->getBlocks(blocks);
3368
3369                 for(std::list<MapBlock*>::iterator j = blocks.begin();
3370                         j != blocks.end(); ++j)
3371                 {
3372                         MapBlock *block = *j;
3373
3374                         block_count_all++;
3375
3376                         if(block->getModified() >= (u32)save_level)
3377                         {
3378                                 // Lazy beginSave()
3379                                 if(!save_started){
3380                                         beginSave();
3381                                         save_started = true;
3382                                 }
3383
3384                                 modprofiler.add(block->getModifiedReason(), 1);
3385
3386                                 saveBlock(block);
3387                                 block_count++;
3388
3389                                 /*infostream<<"ServerMap: Written block ("
3390                                                 <<block->getPos().X<<","
3391                                                 <<block->getPos().Y<<","
3392                                                 <<block->getPos().Z<<")"
3393                                                 <<std::endl;*/
3394                         }
3395                 }
3396         }
3397         if(save_started)
3398                 endSave();
3399
3400         /*
3401                 Only print if something happened or saved whole map
3402         */
3403         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
3404                         || block_count != 0)
3405         {
3406                 infostream<<"ServerMap: Written: "
3407                                 <<sector_meta_count<<" sector metadata files, "
3408                                 <<block_count<<" block files"
3409                                 <<", "<<block_count_all<<" blocks in memory."
3410                                 <<std::endl;
3411                 PrintInfo(infostream); // ServerMap/ClientMap:
3412                 infostream<<"Blocks modified by: "<<std::endl;
3413                 modprofiler.print(infostream);
3414         }
3415 }
3416
3417 static s32 unsignedToSigned(s32 i, s32 max_positive)
3418 {
3419         if(i < max_positive)
3420                 return i;
3421         else
3422                 return i - 2*max_positive;
3423 }
3424
3425 // modulo of a negative number does not work consistently in C
3426 static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
3427 {
3428         if(i >= 0)
3429                 return i % mod;
3430         return mod - ((-i) % mod);
3431 }
3432
3433 v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
3434 {
3435         s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3436         i = (i - x) / 4096;
3437         s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3438         i = (i - y) / 4096;
3439         s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3440         return v3s16(x,y,z);
3441 }
3442
3443 void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
3444 {
3445         if(loadFromFolders()){
3446                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
3447                                 <<"all blocks that are stored in flat files"<<std::endl;
3448         }
3449
3450         {
3451                 verifyDatabase();
3452
3453                 while(sqlite3_step(m_database_list) == SQLITE_ROW)
3454                 {
3455                         sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
3456                         v3s16 p = getIntegerAsBlock(block_i);
3457                         //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
3458                         dst.push_back(p);
3459                 }
3460         }
3461 }
3462
3463 void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
3464 {
3465         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
3466                 si != m_sectors.end(); ++si)
3467         {
3468                 MapSector *sector = si->second;
3469
3470                 std::list<MapBlock*> blocks;
3471                 sector->getBlocks(blocks);
3472
3473                 for(std::list<MapBlock*>::iterator i = blocks.begin();
3474                                 i != blocks.end(); ++i)
3475                 {
3476                         MapBlock *block = (*i);
3477                         v3s16 p = block->getPos();
3478                         dst.push_back(p);
3479                 }
3480         }
3481 }
3482
3483 void ServerMap::saveMapMeta()
3484 {
3485         DSTACK(__FUNCTION_NAME);
3486
3487         /*infostream<<"ServerMap::saveMapMeta(): "
3488                         <<"seed="<<m_seed
3489                         <<std::endl;*/
3490
3491         createDirs(m_savedir);
3492
3493         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3494         std::ostringstream ss(std::ios_base::binary);
3495
3496         Settings params;
3497
3498         m_emerge->setParamsToSettings(&params);
3499         params.writeLines(ss);
3500
3501         ss<<"[end_of_params]\n";
3502
3503         if(!fs::safeWriteToFile(fullpath, ss.str()))
3504         {
3505                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3506                                 <<"could not write "<<fullpath<<std::endl;
3507                 throw FileNotGoodException("Cannot save chunk metadata");
3508         }
3509
3510         m_map_metadata_changed = false;
3511 }
3512
3513 void ServerMap::loadMapMeta()
3514 {
3515         DSTACK(__FUNCTION_NAME);
3516
3517         /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3518                         <<std::endl;*/
3519
3520         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3521         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3522         if(is.good() == false)
3523         {
3524                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3525                                 <<"could not open"<<fullpath<<std::endl;
3526                 throw FileNotGoodException("Cannot open map metadata");
3527         }
3528
3529         Settings params;
3530
3531         for(;;)
3532         {
3533                 if(is.eof())
3534                         throw SerializationError
3535                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3536                 std::string line;
3537                 std::getline(is, line);
3538                 std::string trimmedline = trim(line);
3539                 if(trimmedline == "[end_of_params]")
3540                         break;
3541                 params.parseConfigLine(line);
3542         }
3543         
3544         MapgenParams *mgparams;
3545         try {
3546                 mgparams = m_emerge->getParamsFromSettings(&params);
3547         } catch (SettingNotFoundException &e) {
3548                 infostream << "Couldn't get a setting from map_meta.txt: "
3549                                    << e.what() << std::endl;
3550                 mgparams = NULL;
3551         }
3552         
3553         if (mgparams) {
3554                 if (m_mgparams)
3555                         delete m_mgparams;
3556                 m_mgparams = mgparams;
3557                 m_seed = mgparams->seed;
3558         } else {
3559                 if (params.exists("seed")) {
3560                         m_seed = params.getU64("seed");
3561                         m_mgparams->seed = m_seed;
3562                 }
3563         }
3564
3565         verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3566 }
3567
3568 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3569 {
3570         DSTACK(__FUNCTION_NAME);
3571         // Format used for writing
3572         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3573         // Get destination
3574         v2s16 pos = sector->getPos();
3575         std::string dir = getSectorDir(pos);
3576         createDirs(dir);
3577
3578         std::string fullpath = dir + DIR_DELIM + "meta";
3579         std::ostringstream ss(std::ios_base::binary);
3580
3581         sector->serialize(ss, version);
3582
3583         if(!fs::safeWriteToFile(fullpath, ss.str()))
3584                 throw FileNotGoodException("Cannot write sector metafile");
3585
3586         sector->differs_from_disk = false;
3587 }
3588
3589 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3590 {
3591         DSTACK(__FUNCTION_NAME);
3592         // Get destination
3593         v2s16 p2d = getSectorPos(sectordir);
3594
3595         ServerMapSector *sector = NULL;
3596
3597         std::string fullpath = sectordir + DIR_DELIM + "meta";
3598         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3599         if(is.good() == false)
3600         {
3601                 // If the directory exists anyway, it probably is in some old
3602                 // format. Just go ahead and create the sector.
3603                 if(fs::PathExists(sectordir))
3604                 {
3605                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3606                                         <<fullpath<<" doesn't exist but directory does."
3607                                         <<" Continuing with a sector with no metadata."
3608                                         <<std::endl;*/
3609                         sector = new ServerMapSector(this, p2d, m_gamedef);
3610                         m_sectors[p2d] = sector;
3611                 }
3612                 else
3613                 {
3614                         throw FileNotGoodException("Cannot open sector metafile");
3615                 }
3616         }
3617         else
3618         {
3619                 sector = ServerMapSector::deSerialize
3620                                 (is, this, p2d, m_sectors, m_gamedef);
3621                 if(save_after_load)
3622                         saveSectorMeta(sector);
3623         }
3624
3625         sector->differs_from_disk = false;
3626
3627         return sector;
3628 }
3629
3630 bool ServerMap::loadSectorMeta(v2s16 p2d)
3631 {
3632         DSTACK(__FUNCTION_NAME);
3633
3634         MapSector *sector = NULL;
3635
3636         // The directory layout we're going to load from.
3637         //  1 - original sectors/xxxxzzzz/
3638         //  2 - new sectors2/xxx/zzz/
3639         //  If we load from anything but the latest structure, we will
3640         //  immediately save to the new one, and remove the old.
3641         int loadlayout = 1;
3642         std::string sectordir1 = getSectorDir(p2d, 1);
3643         std::string sectordir;
3644         if(fs::PathExists(sectordir1))
3645         {
3646                 sectordir = sectordir1;
3647         }
3648         else
3649         {
3650                 loadlayout = 2;
3651                 sectordir = getSectorDir(p2d, 2);
3652         }
3653
3654         try{
3655                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3656         }
3657         catch(InvalidFilenameException &e)
3658         {
3659                 return false;
3660         }
3661         catch(FileNotGoodException &e)
3662         {
3663                 return false;
3664         }
3665         catch(std::exception &e)
3666         {
3667                 return false;
3668         }
3669
3670         return true;
3671 }
3672
3673 #if 0
3674 bool ServerMap::loadSectorFull(v2s16 p2d)
3675 {
3676         DSTACK(__FUNCTION_NAME);
3677
3678         MapSector *sector = NULL;
3679
3680         // The directory layout we're going to load from.
3681         //  1 - original sectors/xxxxzzzz/
3682         //  2 - new sectors2/xxx/zzz/
3683         //  If we load from anything but the latest structure, we will
3684         //  immediately save to the new one, and remove the old.
3685         int loadlayout = 1;
3686         std::string sectordir1 = getSectorDir(p2d, 1);
3687         std::string sectordir;
3688         if(fs::PathExists(sectordir1))
3689         {
3690                 sectordir = sectordir1;
3691         }
3692         else
3693         {
3694                 loadlayout = 2;
3695                 sectordir = getSectorDir(p2d, 2);
3696         }
3697
3698         try{
3699                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3700         }
3701         catch(InvalidFilenameException &e)
3702         {
3703                 return false;
3704         }
3705         catch(FileNotGoodException &e)
3706         {
3707                 return false;
3708         }
3709         catch(std::exception &e)
3710         {
3711                 return false;
3712         }
3713
3714         /*
3715                 Load blocks
3716         */
3717         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3718                         (sectordir);
3719         std::vector<fs::DirListNode>::iterator i2;
3720         for(i2=list2.begin(); i2!=list2.end(); i2++)
3721         {
3722                 // We want files
3723                 if(i2->dir)
3724                         continue;
3725                 try{
3726                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3727                 }
3728                 catch(InvalidFilenameException &e)
3729                 {
3730                         // This catches unknown crap in directory
3731                 }
3732         }
3733
3734         if(loadlayout != 2)
3735         {
3736                 infostream<<"Sector converted to new layout - deleting "<<
3737                         sectordir1<<std::endl;
3738                 fs::RecursiveDelete(sectordir1);
3739         }
3740
3741         return true;
3742 }
3743 #endif
3744
3745 void ServerMap::beginSave() {
3746         verifyDatabase();
3747         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3748                 infostream<<"WARNING: beginSave() failed, saving might be slow.";
3749 }
3750
3751 void ServerMap::endSave() {
3752         verifyDatabase();
3753         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3754                 infostream<<"WARNING: endSave() failed, map might not have saved.";
3755 }
3756
3757 void ServerMap::saveBlock(MapBlock *block)
3758 {
3759         DSTACK(__FUNCTION_NAME);
3760         /*
3761                 Dummy blocks are not written
3762         */
3763         if(block->isDummy())
3764         {
3765                 /*v3s16 p = block->getPos();
3766                 infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3767                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3768                 return;
3769         }
3770
3771         // Format used for writing
3772         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3773         // Get destination
3774         v3s16 p3d = block->getPos();
3775
3776
3777 #if 0
3778         v2s16 p2d(p3d.X, p3d.Z);
3779         std::string sectordir = getSectorDir(p2d);
3780
3781         createDirs(sectordir);
3782
3783         std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
3784         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3785         if(o.good() == false)
3786                 throw FileNotGoodException("Cannot open block data");
3787 #endif
3788         /*
3789                 [0] u8 serialization version
3790                 [1] data
3791         */
3792
3793         verifyDatabase();
3794
3795         std::ostringstream o(std::ios_base::binary);
3796
3797         o.write((char*)&version, 1);
3798
3799         // Write basic data
3800         block->serialize(o, version, true);
3801
3802         // Write block to database
3803
3804         std::string tmp = o.str();
3805         const char *bytes = tmp.c_str();
3806
3807         bool success = true;
3808         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) {
3809                 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3810                 success = false;
3811         }
3812         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) { // TODO this mught not be the right length
3813                 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3814                 success = false;
3815         }
3816         int written = sqlite3_step(m_database_write);
3817         if(written != SQLITE_DONE) {
3818                 errorstream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3819                                 <<sqlite3_errmsg(m_database)<<std::endl;
3820                 success = false;
3821         }
3822         // Make ready for later reuse
3823         sqlite3_reset(m_database_write);
3824
3825         // We just wrote it to the disk so clear modified flag
3826         if (success)
3827                 block->resetModified();
3828 }
3829
3830 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3831 {
3832         DSTACK(__FUNCTION_NAME);
3833
3834         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3835         try{
3836
3837                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3838                 if(is.good() == false)
3839                         throw FileNotGoodException("Cannot open block file");
3840
3841                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3842                 v2s16 p2d(p3d.X, p3d.Z);
3843
3844                 assert(sector->getPos() == p2d);
3845
3846                 u8 version = SER_FMT_VER_INVALID;
3847                 is.read((char*)&version, 1);
3848
3849                 if(is.fail())
3850                         throw SerializationError("ServerMap::loadBlock(): Failed"
3851                                         " to read MapBlock version");
3852
3853                 /*u32 block_size = MapBlock::serializedLength(version);
3854                 SharedBuffer<u8> data(block_size);
3855                 is.read((char*)*data, block_size);*/
3856
3857                 // This will always return a sector because we're the server
3858                 //MapSector *sector = emergeSector(p2d);
3859
3860                 MapBlock *block = NULL;
3861                 bool created_new = false;
3862                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3863                 if(block == NULL)
3864                 {
3865                         block = sector->createBlankBlockNoInsert(p3d.Y);
3866                         created_new = true;
3867                 }
3868
3869                 // Read basic data
3870                 block->deSerialize(is, version, true);
3871
3872                 // If it's a new block, insert it to the map
3873                 if(created_new)
3874                         sector->insertBlock(block);
3875
3876                 /*
3877                         Save blocks loaded in old format in new format
3878                 */
3879
3880                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
3881                 {
3882                         saveBlock(block);
3883
3884                         // Should be in database now, so delete the old file
3885                         fs::RecursiveDelete(fullpath);
3886                 }
3887
3888                 // We just loaded it from the disk, so it's up-to-date.
3889                 block->resetModified();
3890
3891         }
3892         catch(SerializationError &e)
3893         {
3894                 infostream<<"WARNING: Invalid block data on disk "
3895                                 <<"fullpath="<<fullpath
3896                                 <<" (SerializationError). "
3897                                 <<"what()="<<e.what()
3898                                 <<std::endl;
3899                                 // Ignoring. A new one will be generated.
3900                 assert(0);
3901
3902                 // TODO: Backup file; name is in fullpath.
3903         }
3904 }
3905
3906 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3907 {
3908         DSTACK(__FUNCTION_NAME);
3909
3910         try {
3911                 std::istringstream is(*blob, std::ios_base::binary);
3912
3913                 u8 version = SER_FMT_VER_INVALID;
3914                 is.read((char*)&version, 1);
3915
3916                 if(is.fail())
3917                         throw SerializationError("ServerMap::loadBlock(): Failed"
3918                                         " to read MapBlock version");
3919
3920                 /*u32 block_size = MapBlock::serializedLength(version);
3921                 SharedBuffer<u8> data(block_size);
3922                 is.read((char*)*data, block_size);*/
3923
3924                 // This will always return a sector because we're the server
3925                 //MapSector *sector = emergeSector(p2d);
3926
3927                 MapBlock *block = NULL;
3928                 bool created_new = false;
3929                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3930                 if(block == NULL)
3931                 {
3932                         block = sector->createBlankBlockNoInsert(p3d.Y);
3933                         created_new = true;
3934                 }
3935
3936                 // Read basic data
3937                 block->deSerialize(is, version, true);
3938
3939                 // If it's a new block, insert it to the map
3940                 if(created_new)
3941                         sector->insertBlock(block);
3942
3943                 /*
3944                         Save blocks loaded in old format in new format
3945                 */
3946
3947                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
3948                 // Only save if asked to; no need to update version
3949                 if(save_after_load)
3950                         saveBlock(block);
3951
3952                 // We just loaded it from, so it's up-to-date.
3953                 block->resetModified();
3954
3955         }
3956         catch(SerializationError &e)
3957         {
3958                 errorstream<<"Invalid block data in database"
3959                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3960                                 <<" (SerializationError): "<<e.what()<<std::endl;
3961
3962                 // TODO: Block should be marked as invalid in memory so that it is
3963                 // not touched but the game can run
3964
3965                 if(g_settings->getBool("ignore_world_load_errors")){
3966                         errorstream<<"Ignoring block load error. Duck and cover! "
3967                                         <<"(ignore_world_load_errors)"<<std::endl;
3968                 } else {
3969                         throw SerializationError("Invalid block data in database");
3970                         //assert(0);
3971                 }
3972         }
3973 }
3974
3975 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3976 {
3977         DSTACK(__FUNCTION_NAME);
3978
3979         v2s16 p2d(blockpos.X, blockpos.Z);
3980
3981         if(!loadFromFolders()) {
3982                 verifyDatabase();
3983
3984                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3985                         infostream<<"WARNING: Could not bind block position for load: "
3986                                 <<sqlite3_errmsg(m_database)<<std::endl;
3987                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3988                         /*
3989                                 Make sure sector is loaded
3990                         */
3991                         MapSector *sector = createSector(p2d);
3992
3993                         /*
3994                                 Load block
3995                         */
3996                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3997                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3998
3999                         std::string datastr(data, len);
4000
4001                         loadBlock(&datastr, blockpos, sector, false);
4002
4003                         sqlite3_step(m_database_read);
4004                         // We should never get more than 1 row, so ok to reset
4005                         sqlite3_reset(m_database_read);
4006
4007                         return getBlockNoCreateNoEx(blockpos);
4008                 }
4009                 sqlite3_reset(m_database_read);
4010
4011                 // Not found in database, try the files
4012         }
4013
4014         // The directory layout we're going to load from.
4015         //  1 - original sectors/xxxxzzzz/
4016         //  2 - new sectors2/xxx/zzz/
4017         //  If we load from anything but the latest structure, we will
4018         //  immediately save to the new one, and remove the old.
4019         int loadlayout = 1;
4020         std::string sectordir1 = getSectorDir(p2d, 1);
4021         std::string sectordir;
4022         if(fs::PathExists(sectordir1))
4023         {
4024                 sectordir = sectordir1;
4025         }
4026         else
4027         {
4028                 loadlayout = 2;
4029                 sectordir = getSectorDir(p2d, 2);
4030         }
4031
4032         /*
4033                 Make sure sector is loaded
4034         */
4035         MapSector *sector = getSectorNoGenerateNoEx(p2d);
4036         if(sector == NULL)
4037         {
4038                 try{
4039                         sector = loadSectorMeta(sectordir, loadlayout != 2);
4040                 }
4041                 catch(InvalidFilenameException &e)
4042                 {
4043                         return NULL;
4044                 }
4045                 catch(FileNotGoodException &e)
4046                 {
4047                         return NULL;
4048                 }
4049                 catch(std::exception &e)
4050                 {
4051                         return NULL;
4052                 }
4053         }
4054
4055         /*
4056                 Make sure file exists
4057         */
4058
4059         std::string blockfilename = getBlockFilename(blockpos);
4060         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
4061                 return NULL;
4062
4063         /*
4064                 Load block and save it to the database
4065         */
4066         loadBlock(sectordir, blockfilename, sector, true);
4067         return getBlockNoCreateNoEx(blockpos);
4068 }
4069
4070 void ServerMap::PrintInfo(std::ostream &out)
4071 {
4072         out<<"ServerMap: ";
4073 }
4074
4075 s16 ServerMap::getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block)
4076 {
4077         if(block == NULL)
4078                 block = getBlockNoCreateNoEx(getNodeBlockPos(p));
4079         if(block != NULL) {
4080                 if (env->getGameTime() - block->heat_time < 10)
4081                         return block->heat;
4082         }
4083
4084         //variant 1: full random
4085         //f32 heat = NoisePerlin3D(m_emerge->biomedef->np_heat, p.X, env->getGameTime()/100, p.Z, m_emerge->params->seed);
4086
4087         //variant 2: season change based on default heat map
4088         f32 heat = NoisePerlin2D(m_emerge->biomedef->np_heat, p.X, p.Z, m_emerge->params->seed);
4089         heat += -30; // -30 - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50,
4090         f32 base = (f32)env->getGameTime() * env->getTimeOfDaySpeed();
4091         base /= ( 86400 * g_settings->getS16("year_days") );
4092         base += (f32)p.X / 3000;
4093         heat += 30 * sin(base * M_PI); // season
4094
4095         heat += p.Y / -333; // upper=colder, lower=hotter
4096
4097         // daily change, hotter at sun +4, colder at night -4
4098         heat += 8 * (sin(cycle_shift(env->getTimeOfDayF(), -0.25) * M_PI) - 0.5); 
4099
4100         if(block != NULL) {
4101                 block->heat = heat;
4102                 block->heat_time = env->getGameTime();
4103         }
4104         return heat;
4105 }
4106
4107 s16 ServerMap::getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block)
4108 {
4109         if(block == NULL)
4110                 block = getBlockNoCreateNoEx(getNodeBlockPos(p));
4111         if(block != NULL) {
4112                 if (env->getGameTime() - block->humidity_time < 10)
4113                         return block->humidity;
4114         }
4115
4116         f32 humidity = NoisePerlin3D(   m_emerge->biomedef->np_humidity,
4117                                         p.X, env->getGameTime()/10, p.Z,
4118                                         m_emerge->params->seed);
4119         humidity += -12 * ( sin(cycle_shift(env->getTimeOfDayF(), -0.1) * M_PI) - 0.5);
4120         //todo like heat//humidity += 20 * ( sin(((f32)p.Z / 300) * M_PI) - 0.5);
4121
4122         if (humidity > 100) humidity = 100;
4123         if (humidity < 0) humidity = 0;
4124
4125         if(block != NULL) {
4126                 block->humidity = humidity;
4127                 block->humidity_time = env->getGameTime();
4128         }
4129         return humidity;
4130 }
4131
4132 /*
4133         MapVoxelManipulator
4134 */
4135
4136 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4137 {
4138         m_map = map;
4139 }
4140
4141 MapVoxelManipulator::~MapVoxelManipulator()
4142 {
4143         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4144                         <<std::endl;*/
4145 }
4146
4147 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4148 {
4149         TimeTaker timer1("emerge", &emerge_time);
4150
4151         // Units of these are MapBlocks
4152         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4153         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4154
4155         VoxelArea block_area_nodes
4156                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4157
4158         addArea(block_area_nodes);
4159
4160         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4161         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4162         for(s32 x=p_min.X; x<=p_max.X; x++)
4163         {
4164                 u8 flags = 0;
4165                 MapBlock *block;
4166                 v3s16 p(x,y,z);
4167                 std::map<v3s16, u8>::iterator n;
4168                 n = m_loaded_blocks.find(p);
4169                 if(n != m_loaded_blocks.end())
4170                         continue;
4171
4172                 bool block_data_inexistent = false;
4173                 try
4174                 {
4175                         TimeTaker timer1("emerge load", &emerge_load_time);
4176
4177                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
4178                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4179                                         <<" wanted area: ";
4180                         a.print(infostream);
4181                         infostream<<std::endl;*/
4182
4183                         block = m_map->getBlockNoCreate(p);
4184                         if(block->isDummy())
4185                                 block_data_inexistent = true;
4186                         else
4187                                 block->copyTo(*this);
4188                 }
4189                 catch(InvalidPositionException &e)
4190                 {
4191                         block_data_inexistent = true;
4192                 }
4193
4194                 if(block_data_inexistent)
4195                 {
4196                         flags |= VMANIP_BLOCK_DATA_INEXIST;
4197
4198                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4199                         // Fill with VOXELFLAG_INEXISTENT
4200                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4201                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4202                         {
4203                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4204                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4205                         }
4206                 }
4207                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
4208                 {
4209                         // Mark that block was loaded as blank
4210                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
4211                 }*/
4212
4213                 m_loaded_blocks[p] = flags;
4214         }
4215
4216         //infostream<<"emerge done"<<std::endl;
4217 }
4218
4219 /*
4220         SUGG: Add an option to only update eg. water and air nodes.
4221               This will make it interfere less with important stuff if
4222                   run on background.
4223 */
4224 void MapVoxelManipulator::blitBack
4225                 (std::map<v3s16, MapBlock*> & modified_blocks)
4226 {
4227         if(m_area.getExtent() == v3s16(0,0,0))
4228                 return;
4229
4230         //TimeTaker timer1("blitBack");
4231
4232         /*infostream<<"blitBack(): m_loaded_blocks.size()="
4233                         <<m_loaded_blocks.size()<<std::endl;*/
4234
4235         /*
4236                 Initialize block cache
4237         */
4238         v3s16 blockpos_last;
4239         MapBlock *block = NULL;
4240         bool block_checked_in_modified = false;
4241
4242         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4243         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4244         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4245         {
4246                 v3s16 p(x,y,z);
4247
4248                 u8 f = m_flags[m_area.index(p)];
4249                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4250                         continue;
4251
4252                 MapNode &n = m_data[m_area.index(p)];
4253
4254                 v3s16 blockpos = getNodeBlockPos(p);
4255
4256                 try
4257                 {
4258                         // Get block
4259                         if(block == NULL || blockpos != blockpos_last){
4260                                 block = m_map->getBlockNoCreate(blockpos);
4261                                 blockpos_last = blockpos;
4262                                 block_checked_in_modified = false;
4263                         }
4264
4265                         // Calculate relative position in block
4266                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4267
4268                         // Don't continue if nothing has changed here
4269                         if(block->getNode(relpos) == n)
4270                                 continue;
4271
4272                         //m_map->setNode(m_area.MinEdge + p, n);
4273                         block->setNode(relpos, n);
4274
4275                         /*
4276                                 Make sure block is in modified_blocks
4277                         */
4278                         if(block_checked_in_modified == false)
4279                         {
4280                                 modified_blocks[blockpos] = block;
4281                                 block_checked_in_modified = true;
4282                         }
4283                 }
4284                 catch(InvalidPositionException &e)
4285                 {
4286                 }
4287         }
4288 }
4289
4290 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4291                 MapVoxelManipulator(map),
4292                 m_create_area(false)
4293 {
4294 }
4295
4296 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4297 {
4298 }
4299
4300 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4301 {
4302         // Just create the area so that it can be pointed to
4303         VoxelManipulator::emerge(a, caller_id);
4304 }
4305
4306 void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
4307                                                 v3s16 blockpos_max, bool load_if_inexistent)
4308 {
4309         TimeTaker timer1("initialEmerge", &emerge_time);
4310
4311         // Units of these are MapBlocks
4312         v3s16 p_min = blockpos_min;
4313         v3s16 p_max = blockpos_max;
4314
4315         VoxelArea block_area_nodes
4316                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4317
4318         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4319         if(size_MB >= 1)
4320         {
4321                 infostream<<"initialEmerge: area: ";
4322                 block_area_nodes.print(infostream);
4323                 infostream<<" ("<<size_MB<<"MB)";
4324                 infostream<<std::endl;
4325         }
4326
4327         addArea(block_area_nodes);
4328
4329         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4330         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4331         for(s32 x=p_min.X; x<=p_max.X; x++)
4332         {
4333                 u8 flags = 0;
4334                 MapBlock *block;
4335                 v3s16 p(x,y,z);
4336                 std::map<v3s16, u8>::iterator n;
4337                 n = m_loaded_blocks.find(p);
4338                 if(n != m_loaded_blocks.end())
4339                         continue;
4340
4341                 bool block_data_inexistent = false;
4342                 try
4343                 {
4344                         TimeTaker timer1("emerge load", &emerge_load_time);
4345
4346                         block = m_map->getBlockNoCreate(p);
4347                         if(block->isDummy())
4348                                 block_data_inexistent = true;
4349                         else
4350                                 block->copyTo(*this);
4351                 }
4352                 catch(InvalidPositionException &e)
4353                 {
4354                         block_data_inexistent = true;
4355                 }
4356
4357                 if(block_data_inexistent)
4358                 {
4359                         
4360                         if (load_if_inexistent) {
4361                                 ServerMap *svrmap = (ServerMap *)m_map;
4362                                 block = svrmap->emergeBlock(p, false);
4363                                 if (block == NULL)
4364                                         block = svrmap->createBlock(p);
4365                                 else
4366                                         block->copyTo(*this);
4367                         } else {
4368                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
4369                                 
4370                                 /*
4371                                         Mark area inexistent
4372                                 */
4373                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4374                                 // Fill with VOXELFLAG_INEXISTENT
4375                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4376                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4377                                 {
4378                                         s32 i = m_area.index(a.MinEdge.X,y,z);
4379                                         memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4380                                 }
4381                         }
4382                 }
4383                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
4384                 {
4385                         // Mark that block was loaded as blank
4386                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
4387                 }*/
4388
4389                 m_loaded_blocks[p] = flags;
4390         }
4391 }
4392
4393 void ManualMapVoxelManipulator::blitBackAll(
4394                 std::map<v3s16, MapBlock*> * modified_blocks)
4395 {
4396         if(m_area.getExtent() == v3s16(0,0,0))
4397                 return;
4398
4399         /*
4400                 Copy data of all blocks
4401         */
4402         for(std::map<v3s16, u8>::iterator
4403                         i = m_loaded_blocks.begin();
4404                         i != m_loaded_blocks.end(); ++i)
4405         {
4406                 v3s16 p = i->first;
4407                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4408                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
4409                 if(existed == false)
4410                 {
4411                         continue;
4412                 }
4413
4414                 block->copyFrom(*this);
4415
4416                 if(modified_blocks)
4417                         (*modified_blocks)[p] = block;
4418         }
4419 }
4420
4421 //END