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