]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
tweaked mapgen
[dragonfireclient.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 "main.h"
22 #include "jmutexautolock.h"
23 #include "client.h"
24 #include "filesys.h"
25 #include "utility.h"
26 #include "voxel.h"
27 #include "porting.h"
28 #include "mineral.h"
29 #include "noise.h"
30
31 /*
32         Map
33 */
34
35 Map::Map(std::ostream &dout):
36         m_dout(dout),
37         m_sector_cache(NULL)
38 {
39         m_sector_mutex.Init();
40         assert(m_sector_mutex.IsInitialized());
41 }
42
43 Map::~Map()
44 {
45         /*
46                 Free all MapSectors
47         */
48         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
49         for(; i.atEnd() == false; i++)
50         {
51                 MapSector *sector = i.getNode()->getValue();
52                 delete sector;
53         }
54 }
55
56 void Map::addEventReceiver(MapEventReceiver *event_receiver)
57 {
58         m_event_receivers.insert(event_receiver, false);
59 }
60
61 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
62 {
63         if(m_event_receivers.find(event_receiver) == NULL)
64                 return;
65         m_event_receivers.remove(event_receiver);
66 }
67
68 void Map::dispatchEvent(MapEditEvent *event)
69 {
70         for(core::map<MapEventReceiver*, bool>::Iterator
71                         i = m_event_receivers.getIterator();
72                         i.atEnd()==false; i++)
73         {
74                 MapEventReceiver* event_receiver = i.getNode()->getKey();
75                 event_receiver->onMapEditEvent(event);
76         }
77 }
78
79 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
80 {
81         if(m_sector_cache != NULL && p == m_sector_cache_p){
82                 MapSector * sector = m_sector_cache;
83                 // Reset inactivity timer
84                 sector->usage_timer = 0.0;
85                 return sector;
86         }
87         
88         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
89         
90         if(n == NULL)
91                 return NULL;
92         
93         MapSector *sector = n->getValue();
94         
95         // Cache the last result
96         m_sector_cache_p = p;
97         m_sector_cache = sector;
98
99         // Reset inactivity timer
100         sector->usage_timer = 0.0;
101         return sector;
102 }
103
104 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
105 {
106         JMutexAutoLock lock(m_sector_mutex);
107
108         return getSectorNoGenerateNoExNoLock(p);
109 }
110
111 MapSector * Map::getSectorNoGenerate(v2s16 p)
112 {
113         MapSector *sector = getSectorNoGenerateNoEx(p);
114         if(sector == NULL)
115                 throw InvalidPositionException();
116         
117         return sector;
118 }
119
120 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
121 {       
122         v2s16 p2d(p3d.X, p3d.Z);
123         MapSector * sector = getSectorNoGenerate(p2d);
124
125         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
126
127         return block;
128 }
129
130 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
131 {
132         try
133         {
134                 v2s16 p2d(p3d.X, p3d.Z);
135                 MapSector * sector = getSectorNoGenerate(p2d);
136                 MapBlock *block = sector->getBlockNoCreate(p3d.Y);
137                 return block;
138         }
139         catch(InvalidPositionException &e)
140         {
141                 return NULL;
142         }
143 }
144
145 /*MapBlock * Map::getBlockCreate(v3s16 p3d)
146 {
147         v2s16 p2d(p3d.X, p3d.Z);
148         MapSector * sector = getSectorCreate(p2d);
149         assert(sector);
150         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
151         if(block)
152                 return block;
153         block = sector->createBlankBlock(p3d.Y);
154         return block;
155 }*/
156
157 bool Map::isNodeUnderground(v3s16 p)
158 {
159         v3s16 blockpos = getNodeBlockPos(p);
160         try{
161                 MapBlock * block = getBlockNoCreate(blockpos);
162                 return block->getIsUnderground();
163         }
164         catch(InvalidPositionException &e)
165         {
166                 return false;
167         }
168 }
169
170 /*
171         Goes recursively through the neighbours of the node.
172
173         Alters only transparent nodes.
174
175         If the lighting of the neighbour is lower than the lighting of
176         the node was (before changing it to 0 at the step before), the
177         lighting of the neighbour is set to 0 and then the same stuff
178         repeats for the neighbour.
179
180         The ending nodes of the routine are stored in light_sources.
181         This is useful when a light is removed. In such case, this
182         routine can be called for the light node and then again for
183         light_sources to re-light the area without the removed light.
184
185         values of from_nodes are lighting values.
186 */
187 void Map::unspreadLight(enum LightBank bank,
188                 core::map<v3s16, u8> & from_nodes,
189                 core::map<v3s16, bool> & light_sources,
190                 core::map<v3s16, MapBlock*>  & modified_blocks)
191 {
192         v3s16 dirs[6] = {
193                 v3s16(0,0,1), // back
194                 v3s16(0,1,0), // top
195                 v3s16(1,0,0), // right
196                 v3s16(0,0,-1), // front
197                 v3s16(0,-1,0), // bottom
198                 v3s16(-1,0,0), // left
199         };
200         
201         if(from_nodes.size() == 0)
202                 return;
203         
204         u32 blockchangecount = 0;
205
206         core::map<v3s16, u8> unlighted_nodes;
207         core::map<v3s16, u8>::Iterator j;
208         j = from_nodes.getIterator();
209
210         /*
211                 Initialize block cache
212         */
213         v3s16 blockpos_last;
214         MapBlock *block = NULL;
215         // Cache this a bit, too
216         bool block_checked_in_modified = false;
217         
218         for(; j.atEnd() == false; j++)
219         {
220                 v3s16 pos = j.getNode()->getKey();
221                 v3s16 blockpos = getNodeBlockPos(pos);
222                 
223                 // Only fetch a new block if the block position has changed
224                 try{
225                         if(block == NULL || blockpos != blockpos_last){
226                                 block = getBlockNoCreate(blockpos);
227                                 blockpos_last = blockpos;
228
229                                 block_checked_in_modified = false;
230                                 blockchangecount++;
231                         }
232                 }
233                 catch(InvalidPositionException &e)
234                 {
235                         continue;
236                 }
237
238                 if(block->isDummy())
239                         continue;
240
241                 // Calculate relative position in block
242                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
243
244                 // Get node straight from the block
245                 MapNode n = block->getNode(relpos);
246                 
247                 u8 oldlight = j.getNode()->getValue();
248                 
249                 // Loop through 6 neighbors
250                 for(u16 i=0; i<6; i++)
251                 {
252                         // Get the position of the neighbor node
253                         v3s16 n2pos = pos + dirs[i];
254                         
255                         // Get the block where the node is located
256                         v3s16 blockpos = getNodeBlockPos(n2pos);
257
258                         try
259                         {
260                                 // Only fetch a new block if the block position has changed
261                                 try{
262                                         if(block == NULL || blockpos != blockpos_last){
263                                                 block = getBlockNoCreate(blockpos);
264                                                 blockpos_last = blockpos;
265
266                                                 block_checked_in_modified = false;
267                                                 blockchangecount++;
268                                         }
269                                 }
270                                 catch(InvalidPositionException &e)
271                                 {
272                                         continue;
273                                 }
274                                 
275                                 // Calculate relative position in block
276                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
277                                 // Get node straight from the block
278                                 MapNode n2 = block->getNode(relpos);
279                                 
280                                 bool changed = false;
281
282                                 //TODO: Optimize output by optimizing light_sources?
283
284                                 /*
285                                         If the neighbor is dimmer than what was specified
286                                         as oldlight (the light of the previous node)
287                                 */
288                                 if(n2.getLight(bank) < oldlight)
289                                 {
290                                         /*
291                                                 And the neighbor is transparent and it has some light
292                                         */
293                                         if(n2.light_propagates() && n2.getLight(bank) != 0)
294                                         {
295                                                 /*
296                                                         Set light to 0 and add to queue
297                                                 */
298
299                                                 u8 current_light = n2.getLight(bank);
300                                                 n2.setLight(bank, 0);
301                                                 block->setNode(relpos, n2);
302
303                                                 unlighted_nodes.insert(n2pos, current_light);
304                                                 changed = true;
305
306                                                 /*
307                                                         Remove from light_sources if it is there
308                                                         NOTE: This doesn't happen nearly at all
309                                                 */
310                                                 /*if(light_sources.find(n2pos))
311                                                 {
312                                                         std::cout<<"Removed from light_sources"<<std::endl;
313                                                         light_sources.remove(n2pos);
314                                                 }*/
315                                         }
316                                         
317                                         /*// DEBUG
318                                         if(light_sources.find(n2pos) != NULL)
319                                                 light_sources.remove(n2pos);*/
320                                 }
321                                 else{
322                                         light_sources.insert(n2pos, true);
323                                 }
324
325                                 // Add to modified_blocks
326                                 if(changed == true && block_checked_in_modified == false)
327                                 {
328                                         // If the block is not found in modified_blocks, add.
329                                         if(modified_blocks.find(blockpos) == NULL)
330                                         {
331                                                 modified_blocks.insert(blockpos, block);
332                                         }
333                                         block_checked_in_modified = true;
334                                 }
335                         }
336                         catch(InvalidPositionException &e)
337                         {
338                                 continue;
339                         }
340                 }
341         }
342
343         /*dstream<<"unspreadLight(): Changed block "
344                         <<blockchangecount<<" times"
345                         <<" for "<<from_nodes.size()<<" nodes"
346                         <<std::endl;*/
347         
348         if(unlighted_nodes.size() > 0)
349                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
350 }
351
352 /*
353         A single-node wrapper of the above
354 */
355 void Map::unLightNeighbors(enum LightBank bank,
356                 v3s16 pos, u8 lightwas,
357                 core::map<v3s16, bool> & light_sources,
358                 core::map<v3s16, MapBlock*>  & modified_blocks)
359 {
360         core::map<v3s16, u8> from_nodes;
361         from_nodes.insert(pos, lightwas);
362
363         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
364 }
365
366 /*
367         Lights neighbors of from_nodes, collects all them and then
368         goes on recursively.
369 */
370 void Map::spreadLight(enum LightBank bank,
371                 core::map<v3s16, bool> & from_nodes,
372                 core::map<v3s16, MapBlock*> & modified_blocks)
373 {
374         const v3s16 dirs[6] = {
375                 v3s16(0,0,1), // back
376                 v3s16(0,1,0), // top
377                 v3s16(1,0,0), // right
378                 v3s16(0,0,-1), // front
379                 v3s16(0,-1,0), // bottom
380                 v3s16(-1,0,0), // left
381         };
382
383         if(from_nodes.size() == 0)
384                 return;
385         
386         u32 blockchangecount = 0;
387
388         core::map<v3s16, bool> lighted_nodes;
389         core::map<v3s16, bool>::Iterator j;
390         j = from_nodes.getIterator();
391
392         /*
393                 Initialize block cache
394         */
395         v3s16 blockpos_last;
396         MapBlock *block = NULL;
397         // Cache this a bit, too
398         bool block_checked_in_modified = false;
399         
400         for(; j.atEnd() == false; j++)
401         //for(; j != from_nodes.end(); j++)
402         {
403                 v3s16 pos = j.getNode()->getKey();
404                 //v3s16 pos = *j;
405                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
406                 v3s16 blockpos = getNodeBlockPos(pos);
407                 
408                 // Only fetch a new block if the block position has changed
409                 try{
410                         if(block == NULL || blockpos != blockpos_last){
411                                 block = getBlockNoCreate(blockpos);
412                                 blockpos_last = blockpos;
413
414                                 block_checked_in_modified = false;
415                                 blockchangecount++;
416                         }
417                 }
418                 catch(InvalidPositionException &e)
419                 {
420                         continue;
421                 }
422
423                 if(block->isDummy())
424                         continue;
425
426                 // Calculate relative position in block
427                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
428
429                 // Get node straight from the block
430                 MapNode n = block->getNode(relpos);
431
432                 u8 oldlight = n.getLight(bank);
433                 u8 newlight = diminish_light(oldlight);
434
435                 // Loop through 6 neighbors
436                 for(u16 i=0; i<6; i++){
437                         // Get the position of the neighbor node
438                         v3s16 n2pos = pos + dirs[i];
439                         
440                         // Get the block where the node is located
441                         v3s16 blockpos = getNodeBlockPos(n2pos);
442
443                         try
444                         {
445                                 // Only fetch a new block if the block position has changed
446                                 try{
447                                         if(block == NULL || blockpos != blockpos_last){
448                                                 block = getBlockNoCreate(blockpos);
449                                                 blockpos_last = blockpos;
450
451                                                 block_checked_in_modified = false;
452                                                 blockchangecount++;
453                                         }
454                                 }
455                                 catch(InvalidPositionException &e)
456                                 {
457                                         continue;
458                                 }
459                                 
460                                 // Calculate relative position in block
461                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
462                                 // Get node straight from the block
463                                 MapNode n2 = block->getNode(relpos);
464                                 
465                                 bool changed = false;
466                                 /*
467                                         If the neighbor is brighter than the current node,
468                                         add to list (it will light up this node on its turn)
469                                 */
470                                 if(n2.getLight(bank) > undiminish_light(oldlight))
471                                 {
472                                         lighted_nodes.insert(n2pos, true);
473                                         //lighted_nodes.push_back(n2pos);
474                                         changed = true;
475                                 }
476                                 /*
477                                         If the neighbor is dimmer than how much light this node
478                                         would spread on it, add to list
479                                 */
480                                 if(n2.getLight(bank) < newlight)
481                                 {
482                                         if(n2.light_propagates())
483                                         {
484                                                 n2.setLight(bank, newlight);
485                                                 block->setNode(relpos, n2);
486                                                 lighted_nodes.insert(n2pos, true);
487                                                 //lighted_nodes.push_back(n2pos);
488                                                 changed = true;
489                                         }
490                                 }
491
492                                 // Add to modified_blocks
493                                 if(changed == true && block_checked_in_modified == false)
494                                 {
495                                         // If the block is not found in modified_blocks, add.
496                                         if(modified_blocks.find(blockpos) == NULL)
497                                         {
498                                                 modified_blocks.insert(blockpos, block);
499                                         }
500                                         block_checked_in_modified = true;
501                                 }
502                         }
503                         catch(InvalidPositionException &e)
504                         {
505                                 continue;
506                         }
507                 }
508         }
509
510         /*dstream<<"spreadLight(): Changed block "
511                         <<blockchangecount<<" times"
512                         <<" for "<<from_nodes.size()<<" nodes"
513                         <<std::endl;*/
514         
515         if(lighted_nodes.size() > 0)
516                 spreadLight(bank, lighted_nodes, modified_blocks);
517 }
518
519 /*
520         A single-node source variation of the above.
521 */
522 void Map::lightNeighbors(enum LightBank bank,
523                 v3s16 pos,
524                 core::map<v3s16, MapBlock*> & modified_blocks)
525 {
526         core::map<v3s16, bool> from_nodes;
527         from_nodes.insert(pos, true);
528         spreadLight(bank, from_nodes, modified_blocks);
529 }
530
531 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
532 {
533         v3s16 dirs[6] = {
534                 v3s16(0,0,1), // back
535                 v3s16(0,1,0), // top
536                 v3s16(1,0,0), // right
537                 v3s16(0,0,-1), // front
538                 v3s16(0,-1,0), // bottom
539                 v3s16(-1,0,0), // left
540         };
541         
542         u8 brightest_light = 0;
543         v3s16 brightest_pos(0,0,0);
544         bool found_something = false;
545
546         // Loop through 6 neighbors
547         for(u16 i=0; i<6; i++){
548                 // Get the position of the neighbor node
549                 v3s16 n2pos = p + dirs[i];
550                 MapNode n2;
551                 try{
552                         n2 = getNode(n2pos);
553                 }
554                 catch(InvalidPositionException &e)
555                 {
556                         continue;
557                 }
558                 if(n2.getLight(bank) > brightest_light || found_something == false){
559                         brightest_light = n2.getLight(bank);
560                         brightest_pos = n2pos;
561                         found_something = true;
562                 }
563         }
564
565         if(found_something == false)
566                 throw InvalidPositionException();
567                 
568         return brightest_pos;
569 }
570
571 /*
572         Propagates sunlight down from a node.
573         Starting point gets sunlight.
574
575         Returns the lowest y value of where the sunlight went.
576
577         Mud is turned into grass in where the sunlight stops.
578 */
579 s16 Map::propagateSunlight(v3s16 start,
580                 core::map<v3s16, MapBlock*> & modified_blocks)
581 {
582         s16 y = start.Y;
583         for(; ; y--)
584         {
585                 v3s16 pos(start.X, y, start.Z);
586                 
587                 v3s16 blockpos = getNodeBlockPos(pos);
588                 MapBlock *block;
589                 try{
590                         block = getBlockNoCreate(blockpos);
591                 }
592                 catch(InvalidPositionException &e)
593                 {
594                         break;
595                 }
596
597                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
598                 MapNode n = block->getNode(relpos);
599
600                 if(n.sunlight_propagates())
601                 {
602                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
603                         block->setNode(relpos, n);
604
605                         modified_blocks.insert(blockpos, block);
606                 }
607                 else
608                 {
609                         // Turn mud into grass
610                         if(n.d == CONTENT_MUD)
611                         {
612                                 n.d = CONTENT_GRASS;
613                                 block->setNode(relpos, n);
614                                 modified_blocks.insert(blockpos, block);
615                         }
616
617                         // Sunlight goes no further
618                         break;
619                 }
620         }
621         return y + 1;
622 }
623
624 void Map::updateLighting(enum LightBank bank,
625                 core::map<v3s16, MapBlock*> & a_blocks,
626                 core::map<v3s16, MapBlock*> & modified_blocks)
627 {
628         /*m_dout<<DTIME<<"Map::updateLighting(): "
629                         <<a_blocks.size()<<" blocks."<<std::endl;*/
630         
631         //TimeTaker timer("updateLighting");
632         
633         // For debugging
634         //bool debug=true;
635         //u32 count_was = modified_blocks.size();
636         
637         core::map<v3s16, MapBlock*> blocks_to_update;
638
639         core::map<v3s16, bool> light_sources;
640         
641         core::map<v3s16, u8> unlight_from;
642                 
643         core::map<v3s16, MapBlock*>::Iterator i;
644         i = a_blocks.getIterator();
645         for(; i.atEnd() == false; i++)
646         {
647                 MapBlock *block = i.getNode()->getValue();
648                 
649                 for(;;)
650                 {
651                         // Don't bother with dummy blocks.
652                         if(block->isDummy())
653                                 break;
654                 
655                         v3s16 pos = block->getPos();
656                         modified_blocks.insert(pos, block);
657
658                         blocks_to_update.insert(pos, block);
659
660                         /*
661                                 Clear all light from block
662                         */
663                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
664                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
665                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
666                         {
667                                 
668                                 try{
669                                         v3s16 p(x,y,z);
670                                         MapNode n = block->getNode(v3s16(x,y,z));
671                                         u8 oldlight = n.getLight(bank);
672                                         n.setLight(bank, 0);
673                                         block->setNode(v3s16(x,y,z), n);
674                                         
675                                         // Collect borders for unlighting
676                                         if(x==0 || x == MAP_BLOCKSIZE-1
677                                         || y==0 || y == MAP_BLOCKSIZE-1
678                                         || z==0 || z == MAP_BLOCKSIZE-1)
679                                         {
680                                                 v3s16 p_map = p + v3s16(
681                                                                 MAP_BLOCKSIZE*pos.X,
682                                                                 MAP_BLOCKSIZE*pos.Y,
683                                                                 MAP_BLOCKSIZE*pos.Z);
684                                                 unlight_from.insert(p_map, oldlight);
685                                         }
686                                 }
687                                 catch(InvalidPositionException &e)
688                                 {
689                                         /*
690                                                 This would happen when dealing with a
691                                                 dummy block.
692                                         */
693                                         //assert(0);
694                                         dstream<<"updateLighting(): InvalidPositionException"
695                                                         <<std::endl;
696                                 }
697                         }
698                         
699                         if(bank == LIGHTBANK_DAY)
700                         {
701                                 bool bottom_valid = block->propagateSunlight(light_sources);
702
703                                 // If bottom is valid, we're done.
704                                 if(bottom_valid)
705                                         break;
706                         }
707                         else if(bank == LIGHTBANK_NIGHT)
708                         {
709                                 // For night lighting, sunlight is not propagated
710                                 break;
711                         }
712                         else
713                         {
714                                 // Invalid lighting bank
715                                 assert(0);
716                         }
717                                 
718                         /*dstream<<"Bottom for sunlight-propagated block ("
719                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
720                                         <<std::endl;*/
721
722                         // Bottom sunlight is not valid; get the block and loop to it
723
724                         pos.Y--;
725                         try{
726                                 block = getBlockNoCreate(pos);
727                         }
728                         catch(InvalidPositionException &e)
729                         {
730                                 assert(0);
731                         }
732                         
733                 }
734         }
735
736 #if 0
737         {
738                 TimeTaker timer("unspreadLight");
739                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
740         }
741         
742         if(debug)
743         {
744                 u32 diff = modified_blocks.size() - count_was;
745                 count_was = modified_blocks.size();
746                 dstream<<"unspreadLight modified "<<diff<<std::endl;
747         }
748
749         {
750                 TimeTaker timer("spreadLight");
751                 spreadLight(bank, light_sources, modified_blocks);
752         }
753         
754         if(debug)
755         {
756                 u32 diff = modified_blocks.size() - count_was;
757                 count_was = modified_blocks.size();
758                 dstream<<"spreadLight modified "<<diff<<std::endl;
759         }
760 #endif
761         
762         {
763                 //MapVoxelManipulator vmanip(this);
764                 
765                 // Make a manual voxel manipulator and load all the blocks
766                 // that touch the requested blocks
767                 ManualMapVoxelManipulator vmanip(this);
768                 core::map<v3s16, MapBlock*>::Iterator i;
769                 i = blocks_to_update.getIterator();
770                 for(; i.atEnd() == false; i++)
771                 {
772                         MapBlock *block = i.getNode()->getValue();
773                         v3s16 p = block->getPos();
774                         
775                         // Add all surrounding blocks
776                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
777
778                         /*
779                                 Add all surrounding blocks that have up-to-date lighting
780                                 NOTE: This doesn't quite do the job (not everything
781                                       appropriate is lighted)
782                         */
783                         /*for(s16 z=-1; z<=1; z++)
784                         for(s16 y=-1; y<=1; y++)
785                         for(s16 x=-1; x<=1; x++)
786                         {
787                                 v3s16 p(x,y,z);
788                                 MapBlock *block = getBlockNoCreateNoEx(p);
789                                 if(block == NULL)
790                                         continue;
791                                 if(block->isDummy())
792                                         continue;
793                                 if(block->getLightingExpired())
794                                         continue;
795                                 vmanip.initialEmerge(p, p);
796                         }*/
797                         
798                         // Lighting of block will be updated completely
799                         block->setLightingExpired(false);
800                 }
801
802                 {
803                         //TimeTaker timer("unSpreadLight");
804                         vmanip.unspreadLight(bank, unlight_from, light_sources);
805                 }
806                 {
807                         //TimeTaker timer("spreadLight");
808                         vmanip.spreadLight(bank, light_sources);
809                 }
810                 {
811                         //TimeTaker timer("blitBack");
812                         vmanip.blitBack(modified_blocks);
813                 }
814                 /*dstream<<"emerge_time="<<emerge_time<<std::endl;
815                 emerge_time = 0;*/
816         }
817
818         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
819 }
820
821 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
822                 core::map<v3s16, MapBlock*> & modified_blocks)
823 {
824         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
825         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
826         
827         /*
828                 Update information about whether day and night light differ
829         */
830         for(core::map<v3s16, MapBlock*>::Iterator
831                         i = modified_blocks.getIterator();
832                         i.atEnd() == false; i++)
833         {
834                 MapBlock *block = i.getNode()->getValue();
835                 block->updateDayNightDiff();
836         }
837 }
838
839 /*
840         This is called after changing a node from transparent to opaque.
841         The lighting value of the node should be left as-is after changing
842         other values. This sets the lighting value to 0.
843 */
844 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
845                 core::map<v3s16, MapBlock*> &modified_blocks)
846 {
847         /*PrintInfo(m_dout);
848         m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
849                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
850         
851         /*
852                 From this node to nodes underneath:
853                 If lighting is sunlight (1.0), unlight neighbours and
854                 set lighting to 0.
855                 Else discontinue.
856         */
857
858         v3s16 toppos = p + v3s16(0,1,0);
859         v3s16 bottompos = p + v3s16(0,-1,0);
860
861         bool node_under_sunlight = true;
862         core::map<v3s16, bool> light_sources;
863
864         /*
865                 If there is a node at top and it doesn't have sunlight,
866                 there has not been any sunlight going down.
867
868                 Otherwise there probably is.
869         */
870         try{
871                 MapNode topnode = getNode(toppos);
872
873                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
874                         node_under_sunlight = false;
875         }
876         catch(InvalidPositionException &e)
877         {
878         }
879         
880         /*
881                 If the new node doesn't propagate sunlight and there is
882                 grass below, change it to mud
883         */
884         if(content_features(n.d).sunlight_propagates == false)
885         {
886                 try{
887                         MapNode bottomnode = getNode(bottompos);
888                         
889                         if(bottomnode.d == CONTENT_GRASS
890                                         || bottomnode.d == CONTENT_GRASS_FOOTSTEPS)
891                         {
892                                 bottomnode.d = CONTENT_MUD;
893                                 setNode(bottompos, bottomnode);
894                         }
895                 }
896                 catch(InvalidPositionException &e)
897                 {
898                 }
899         }
900
901         /*
902                 If the new node is mud and it is under sunlight, change it
903                 to grass
904         */
905         if(n.d == CONTENT_MUD && node_under_sunlight)
906         {
907                 n.d = CONTENT_GRASS;
908         }
909
910         /*
911                 Remove all light that has come out of this node
912         */
913
914         enum LightBank banks[] =
915         {
916                 LIGHTBANK_DAY,
917                 LIGHTBANK_NIGHT
918         };
919         for(s32 i=0; i<2; i++)
920         {
921                 enum LightBank bank = banks[i];
922
923                 u8 lightwas = getNode(p).getLight(bank);
924
925                 // Add the block of the added node to modified_blocks
926                 v3s16 blockpos = getNodeBlockPos(p);
927                 MapBlock * block = getBlockNoCreate(blockpos);
928                 assert(block != NULL);
929                 modified_blocks.insert(blockpos, block);
930                 
931                 assert(isValidPosition(p));
932                         
933                 // Unlight neighbours of node.
934                 // This means setting light of all consequent dimmer nodes
935                 // to 0.
936                 // This also collects the nodes at the border which will spread
937                 // light again into this.
938                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
939
940                 n.setLight(bank, 0);
941         }
942
943         /*
944                 Set the node on the map
945         */
946         
947         setNode(p, n);
948         
949         /*
950                 If node is under sunlight, take all sunlighted nodes under
951                 it and clear light from them and from where the light has
952                 been spread.
953                 TODO: This could be optimized by mass-unlighting instead
954                       of looping
955         */
956         if(node_under_sunlight)
957         {
958                 s16 y = p.Y - 1;
959                 for(;; y--){
960                         //m_dout<<DTIME<<"y="<<y<<std::endl;
961                         v3s16 n2pos(p.X, y, p.Z);
962                         
963                         MapNode n2;
964                         try{
965                                 n2 = getNode(n2pos);
966                         }
967                         catch(InvalidPositionException &e)
968                         {
969                                 break;
970                         }
971
972                         if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
973                         {
974                                 unLightNeighbors(LIGHTBANK_DAY,
975                                                 n2pos, n2.getLight(LIGHTBANK_DAY),
976                                                 light_sources, modified_blocks);
977                                 n2.setLight(LIGHTBANK_DAY, 0);
978                                 setNode(n2pos, n2);
979                         }
980                         else
981                                 break;
982                 }
983         }
984         
985         for(s32 i=0; i<2; i++)
986         {
987                 enum LightBank bank = banks[i];
988                 
989                 /*
990                         Spread light from all nodes that might be capable of doing so
991                 */
992                 spreadLight(bank, light_sources, modified_blocks);
993         }
994
995         /*
996                 Update information about whether day and night light differ
997         */
998         for(core::map<v3s16, MapBlock*>::Iterator
999                         i = modified_blocks.getIterator();
1000                         i.atEnd() == false; i++)
1001         {
1002                 MapBlock *block = i.getNode()->getValue();
1003                 block->updateDayNightDiff();
1004         }
1005
1006         /*
1007                 Add neighboring liquid nodes and the node itself if it is
1008                 liquid (=water node was added) to transform queue.
1009         */
1010         v3s16 dirs[7] = {
1011                 v3s16(0,0,0), // self
1012                 v3s16(0,0,1), // back
1013                 v3s16(0,1,0), // top
1014                 v3s16(1,0,0), // right
1015                 v3s16(0,0,-1), // front
1016                 v3s16(0,-1,0), // bottom
1017                 v3s16(-1,0,0), // left
1018         };
1019         for(u16 i=0; i<7; i++)
1020         {
1021                 try
1022                 {
1023
1024                 v3s16 p2 = p + dirs[i];
1025                 
1026                 MapNode n2 = getNode(p2);
1027                 if(content_liquid(n2.d))
1028                 {
1029                         m_transforming_liquid.push_back(p2);
1030                 }
1031                 
1032                 }catch(InvalidPositionException &e)
1033                 {
1034                 }
1035         }
1036 }
1037
1038 /*
1039 */
1040 void Map::removeNodeAndUpdate(v3s16 p,
1041                 core::map<v3s16, MapBlock*> &modified_blocks)
1042 {
1043         /*PrintInfo(m_dout);
1044         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1045                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1046         
1047         bool node_under_sunlight = true;
1048         
1049         v3s16 toppos = p + v3s16(0,1,0);
1050
1051         // Node will be replaced with this
1052         u8 replace_material = CONTENT_AIR;
1053         
1054         /*
1055                 If there is a node at top and it doesn't have sunlight,
1056                 there will be no sunlight going down.
1057         */
1058         try{
1059                 MapNode topnode = getNode(toppos);
1060
1061                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1062                         node_under_sunlight = false;
1063         }
1064         catch(InvalidPositionException &e)
1065         {
1066         }
1067
1068         core::map<v3s16, bool> light_sources;
1069
1070         enum LightBank banks[] =
1071         {
1072                 LIGHTBANK_DAY,
1073                 LIGHTBANK_NIGHT
1074         };
1075         for(s32 i=0; i<2; i++)
1076         {
1077                 enum LightBank bank = banks[i];
1078         
1079                 /*
1080                         Unlight neighbors (in case the node is a light source)
1081                 */
1082                 unLightNeighbors(bank, p,
1083                                 getNode(p).getLight(bank),
1084                                 light_sources, modified_blocks);
1085         }
1086
1087         /*
1088                 Remove the node.
1089                 This also clears the lighting.
1090         */
1091
1092         MapNode n;
1093         n.d = replace_material;
1094         setNode(p, n);
1095         
1096         for(s32 i=0; i<2; i++)
1097         {
1098                 enum LightBank bank = banks[i];
1099         
1100                 /*
1101                         Recalculate lighting
1102                 */
1103                 spreadLight(bank, light_sources, modified_blocks);
1104         }
1105
1106         // Add the block of the removed node to modified_blocks
1107         v3s16 blockpos = getNodeBlockPos(p);
1108         MapBlock * block = getBlockNoCreate(blockpos);
1109         assert(block != NULL);
1110         modified_blocks.insert(blockpos, block);
1111
1112         /*
1113                 If the removed node was under sunlight, propagate the
1114                 sunlight down from it and then light all neighbors
1115                 of the propagated blocks.
1116         */
1117         if(node_under_sunlight)
1118         {
1119                 s16 ybottom = propagateSunlight(p, modified_blocks);
1120                 /*m_dout<<DTIME<<"Node was under sunlight. "
1121                                 "Propagating sunlight";
1122                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1123                 s16 y = p.Y;
1124                 for(; y >= ybottom; y--)
1125                 {
1126                         v3s16 p2(p.X, y, p.Z);
1127                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1128                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1129                                         <<std::endl;*/
1130                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1131                 }
1132         }
1133         else
1134         {
1135                 // Set the lighting of this node to 0
1136                 // TODO: Is this needed? Lighting is cleared up there already.
1137                 try{
1138                         MapNode n = getNode(p);
1139                         n.setLight(LIGHTBANK_DAY, 0);
1140                         setNode(p, n);
1141                 }
1142                 catch(InvalidPositionException &e)
1143                 {
1144                         assert(0);
1145                 }
1146         }
1147
1148         for(s32 i=0; i<2; i++)
1149         {
1150                 enum LightBank bank = banks[i];
1151         
1152                 // Get the brightest neighbour node and propagate light from it
1153                 v3s16 n2p = getBrightestNeighbour(bank, p);
1154                 try{
1155                         MapNode n2 = getNode(n2p);
1156                         lightNeighbors(bank, n2p, modified_blocks);
1157                 }
1158                 catch(InvalidPositionException &e)
1159                 {
1160                 }
1161         }
1162
1163         /*
1164                 Update information about whether day and night light differ
1165         */
1166         for(core::map<v3s16, MapBlock*>::Iterator
1167                         i = modified_blocks.getIterator();
1168                         i.atEnd() == false; i++)
1169         {
1170                 MapBlock *block = i.getNode()->getValue();
1171                 block->updateDayNightDiff();
1172         }
1173
1174         /*
1175                 Add neighboring liquid nodes to transform queue.
1176         */
1177         v3s16 dirs[6] = {
1178                 v3s16(0,0,1), // back
1179                 v3s16(0,1,0), // top
1180                 v3s16(1,0,0), // right
1181                 v3s16(0,0,-1), // front
1182                 v3s16(0,-1,0), // bottom
1183                 v3s16(-1,0,0), // left
1184         };
1185         for(u16 i=0; i<6; i++)
1186         {
1187                 try
1188                 {
1189
1190                 v3s16 p2 = p + dirs[i];
1191                 
1192                 MapNode n2 = getNode(p2);
1193                 if(content_liquid(n2.d))
1194                 {
1195                         m_transforming_liquid.push_back(p2);
1196                 }
1197                 
1198                 }catch(InvalidPositionException &e)
1199                 {
1200                 }
1201         }
1202 }
1203
1204 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1205 {
1206         MapEditEvent event;
1207         event.type = MEET_ADDNODE;
1208         event.p = p;
1209         event.n = n;
1210
1211         bool succeeded = true;
1212         try{
1213                 core::map<v3s16, MapBlock*> modified_blocks;
1214                 addNodeAndUpdate(p, n, modified_blocks);
1215
1216                 // Copy modified_blocks to event
1217                 for(core::map<v3s16, MapBlock*>::Iterator
1218                                 i = modified_blocks.getIterator();
1219                                 i.atEnd()==false; i++)
1220                 {
1221                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1222                 }
1223         }
1224         catch(InvalidPositionException &e){
1225                 succeeded = false;
1226         }
1227
1228         dispatchEvent(&event);
1229
1230         return succeeded;
1231 }
1232
1233 bool Map::removeNodeWithEvent(v3s16 p)
1234 {
1235         MapEditEvent event;
1236         event.type = MEET_REMOVENODE;
1237         event.p = p;
1238
1239         bool succeeded = true;
1240         try{
1241                 core::map<v3s16, MapBlock*> modified_blocks;
1242                 removeNodeAndUpdate(p, modified_blocks);
1243
1244                 // Copy modified_blocks to event
1245                 for(core::map<v3s16, MapBlock*>::Iterator
1246                                 i = modified_blocks.getIterator();
1247                                 i.atEnd()==false; i++)
1248                 {
1249                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1250                 }
1251         }
1252         catch(InvalidPositionException &e){
1253                 succeeded = false;
1254         }
1255
1256         dispatchEvent(&event);
1257
1258         return succeeded;
1259 }
1260
1261 bool Map::dayNightDiffed(v3s16 blockpos)
1262 {
1263         try{
1264                 v3s16 p = blockpos + v3s16(0,0,0);
1265                 MapBlock *b = getBlockNoCreate(p);
1266                 if(b->dayNightDiffed())
1267                         return true;
1268         }
1269         catch(InvalidPositionException &e){}
1270         // Leading edges
1271         try{
1272                 v3s16 p = blockpos + v3s16(-1,0,0);
1273                 MapBlock *b = getBlockNoCreate(p);
1274                 if(b->dayNightDiffed())
1275                         return true;
1276         }
1277         catch(InvalidPositionException &e){}
1278         try{
1279                 v3s16 p = blockpos + v3s16(0,-1,0);
1280                 MapBlock *b = getBlockNoCreate(p);
1281                 if(b->dayNightDiffed())
1282                         return true;
1283         }
1284         catch(InvalidPositionException &e){}
1285         try{
1286                 v3s16 p = blockpos + v3s16(0,0,-1);
1287                 MapBlock *b = getBlockNoCreate(p);
1288                 if(b->dayNightDiffed())
1289                         return true;
1290         }
1291         catch(InvalidPositionException &e){}
1292         // Trailing edges
1293         try{
1294                 v3s16 p = blockpos + v3s16(1,0,0);
1295                 MapBlock *b = getBlockNoCreate(p);
1296                 if(b->dayNightDiffed())
1297                         return true;
1298         }
1299         catch(InvalidPositionException &e){}
1300         try{
1301                 v3s16 p = blockpos + v3s16(0,1,0);
1302                 MapBlock *b = getBlockNoCreate(p);
1303                 if(b->dayNightDiffed())
1304                         return true;
1305         }
1306         catch(InvalidPositionException &e){}
1307         try{
1308                 v3s16 p = blockpos + v3s16(0,0,1);
1309                 MapBlock *b = getBlockNoCreate(p);
1310                 if(b->dayNightDiffed())
1311                         return true;
1312         }
1313         catch(InvalidPositionException &e){}
1314
1315         return false;
1316 }
1317
1318 /*
1319         Updates usage timers
1320 */
1321 void Map::timerUpdate(float dtime)
1322 {
1323         JMutexAutoLock lock(m_sector_mutex);
1324
1325         core::map<v2s16, MapSector*>::Iterator si;
1326
1327         si = m_sectors.getIterator();
1328         for(; si.atEnd() == false; si++)
1329         {
1330                 MapSector *sector = si.getNode()->getValue();
1331                 sector->usage_timer += dtime;
1332         }
1333 }
1334
1335 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
1336 {
1337         /*
1338                 Wait for caches to be removed before continuing.
1339                 
1340                 This disables the existence of caches while locked
1341         */
1342         //SharedPtr<JMutexAutoLock> cachelock(m_blockcachelock.waitCaches());
1343
1344         core::list<v2s16>::Iterator j;
1345         for(j=list.begin(); j!=list.end(); j++)
1346         {
1347                 MapSector *sector = m_sectors[*j];
1348                 if(only_blocks)
1349                 {
1350                         sector->deleteBlocks();
1351                 }
1352                 else
1353                 {
1354                         /*
1355                                 If sector is in sector cache, remove it from there
1356                         */
1357                         if(m_sector_cache == sector)
1358                         {
1359                                 m_sector_cache = NULL;
1360                         }
1361                         /*
1362                                 Remove from map and delete
1363                         */
1364                         m_sectors.remove(*j);
1365                         delete sector;
1366                 }
1367         }
1368 }
1369
1370 u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
1371                 core::list<v3s16> *deleted_blocks)
1372 {
1373         JMutexAutoLock lock(m_sector_mutex);
1374
1375         core::list<v2s16> sector_deletion_queue;
1376         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
1377         for(; i.atEnd() == false; i++)
1378         {
1379                 MapSector *sector = i.getNode()->getValue();
1380                 /*
1381                         Delete sector from memory if it hasn't been used in a long time
1382                 */
1383                 if(sector->usage_timer > timeout)
1384                 {
1385                         sector_deletion_queue.push_back(i.getNode()->getKey());
1386                         
1387                         if(deleted_blocks != NULL)
1388                         {
1389                                 // Collect positions of blocks of sector
1390                                 MapSector *sector = i.getNode()->getValue();
1391                                 core::list<MapBlock*> blocks;
1392                                 sector->getBlocks(blocks);
1393                                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1394                                                 i != blocks.end(); i++)
1395                                 {
1396                                         deleted_blocks->push_back((*i)->getPos());
1397                                 }
1398                         }
1399                 }
1400         }
1401         deleteSectors(sector_deletion_queue, only_blocks);
1402         return sector_deletion_queue.getSize();
1403 }
1404
1405 void Map::PrintInfo(std::ostream &out)
1406 {
1407         out<<"Map: ";
1408 }
1409
1410 #define WATER_DROP_BOOST 4
1411
1412 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1413 {
1414         DSTACK(__FUNCTION_NAME);
1415         //TimeTaker timer("transformLiquids()");
1416
1417         u32 loopcount = 0;
1418         u32 initial_size = m_transforming_liquid.size();
1419         
1420         /*if(initial_size != 0)
1421                 dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1422
1423         while(m_transforming_liquid.size() != 0)
1424         {
1425                 try
1426                 {
1427
1428                 /*
1429                         Get a queued transforming liquid node
1430                 */
1431                 v3s16 p0 = m_transforming_liquid.pop_front();
1432
1433                 MapNode n0 = getNode(p0);
1434                 
1435                 // Don't deal with non-liquids
1436                 if(content_liquid(n0.d) == false)
1437                         continue;
1438
1439                 bool is_source = !content_flowing_liquid(n0.d);
1440                 
1441                 u8 liquid_level = 8;
1442                 if(is_source == false)
1443                         liquid_level = n0.param2 & 0x0f;
1444                 
1445                 // Turn possible source into non-source
1446                 u8 nonsource_c = make_liquid_flowing(n0.d);
1447
1448                 /*
1449                         If not source, check that some node flows into this one
1450                         and what is the level of liquid in this one
1451                 */
1452                 if(is_source == false)
1453                 {
1454                         s8 new_liquid_level_max = -1;
1455
1456                         v3s16 dirs_from[5] = {
1457                                 v3s16(0,1,0), // top
1458                                 v3s16(0,0,1), // back
1459                                 v3s16(1,0,0), // right
1460                                 v3s16(0,0,-1), // front
1461                                 v3s16(-1,0,0), // left
1462                         };
1463                         for(u16 i=0; i<5; i++)
1464                         {
1465                                 try
1466                                 {
1467
1468                                 bool from_top = (i==0);
1469
1470                                 v3s16 p2 = p0 + dirs_from[i];
1471                                 MapNode n2 = getNode(p2);
1472
1473                                 if(content_liquid(n2.d))
1474                                 {
1475                                         u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1476                                         // Check that the liquids are the same type
1477                                         if(n2_nonsource_c != nonsource_c)
1478                                         {
1479                                                 dstream<<"WARNING: Not handling: different liquids"
1480                                                                 " collide"<<std::endl;
1481                                                 continue;
1482                                         }
1483                                         bool n2_is_source = !content_flowing_liquid(n2.d);
1484                                         s8 n2_liquid_level = 8;
1485                                         if(n2_is_source == false)
1486                                                 n2_liquid_level = n2.param2 & 0x07;
1487                                         
1488                                         s8 new_liquid_level = -1;
1489                                         if(from_top)
1490                                         {
1491                                                 //new_liquid_level = 7;
1492                                                 if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
1493                                                         new_liquid_level = 7;
1494                                                 else
1495                                                         new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
1496                                         }
1497                                         else if(n2_liquid_level > 0)
1498                                         {
1499                                                 new_liquid_level = n2_liquid_level - 1;
1500                                         }
1501
1502                                         if(new_liquid_level > new_liquid_level_max)
1503                                                 new_liquid_level_max = new_liquid_level;
1504                                 }
1505
1506                                 }catch(InvalidPositionException &e)
1507                                 {
1508                                 }
1509                         } //for
1510                         
1511                         /*
1512                                 If liquid level should be something else, update it and
1513                                 add all the neighboring water nodes to the transform queue.
1514                         */
1515                         if(new_liquid_level_max != liquid_level)
1516                         {
1517                                 if(new_liquid_level_max == -1)
1518                                 {
1519                                         // Remove water alltoghether
1520                                         n0.d = CONTENT_AIR;
1521                                         n0.param2 = 0;
1522                                         setNode(p0, n0);
1523                                 }
1524                                 else
1525                                 {
1526                                         n0.param2 = new_liquid_level_max;
1527                                         setNode(p0, n0);
1528                                 }
1529                                 
1530                                 // Block has been modified
1531                                 {
1532                                         v3s16 blockpos = getNodeBlockPos(p0);
1533                                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1534                                         if(block != NULL)
1535                                                 modified_blocks.insert(blockpos, block);
1536                                 }
1537                                 
1538                                 /*
1539                                         Add neighboring non-source liquid nodes to transform queue.
1540                                 */
1541                                 v3s16 dirs[6] = {
1542                                         v3s16(0,0,1), // back
1543                                         v3s16(0,1,0), // top
1544                                         v3s16(1,0,0), // right
1545                                         v3s16(0,0,-1), // front
1546                                         v3s16(0,-1,0), // bottom
1547                                         v3s16(-1,0,0), // left
1548                                 };
1549                                 for(u16 i=0; i<6; i++)
1550                                 {
1551                                         try
1552                                         {
1553
1554                                         v3s16 p2 = p0 + dirs[i];
1555                                         
1556                                         MapNode n2 = getNode(p2);
1557                                         if(content_flowing_liquid(n2.d))
1558                                         {
1559                                                 m_transforming_liquid.push_back(p2);
1560                                         }
1561                                         
1562                                         }catch(InvalidPositionException &e)
1563                                         {
1564                                         }
1565                                 }
1566                         }
1567                 }
1568                 
1569                 // Get a new one from queue if the node has turned into non-water
1570                 if(content_liquid(n0.d) == false)
1571                         continue;
1572
1573                 /*
1574                         Flow water from this node
1575                 */
1576                 v3s16 dirs_to[5] = {
1577                         v3s16(0,-1,0), // bottom
1578                         v3s16(0,0,1), // back
1579                         v3s16(1,0,0), // right
1580                         v3s16(0,0,-1), // front
1581                         v3s16(-1,0,0), // left
1582                 };
1583                 for(u16 i=0; i<5; i++)
1584                 {
1585                         try
1586                         {
1587
1588                         bool to_bottom = (i == 0);
1589
1590                         // If liquid is at lowest possible height, it's not going
1591                         // anywhere except down
1592                         if(liquid_level == 0 && to_bottom == false)
1593                                 continue;
1594                         
1595                         u8 liquid_next_level = 0;
1596                         // If going to bottom
1597                         if(to_bottom)
1598                         {
1599                                 //liquid_next_level = 7;
1600                                 if(liquid_level >= 7 - WATER_DROP_BOOST)
1601                                         liquid_next_level = 7;
1602                                 else
1603                                         liquid_next_level = liquid_level + WATER_DROP_BOOST;
1604                         }
1605                         else
1606                                 liquid_next_level = liquid_level - 1;
1607
1608                         bool n2_changed = false;
1609                         bool flowed = false;
1610                         
1611                         v3s16 p2 = p0 + dirs_to[i];
1612
1613                         MapNode n2 = getNode(p2);
1614                         //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
1615
1616                         if(content_liquid(n2.d))
1617                         {
1618                                 u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1619                                 // Check that the liquids are the same type
1620                                 if(n2_nonsource_c != nonsource_c)
1621                                 {
1622                                         dstream<<"WARNING: Not handling: different liquids"
1623                                                         " collide"<<std::endl;
1624                                         continue;
1625                                 }
1626                                 bool n2_is_source = !content_flowing_liquid(n2.d);
1627                                 u8 n2_liquid_level = 8;
1628                                 if(n2_is_source == false)
1629                                         n2_liquid_level = n2.param2 & 0x07;
1630                                 
1631                                 if(to_bottom)
1632                                 {
1633                                         flowed = true;
1634                                 }
1635
1636                                 if(n2_is_source)
1637                                 {
1638                                         // Just flow into the source, nothing changes.
1639                                         // n2_changed is not set because destination didn't change
1640                                         flowed = true;
1641                                 }
1642                                 else
1643                                 {
1644                                         if(liquid_next_level > liquid_level)
1645                                         {
1646                                                 n2.param2 = liquid_next_level;
1647                                                 setNode(p2, n2);
1648
1649                                                 n2_changed = true;
1650                                                 flowed = true;
1651                                         }
1652                                 }
1653                         }
1654                         else if(n2.d == CONTENT_AIR)
1655                         {
1656                                 n2.d = nonsource_c;
1657                                 n2.param2 = liquid_next_level;
1658                                 setNode(p2, n2);
1659                                 
1660                                 n2_changed = true;
1661                                 flowed = true;
1662                         }
1663                         
1664                         //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl;
1665
1666                         if(n2_changed)
1667                         {
1668                                 m_transforming_liquid.push_back(p2);
1669                                 
1670                                 v3s16 blockpos = getNodeBlockPos(p2);
1671                                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1672                                 if(block != NULL)
1673                                         modified_blocks.insert(blockpos, block);
1674                         }
1675                         
1676                         // If n2_changed to bottom, don't flow anywhere else
1677                         if(to_bottom && flowed && !is_source)
1678                                 break;
1679                                 
1680                         }catch(InvalidPositionException &e)
1681                         {
1682                         }
1683                 }
1684
1685                 loopcount++;
1686                 if(loopcount >= initial_size * 1 || loopcount >= 1000)
1687                         break;
1688                         
1689                 }catch(InvalidPositionException &e)
1690                 {
1691                 }
1692         }
1693         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1694 }
1695
1696 /*
1697         ServerMap
1698 */
1699
1700 ServerMap::ServerMap(std::string savedir):
1701         Map(dout_server),
1702         m_seed(0)
1703 {
1704         
1705         //m_chunksize = 64;
1706         //m_chunksize = 16; // Too slow
1707         //m_chunksize = 8; // Takes a few seconds
1708         m_chunksize = 4; // Too small?
1709         //m_chunksize = 2;
1710         
1711         // TODO: Save to and load from a file
1712         m_seed = (((u64)(myrand()%0xffff)<<0)
1713                         + ((u64)(myrand()%0xffff)<<16)
1714                         + ((u64)(myrand()%0xffff)<<32)
1715                         + ((u64)(myrand()%0xffff)<<48));
1716
1717         /*
1718                 Experimental and debug stuff
1719         */
1720         
1721         {
1722         }
1723         
1724         /*
1725                 Try to load map; if not found, create a new one.
1726         */
1727
1728         m_savedir = savedir;
1729         m_map_saving_enabled = false;
1730         
1731         try
1732         {
1733                 // If directory exists, check contents and load if possible
1734                 if(fs::PathExists(m_savedir))
1735                 {
1736                         // If directory is empty, it is safe to save into it.
1737                         if(fs::GetDirListing(m_savedir).size() == 0)
1738                         {
1739                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1740                                                 <<std::endl;
1741                                 m_map_saving_enabled = true;
1742                         }
1743                         else
1744                         {
1745                                 // Load map metadata (seed, chunksize)
1746                                 loadMapMeta();
1747                                 
1748                                 // Load chunk metadata
1749                                 loadChunkMeta();
1750                         
1751                                 /*// Load sector (0,0) and throw and exception on fail
1752                                 if(loadSectorFull(v2s16(0,0)) == false)
1753                                         throw LoadError("Failed to load sector (0,0)");*/
1754
1755                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1756                                                 "metadata and sector (0,0) from "<<savedir<<
1757                                                 ", assuming valid save directory."
1758                                                 <<std::endl;*/
1759
1760                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1761                                                 <<"and chunk metadata from "<<savedir
1762                                                 <<", assuming valid save directory."
1763                                                 <<std::endl;
1764
1765                                 m_map_saving_enabled = true;
1766                                 // Map loaded, not creating new one
1767                                 return;
1768                         }
1769                 }
1770                 // If directory doesn't exist, it is safe to save to it
1771                 else{
1772                         m_map_saving_enabled = true;
1773                 }
1774         }
1775         catch(std::exception &e)
1776         {
1777                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1778                                 <<", exception: "<<e.what()<<std::endl;
1779                 dstream<<"Please remove the map or fix it."<<std::endl;
1780                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1781         }
1782
1783         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1784         
1785         // Create zero sector
1786         emergeSector(v2s16(0,0));
1787
1788         // Initially write whole map
1789         save(false);
1790 }
1791
1792 ServerMap::~ServerMap()
1793 {
1794         try
1795         {
1796                 if(m_map_saving_enabled)
1797                 {
1798                         //save(false);
1799                         // Save only changed parts
1800                         save(true);
1801                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1802                 }
1803                 else
1804                 {
1805                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1806                 }
1807         }
1808         catch(std::exception &e)
1809         {
1810                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1811                                 <<", exception: "<<e.what()<<std::endl;
1812         }
1813         
1814         /*
1815                 Free all MapChunks
1816         */
1817         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1818         for(; i.atEnd() == false; i++)
1819         {
1820                 MapChunk *chunk = i.getNode()->getValue();
1821                 delete chunk;
1822         }
1823 }
1824
1825 /*
1826         Some helper functions for the map generator
1827 */
1828
1829 s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
1830 {
1831         v3s16 em = vmanip.m_area.getExtent();
1832         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1833         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1834         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1835         s16 y;
1836         for(y=y_nodes_max; y>=y_nodes_min; y--)
1837         {
1838                 MapNode &n = vmanip.m_data[i];
1839                 if(content_walkable(n.d))
1840                         break;
1841                         
1842                 vmanip.m_area.add_y(em, i, -1);
1843         }
1844         if(y >= y_nodes_min)
1845                 return y;
1846         else
1847                 return y_nodes_min;
1848 }
1849
1850 s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
1851 {
1852         v3s16 em = vmanip.m_area.getExtent();
1853         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1854         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1855         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1856         s16 y;
1857         for(y=y_nodes_max; y>=y_nodes_min; y--)
1858         {
1859                 MapNode &n = vmanip.m_data[i];
1860                 if(content_walkable(n.d)
1861                                 && n.d != CONTENT_TREE
1862                                 && n.d != CONTENT_LEAVES)
1863                         break;
1864                         
1865                 vmanip.m_area.add_y(em, i, -1);
1866         }
1867         if(y >= y_nodes_min)
1868                 return y;
1869         else
1870                 return y_nodes_min;
1871 }
1872
1873 void make_tree(VoxelManipulator &vmanip, v3s16 p0)
1874 {
1875         MapNode treenode(CONTENT_TREE);
1876         MapNode leavesnode(CONTENT_LEAVES);
1877
1878         vmanip.emerge(VoxelArea(p0-v3s16(2,0,2),p0+v3s16(2,7+2,2)));
1879
1880         s16 trunk_h = myrand_range(4, 7);
1881         v3s16 p1 = p0;
1882         for(s16 ii=0; ii<trunk_h; ii++)
1883         {
1884                 if(vmanip.m_area.contains(p1))
1885                         vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
1886                 p1.Y++;
1887         }
1888         
1889         // p1 is now the last piece of the trunk
1890         p1.Y -= 1;
1891
1892         VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
1893         //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
1894         Buffer<u8> leaves_d(leaves_a.getVolume());
1895         for(s32 i=0; i<leaves_a.getVolume(); i++)
1896                 leaves_d[i] = 0;
1897         
1898         // Force leaves at near the end of the trunk
1899         {
1900                 s16 d = 1;
1901                 for(s16 z=-d; z<=d; z++)
1902                 for(s16 y=-d; y<=d; y++)
1903                 for(s16 x=-d; x<=d; x++)
1904                 {
1905                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
1906                 }
1907         }
1908         
1909         // Add leaves randomly
1910         for(u32 iii=0; iii<7; iii++)
1911         {
1912                 s16 d = 1;
1913
1914                 v3s16 p(
1915                         myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
1916                         myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
1917                         myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
1918                 );
1919                 
1920                 for(s16 z=0; z<=d; z++)
1921                 for(s16 y=0; y<=d; y++)
1922                 for(s16 x=0; x<=d; x++)
1923                 {
1924                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
1925                 }
1926         }
1927         
1928         // Blit leaves to vmanip
1929         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
1930         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
1931         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
1932         {
1933                 v3s16 p(x,y,z);
1934                 p += p1;
1935                 if(vmanip.m_area.contains(p) == false)
1936                         continue;
1937                 u32 vi = vmanip.m_area.index(p);
1938                 if(vmanip.m_data[vi].d != CONTENT_AIR)
1939                         continue;
1940                 u32 i = leaves_a.index(x,y,z);
1941                 if(leaves_d[i] == 1)
1942                         vmanip.m_data[vi] = leavesnode;
1943         }
1944 }
1945
1946 /*
1947         Noise functions. Make sure seed is mangled differently in each one.
1948 */
1949
1950 // Amount of trees per area in nodes
1951 double tree_amount_2d(u64 seed, v2s16 p)
1952 {
1953         double noise = noise2d_perlin(
1954                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1955                         seed+2, 5, 0.66);
1956         double zeroval = -0.3;
1957         if(noise < zeroval)
1958                 return 0;
1959         else
1960                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1961 }
1962
1963 #define AVERAGE_MUD_AMOUNT 4.0
1964
1965 double get_mud_amount(u64 seed, v2f p)
1966 {
1967         return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1968                         0.5+p.X/200, 0.5+p.Y/200,
1969                         seed+1, 5, 0.65));
1970 }
1971
1972 bool get_have_sand(u64 seed, v2f p)
1973 {
1974         double sandnoise = noise2d_perlin(
1975                         0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1976                         seed+59420, 3, 0.50);
1977         return (sandnoise > -0.15);
1978 }
1979
1980 // -1->0, 0->1, 1->0
1981 double contour(double v)
1982 {
1983         v = fabs(v);
1984         if(v >= 1.0)
1985                 return 0.0;
1986         return (1.0-v);
1987 }
1988
1989 // -1->0, -r->1, 0->1, r->1, 1->0
1990 double contour_flat_top(double v, double r)
1991 {
1992         v = fabs(v);
1993         if(v >= 1.0)
1994                 return 0.0;
1995         double rmax = 0.999;
1996         if(r >= rmax)
1997                 r = rmax;
1998         if(v <= r)
1999                 return 1.0;
2000         v -= r;
2001         return ((1.0-r)-v) / (1.0-r);
2002         //return easeCurve(((1.0-r)-v) / (1.0-r));
2003 }
2004
2005 double base_rock_level_2d(u64 seed, v2f p)
2006 {
2007         // The ground level (return value)
2008         double h = WATER_LEVEL;
2009         
2010         // Raises from 0 when parameter is -1...1
2011         /*double m2 = contour_flat_top(-0.8 + 2.0 * noise2d_perlin(
2012                         0.0+(float)p.X/1500., 0.0+(float)p.Y/1500.,
2013                         (seed>>32)+34758, 5, 0.55), 0.10);*/
2014         /*double m2 = 1.0;
2015         if(m2 > 0.0001)
2016         {
2017                 // HUGE mountains
2018                 double m1 = 200.0 + 300.0 * noise2d_perlin(
2019                                 0.0+(float)p.X/1000., 0.0+(float)p.Y/1000.,
2020                                 (seed>>32)+98525, 8, 0.5);
2021                 h += m1 * m2;
2022                 //h += 30 * m2;
2023         }*/
2024
2025         /*double tm2 = contour_flat_top(-1.0 + 3.0 * noise2d_perlin(
2026                         0.0+(float)p.X/300., 0.0+(float)p.Y/300.,
2027                         (seed>>32)+78593, 5, 0.55), 0.15);
2028         h += 30 * tm2;*/
2029
2030 #if 1
2031         // Huge mountains
2032         double m3 = 150.0 - 500.0 * noise2d_perlin_abs(
2033                         0.324+(float)p.X/2000., 0.423+(float)p.Y/2000.,
2034                         (seed>>32)+985251, 9, 0.55);
2035         if(m3 > h)
2036                 h = m3;
2037 #endif
2038
2039 #if 1
2040         // Some kind of hill chains or something
2041         {
2042                 double a1 = 30 - 130. * noise2d_perlin_abs(
2043                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2044                                 seed+850342, 6, 0.63);
2045                 double d = 15;
2046                 if(a1 > d)
2047                         a1 = d + sqrt(a1-d);
2048                 /*if(a1 > h)
2049                         h = a1;*/
2050                 if(a1 > 0)
2051                         h += a1;
2052         }
2053 #endif
2054
2055 #if 1
2056         double base = -5. + 25. * noise2d_perlin(
2057                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2058                         (seed>>32)+653876, 7, 0.6);
2059 #else
2060         double base = 0;
2061 #endif
2062         
2063 #if 1
2064         double higher = 40. * noise2d_perlin(
2065                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2066                         seed+39292, 7, 0.55);
2067         /*double higher = 50. * noise2d_perlin_abs(
2068                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2069                         seed+85039, 5, 0.63);*/
2070         //higher = 25;
2071
2072         if(higher > base)
2073         {
2074                 // Steepness factor of cliffs
2075                 double b = 1.0 + 1.0 * noise2d_perlin(
2076                                 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2077                                 seed-932, 7, 0.7);
2078                 b = rangelim(b, 0.0, 1000.0);
2079 #if 1
2080                 b = pow(b, 5);
2081                 b *= 16;
2082                 b = rangelim(b, 3.0, 1000.0);
2083                 //dstream<<"b="<<b<<std::endl;
2084                 //double b = 20;
2085                 // Offset to more low
2086                 //double a_off = -0.30;
2087                 double a_off = -0.00;
2088                 // High/low selector
2089                 double a = (double)0.5 + b * (a_off + noise2d_perlin(
2090                                 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2091                                 seed-359, 6, 0.70));
2092 #endif
2093 #if 0
2094                 /*b = pow(b, 5);
2095                 b *= 2;
2096                 b = rangelim(b, 3.0, 20.0);*/
2097                 //b = 10.0;
2098                 double a = -1.5 + 5.0 * (noise2d_perlin_abs(
2099                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2100                                 seed-359, 6, 0.6));
2101                 a *= 3.0;
2102                 /*double a = 5.0 * (noise2d_perlin(
2103                                 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2104                                 seed-359, 5, 0.6));*/
2105                 //a = contour_flat_top(a, 0.2);
2106 #endif
2107                 // Limit
2108                 a = rangelim(a, 0.0, 1.0);
2109                 a = easeCurve(a);
2110
2111                 //dstream<<"a="<<a<<std::endl;
2112
2113                 /*double h2 = higher * a;
2114                 if(h2 > h)
2115                         h = h2;*/
2116                 
2117                 h += base*(1.0-a) + higher*a;
2118         }
2119         else
2120         {
2121                 h += base;
2122         }
2123 #else
2124         h += base;
2125 #endif
2126
2127         return h;
2128 }
2129
2130 double base_rock_level_2d(u64 seed, v2s16 p)
2131 {
2132         return base_rock_level_2d(seed, v2f((float)p.X, (float)p.Y));
2133 }
2134
2135 v2f base_ground_turbulence(u64 seed, v3f p)
2136 {
2137 #if 1
2138         double f = 20;
2139
2140         double vv = 1.0 - 1.0 * noise3d_perlin_abs(
2141                         0.5+p.X/500,
2142                         0.5+p.Y/500,
2143                         0.5+p.Z/500,
2144                         seed+1324031, 4, 0.5);
2145         //double vve = 1.0 - exp(-MYMAX(0, vv*2.0));
2146         double vve = MYMAX(0, vv);
2147         //dstream<<"vve="<<vve<<std::endl;
2148
2149         double v1 = f * noise3d_perlin(
2150                         0.5+p.X/200,
2151                         0.5+p.Y/200,
2152                         0.5+p.Z/200,
2153                         seed+4045, 6, 0.7);
2154
2155         double v2 = f * noise3d_perlin(
2156                         0.5+p.X/200,
2157                         0.5+p.Y/200,
2158                         0.5+p.Z/200,
2159                         seed+9495, 6, 0.7);
2160         
2161         return v2f(v1*vve, v2*vve);
2162 #else
2163         return v2f(0,0);
2164 #endif
2165 }
2166
2167 bool is_carved(u64 seed, v3f p)
2168 {
2169 #if 1
2170         double v1 = noise3d_perlin_abs(
2171                         0.5+p.X/200,
2172                         0.5+p.Y/200,
2173                         0.5+p.Z/200,
2174                         seed+657890854, 5, 0.7);
2175         
2176         if(v1 > 1.45)
2177                 return true;
2178 #endif
2179
2180         double f = 10.0;
2181         double y_div = 1.5;
2182
2183         double v4 = contour(f*noise3d_perlin(
2184                         0.5+p.X/200,
2185                         0.5+p.Y/200*y_div,
2186                         0.5+p.Z/200,
2187                         seed+87592, 5, 0.7));
2188         // Tilted 90 degrees
2189         double v5 = contour(f*noise3d_perlin(
2190                         0.5+p.X/200,
2191                         0.5+p.Z/200,
2192                         0.5+p.Y/200*y_div,
2193                         seed+98594, 5, 0.7));
2194         
2195         double v45 = v4*v5;
2196         if(v45 > 2.5/f)
2197                 return true;
2198         
2199         return false;
2200 }
2201
2202 bool is_underground_mud(u64 seed, v3f p)
2203 {
2204         double v1 = noise3d_perlin_abs(
2205                         0.5+p.X/50,
2206                         0.5+p.Y/50,
2207                         0.5+p.Z/50,
2208                         seed+83401, 5, 0.75);
2209         return (v1 > 1.3);
2210 }
2211         
2212 /*
2213         if depth_guess!=NULL, it is set to a guessed value of how deep
2214         underground the position is.
2215 */
2216 bool is_base_ground(u64 seed, v3f p, double *depth_guess=NULL)
2217 {
2218 #if 0
2219         // This is used for testing the output of the cave function
2220         {
2221                 if(depth_guess)
2222                         *depth_guess = 10;
2223                 if(p.Y > 50)
2224                         return false;
2225                 return is_carved(seed, p);
2226         }
2227 #endif
2228 #if 0
2229         // This is used for testing the output of the underground mud function
2230         {
2231                 if(depth_guess)
2232                         *depth_guess = 10;
2233                 if(p.Y > 50)
2234                         return false;
2235                 return is_underground_mud(seed, p);
2236         }
2237 #endif
2238
2239         v2f t = base_ground_turbulence(seed, p);
2240
2241         double surface_y_f = base_rock_level_2d(seed, v2f(p.X+t.X, p.Z+t.Y));
2242
2243         /*if(depth_guess)
2244                 *depth_guess = surface_y_f - p.Y;*/
2245         
2246         if(depth_guess)
2247         {
2248                 // Find highest surface near current
2249                 v3f dirs[4] = {
2250                         v3f(1,0,0),
2251                         v3f(-1,0,0),
2252                         v3f(0,0,1),
2253                         v3f(0,0,-1)
2254                 };
2255                 double s2 = surface_y_f;
2256                 for(u32 i=0; i<4; i++)
2257                 {
2258                         v3f dir = dirs[i];
2259                         // Get turbulence at around there
2260                         v2f t2 = base_ground_turbulence(seed, p+dir);
2261                         // Get ground height
2262                         v2f l = v2f(p.X+t2.X+dir.X, p.Z+t2.Y+dir.Z);
2263                         double s = base_rock_level_2d(seed, l);
2264                         if(s > s2)
2265                                 s2 = s;
2266                 }
2267                 *depth_guess = s2 - p.Y;
2268         }
2269         
2270         /*if(depth_guess)
2271         {
2272                 // Check a bit lower also, take highest surface
2273                 v2f t2 = base_ground_turbulence(seed, p + v3f(0,-2,0));
2274                 double s2 = base_rock_level_2d(seed, v2f(p.X+t2.X, p.Z+t2.Y));
2275                 if(s2 > surface_y_f)
2276                         *depth_guess = s2 - p.Y;
2277                 else
2278                         *depth_guess = surface_y_f - p.Y;
2279         }*/
2280         
2281         /*if(depth_guess)
2282         {
2283                 // Guess surface point
2284                 v3f p2(p.X, surface_y_f, p.Z);
2285                 v2f t2 = base_ground_turbulence
2286                 double u1 = 
2287                 double s1 = base_rock_level_2d(seed, v2f(p.X+v1,p.Z+v2));
2288         }*/
2289
2290         bool is_ground = (p.Y <= surface_y_f);
2291
2292 #if 1
2293         if(is_carved(seed, p))
2294                 is_ground = false;
2295 #endif
2296
2297         return is_ground;
2298 }
2299
2300 #define VMANIP_FLAG_DUNGEON VOXELFLAG_CHECKED1
2301
2302 /*
2303         This is the main map generation method
2304 */
2305
2306 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
2307                 core::map<v3s16, MapBlock*> &changed_blocks,
2308                 bool force)
2309 {
2310         DSTACK(__FUNCTION_NAME);
2311
2312         // Shall be not used now
2313         //assert(0);
2314
2315 #if 0
2316
2317         /*
2318                 Don't generate if already fully generated
2319         */
2320         if(force == false)
2321         {
2322                 MapChunk *chunk = getChunk(chunkpos);
2323                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
2324                 {
2325                         dstream<<"generateChunkRaw(): Chunk "
2326                                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2327                                         <<" already generated"<<std::endl;
2328                         return chunk;
2329                 }
2330         }
2331
2332         dstream<<"generateChunkRaw(): Generating chunk "
2333                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2334                         <<std::endl;
2335         
2336         TimeTaker timer("generateChunkRaw()");
2337         
2338         // The distance how far into the neighbors the generator is allowed to go.
2339         s16 max_spread_amount_sectors = 2;
2340         assert(max_spread_amount_sectors <= m_chunksize);
2341         s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
2342
2343         // Minimum amount of space left on sides for mud to fall in
2344         //s16 min_mud_fall_space = 2;
2345         
2346         // Maximum diameter of stone obstacles in X and Z
2347         /*s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
2348         assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);*/
2349         
2350         s16 y_blocks_min = -4;
2351         s16 y_blocks_max = 3;
2352         s16 h_blocks = y_blocks_max - y_blocks_min + 1;
2353         s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
2354         s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
2355
2356         v2s16 sectorpos_base = chunk_to_sector(chunkpos);
2357         s16 sectorpos_base_size = m_chunksize;
2358
2359         /*v2s16 sectorpos_bigbase = chunk_to_sector(chunkpos - v2s16(1,1));
2360         s16 sectorpos_bigbase_size = m_chunksize * 3;*/
2361         v2s16 sectorpos_bigbase =
2362                         sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
2363         s16 sectorpos_bigbase_size =
2364                         sectorpos_base_size + 2 * max_spread_amount_sectors;
2365
2366         v3s16 bigarea_blocks_min(
2367                 sectorpos_bigbase.X,
2368                 y_blocks_min,
2369                 sectorpos_bigbase.Y
2370         );
2371
2372         v3s16 bigarea_blocks_max(
2373                 sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
2374                 y_blocks_max,
2375                 sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
2376         );
2377         
2378         // Relative values to control amount of stuff in one chunk
2379         /*u32 relative_area = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2380                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE;*/
2381         u32 relative_volume = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2382                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE
2383                         *(u32)h_blocks*MAP_BLOCKSIZE;
2384                 
2385         /*
2386                 The limiting edges of the lighting update, inclusive.
2387         */
2388         s16 lighting_min_d = 0-max_spread_amount;
2389         s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
2390
2391         /*
2392                 Create the whole area of this and the neighboring chunks
2393         */
2394         {
2395                 TimeTaker timer("generateChunkRaw() create area");
2396                 
2397                 for(s16 x=0; x<sectorpos_bigbase_size; x++)
2398                 for(s16 z=0; z<sectorpos_bigbase_size; z++)
2399                 {
2400                         v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
2401                         ServerMapSector *sector = createSector(sectorpos);
2402                         assert(sector);
2403
2404                         for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
2405                         {
2406                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
2407                                 MapBlock *block = createBlock(blockpos);
2408
2409                                 // Lighting won't be calculated
2410                                 //block->setLightingExpired(true);
2411                                 // Lighting will be calculated
2412                                 block->setLightingExpired(false);
2413
2414                                 /*
2415                                         Block gets sunlight if this is true.
2416
2417                                         This should be set to true when the top side of a block
2418                                         is completely exposed to the sky.
2419
2420                                         Actually this doesn't matter now because the
2421                                         initial lighting is done here.
2422                                 */
2423                                 block->setIsUnderground(y != y_blocks_max);
2424                         }
2425                 }
2426         }
2427         
2428         /*
2429                 Now we have a big empty area.
2430
2431                 Make a ManualMapVoxelManipulator that contains this and the
2432                 neighboring chunks
2433         */
2434
2435         ManualMapVoxelManipulator vmanip(this);
2436         // Add the area we just generated
2437         {
2438                 TimeTaker timer("generateChunkRaw() initialEmerge");
2439                 vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2440         }
2441
2442         // Clear all flags
2443         vmanip.clearFlag(0xff);
2444
2445         TimeTaker timer_generate("generateChunkRaw() generate");
2446
2447         // Maximum height of the stone surface and obstacles.
2448         // This is used to disable dungeon generation from going too high.
2449         s16 stone_surface_max_y = 0;
2450
2451         /*
2452                 Generate general ground level to full area
2453         */
2454         
2455         {
2456         // 22ms @cs=8
2457         TimeTaker timer1("ground level");
2458         dstream<<"Generating base ground..."<<std::endl;
2459
2460         for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
2461         for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
2462         {
2463                 // Node position
2464                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2465                 
2466                 /*
2467                         Skip if already generated
2468                 */
2469                 {
2470                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2471                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
2472                                 continue;
2473                 }
2474
2475                 v2f p2df(p2d.X, p2d.Y);
2476
2477                 {
2478                         // Use fast index incrementing
2479                         v3s16 em = vmanip.m_area.getExtent();
2480                         s16 min = y_nodes_min;
2481                         s16 max = y_nodes_max;
2482                         /*s16 min = -10;
2483                         s16 max = 20;*/
2484                         //float surface_y_f = base_rock_level_2d(m_seed, p2df);
2485                         u32 i = vmanip.m_area.index(v3s16(p2d.X, min, p2d.Y));
2486                         for(s16 y=min; y<=max; y++)
2487                         {
2488 #if 1
2489                                 bool is = is_base_ground(m_seed, v3f(p2df.X,y,p2df.Y));
2490                                 if(is)
2491                                         vmanip.m_data[i].d = CONTENT_STONE;
2492                                 else
2493                                         vmanip.m_data[i].d = CONTENT_AIR;
2494 #endif
2495 #if 0
2496                                 double v = noise3d_perlin(
2497                                                 0.5+(float)p2d.X/200,
2498                                                 0.5+(float)y/200,
2499                                                 0.5+(float)p2d.Y/200,
2500                                                 m_seed+293, 6, 0.55);
2501                                 if(v > 0.0)
2502                                         vmanip.m_data[i].d = CONTENT_STONE;
2503                                 else
2504                                         vmanip.m_data[i].d = CONTENT_AIR;
2505 #endif
2506 #if 0
2507                                 /*double v1 = 5 * noise3d_perlin(
2508                                                 0.5+(float)p2df.X/200,
2509                                                 0.5+(float)y/200,
2510                                                 0.5+(float)p2df.Y/200,
2511                                                 m_seed+293, 6, 0.55);
2512
2513                                 double v2 = 5 * noise3d_perlin(
2514                                                 0.5+(float)p2df.X/200,
2515                                                 0.5+(float)y/200,
2516                                                 0.5+(float)p2df.Y/200,
2517                                                 m_seed+293, 6, 0.55);*/
2518
2519                                 double v1 = 0;
2520                                 double v2 = 0;
2521
2522                                 float surface_y_f = base_rock_level_2d(m_seed, p2df+v2f(v1,v2));
2523
2524                                 if(y <= surface_y_f)
2525                                         vmanip.m_data[i].d = CONTENT_STONE;
2526                                 else
2527                                         vmanip.m_data[i].d = CONTENT_AIR;
2528 #endif
2529
2530                                 vmanip.m_area.add_y(em, i, 1);
2531                         }
2532                 }
2533
2534 #if 0
2535                 // Node position
2536                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2537
2538                 /*
2539                         Skip if already generated
2540                 */
2541                 {
2542                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2543                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
2544                                 continue;
2545                 }
2546
2547                 // Ground height at this point
2548                 float surface_y_f = 0.0;
2549
2550                 // Use perlin noise for ground height
2551                 surface_y_f = base_rock_level_2d(m_seed, p2d);
2552                 
2553                 /*// Experimental stuff
2554                 {
2555                         float a = highlands_level_2d(m_seed, p2d);
2556                         if(a > surface_y_f)
2557                                 surface_y_f = a;
2558                 }*/
2559
2560                 // Convert to integer
2561                 s16 surface_y = (s16)surface_y_f;
2562                 
2563                 // Log it
2564                 if(surface_y > stone_surface_max_y)
2565                         stone_surface_max_y = surface_y;
2566
2567                 /*
2568                         Fill ground with stone
2569                 */
2570                 {
2571                         // Use fast index incrementing
2572                         v3s16 em = vmanip.m_area.getExtent();
2573                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
2574                         for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++)
2575                         {
2576                                 vmanip.m_data[i].d = CONTENT_STONE;
2577
2578                                 vmanip.m_area.add_y(em, i, 1);
2579                         }
2580                 }
2581 #endif
2582         }
2583         
2584         }//timer1
2585
2586         /*
2587                 Randomize some parameters
2588         */
2589         
2590         s32 stone_obstacle_count = 0;
2591         /*s32 stone_obstacle_count =
2592                         rangelim((1.0+noise2d(m_seed+897,
2593                         sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2594         
2595         s16 stone_obstacle_max_height = 0;
2596         /*s16 stone_obstacle_max_height =
2597                         rangelim((1.0+noise2d(m_seed+5902,
2598                         sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2599
2600         /*
2601                 Loop this part, it will make stuff look older and newer nicely
2602         */
2603         u32 age_count = 2;
2604         for(u32 i_age=0; i_age<age_count; i_age++)
2605         { // Aging loop
2606
2607         {
2608         // 8ms @cs=8
2609         //TimeTaker timer1("stone obstacles");
2610
2611         /*
2612                 Add some random stone obstacles
2613         */
2614         
2615         for(s32 ri=0; ri<stone_obstacle_count; ri++)
2616         {
2617                 // Randomize max height so usually stuff will be quite low
2618                 s16 maxheight_randomized = myrand_range(0, stone_obstacle_max_height);
2619
2620                 //s16 stone_obstacle_max_size = sectorpos_base_size * MAP_BLOCKSIZE - 10;
2621                 s16 stone_obstacle_max_size = MAP_BLOCKSIZE*4-4;
2622
2623                 v3s16 ob_size(
2624                         myrand_range(5, stone_obstacle_max_size),
2625                         myrand_range(0, maxheight_randomized),
2626                         myrand_range(5, stone_obstacle_max_size)
2627                 );
2628                 
2629                 // Don't make stupid small rectangle bumps
2630                 if(ob_size.Y < 5)
2631                         continue;
2632                 
2633                 v2s16 ob_place(
2634                         myrand_range(1+ob_size.X/2+2,
2635                                         sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.X/2-2),
2636                         myrand_range(1+ob_size.Z/2+2,
2637                                         sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.Z/2-2)
2638                 );
2639                 
2640                 // Minimum space left on top of the obstacle
2641                 s16 min_head_space = 12;
2642                 
2643                 for(s16 x=-ob_size.X/2; x<ob_size.X/2; x++)
2644                 for(s16 z=-ob_size.Z/2; z<ob_size.Z/2; z++)
2645                 {
2646                         // Node position in 2d
2647                         v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + ob_place + v2s16(x,z);
2648                         
2649                         // Find stone ground level
2650                         // (ignore everything else than mud in already generated chunks)
2651                         // and mud amount over the stone level
2652                         s16 surface_y = 0;
2653                         s16 mud_amount = 0;
2654                         {
2655                                 v3s16 em = vmanip.m_area.getExtent();
2656                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2657                                 s16 y;
2658                                 // Go to ground level
2659                                 for(y=y_nodes_max; y>=y_nodes_min; y--)
2660                                 {
2661                                         MapNode *n = &vmanip.m_data[i];
2662                                         /*if(content_walkable(n.d)
2663                                                         && n.d != CONTENT_MUD
2664                                                         && n.d != CONTENT_GRASS)
2665                                                 break;*/
2666                                         if(n->d == CONTENT_STONE)
2667                                                 break;
2668                                         
2669                                         if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
2670                                         {
2671                                                 mud_amount++;
2672                                                 /*
2673                                                         Change to mud because otherwise we might
2674                                                         be throwing mud on grass at the next
2675                                                         step
2676                                                 */
2677                                                 n->d = CONTENT_MUD;
2678                                         }
2679                                                 
2680                                         vmanip.m_area.add_y(em, i, -1);
2681                                 }
2682                                 if(y >= y_nodes_min)
2683                                         surface_y = y;
2684                                 else
2685                                         surface_y = y_nodes_min;
2686                         }
2687
2688
2689                         /*
2690                                 Add stone on ground
2691                         */
2692                         {
2693                                 v3s16 em = vmanip.m_area.getExtent();
2694                                 s16 y_start = surface_y+1;
2695                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2696                                 s16 y;
2697                                 // Add stone
2698                                 s16 count = 0;
2699                                 for(y=y_start; y<=y_nodes_max - min_head_space; y++)
2700                                 {
2701                                         MapNode &n = vmanip.m_data[i];
2702                                         n.d = CONTENT_STONE;
2703
2704                                         if(y > stone_surface_max_y)
2705                                                 stone_surface_max_y = y;
2706
2707                                         count++;
2708                                         if(count >= ob_size.Y)
2709                                                 break;
2710                                                 
2711                                         vmanip.m_area.add_y(em, i, 1);
2712                                 }
2713                                 // Add mud
2714                                 count = 0;
2715                                 for(; y<=y_nodes_max - min_head_space; y++)
2716                                 {
2717                                         MapNode &n = vmanip.m_data[i];
2718                                         n.d = CONTENT_MUD;
2719                                         count++;
2720                                         if(count >= mud_amount)
2721                                                 break;
2722                                                 
2723                                         vmanip.m_area.add_y(em, i, 1);
2724                                 }
2725                         }
2726
2727                 }
2728         }
2729
2730         }//timer1
2731         {
2732         // 24ms @cs=8
2733         //TimeTaker timer1("dungeons");
2734
2735         /*
2736                 Make dungeons
2737         */
2738         u32 dungeons_count = relative_volume / 600000;
2739         u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
2740         if(stone_surface_max_y < WATER_LEVEL)
2741                 bruises_count = 0;
2742         /*u32 dungeons_count = 0;
2743         u32 bruises_count = 0;*/
2744         for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
2745         {
2746                 s16 min_tunnel_diameter = 2;
2747                 s16 max_tunnel_diameter = 6;
2748                 u16 tunnel_routepoints = 25;
2749                 
2750                 bool bruise_surface = (jj < bruises_count);
2751
2752                 if(bruise_surface)
2753                 {
2754                         min_tunnel_diameter = 5;
2755                         max_tunnel_diameter = myrand_range(10, 20);
2756                         /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
2757                         max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
2758                         
2759                         /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(m_seed+42,
2760                                         sectorpos_base.X, sectorpos_base.Y)), 0, 15);*/
2761
2762                         tunnel_routepoints = 5;
2763                 }
2764
2765                 // Allowed route area size in nodes
2766                 v3s16 ar(
2767                         sectorpos_base_size*MAP_BLOCKSIZE,
2768                         h_blocks*MAP_BLOCKSIZE,
2769                         sectorpos_base_size*MAP_BLOCKSIZE
2770                 );
2771
2772                 // Area starting point in nodes
2773                 v3s16 of(
2774                         sectorpos_base.X*MAP_BLOCKSIZE,
2775                         y_blocks_min*MAP_BLOCKSIZE,
2776                         sectorpos_base.Y*MAP_BLOCKSIZE
2777                 );
2778
2779                 // Allow a bit more
2780                 //(this should be more than the maximum radius of the tunnel)
2781                 //s16 insure = 5; // Didn't work with max_d = 20
2782                 s16 insure = 10;
2783                 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
2784                 ar += v3s16(1,0,1) * more * 2;
2785                 of -= v3s16(1,0,1) * more;
2786                 
2787                 s16 route_y_min = 0;
2788                 // Allow half a diameter + 7 over stone surface
2789                 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
2790
2791                 /*// If dungeons, don't go through surface too often
2792                 if(bruise_surface == false)
2793                         route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
2794
2795                 // Limit maximum to area
2796                 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
2797
2798                 if(bruise_surface)
2799                 {
2800                         /*// Minimum is at y=0
2801                         route_y_min = -of.Y - 0;*/
2802                         // Minimum is at y=max_tunnel_diameter/4
2803                         //route_y_min = -of.Y + max_tunnel_diameter/4;
2804                         //s16 min = -of.Y + max_tunnel_diameter/4;
2805                         s16 min = -of.Y + 0;
2806                         route_y_min = myrand_range(min, min + max_tunnel_diameter);
2807                         route_y_min = rangelim(route_y_min, 0, route_y_max);
2808                 }
2809
2810                 /*dstream<<"route_y_min = "<<route_y_min
2811                                 <<", route_y_max = "<<route_y_max<<std::endl;*/
2812
2813                 s16 route_start_y_min = route_y_min;
2814                 s16 route_start_y_max = route_y_max;
2815
2816                 // Start every 2nd dungeon from surface
2817                 bool coming_from_surface = (jj % 2 == 0 && bruise_surface == false);
2818
2819                 if(coming_from_surface)
2820                 {
2821                         route_start_y_min = -of.Y + stone_surface_max_y + 5;
2822                 }
2823                 
2824                 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
2825                 route_start_y_max = rangelim(route_start_y_max, 0, ar.Y-1);
2826
2827                 // Randomize starting position
2828                 v3f orp(
2829                         (float)(myrand()%ar.X)+0.5,
2830                         (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
2831                         (float)(myrand()%ar.Z)+0.5
2832                 );
2833
2834                 MapNode airnode(CONTENT_AIR);
2835                 
2836                 /*
2837                         Generate some tunnel starting from orp
2838                 */
2839                 
2840                 for(u16 j=0; j<tunnel_routepoints; j++)
2841                 {
2842                         // Randomize size
2843                         s16 min_d = min_tunnel_diameter;
2844                         s16 max_d = max_tunnel_diameter;
2845                         s16 rs = myrand_range(min_d, max_d);
2846                         
2847                         v3s16 maxlen;
2848                         if(bruise_surface)
2849                         {
2850                                 maxlen = v3s16(rs*7,rs*7,rs*7);
2851                         }
2852                         else
2853                         {
2854                                 maxlen = v3s16(15, myrand_range(1, 20), 15);
2855                         }
2856
2857                         v3f vec;
2858                         
2859                         if(coming_from_surface && j < 3)
2860                         {
2861                                 vec = v3f(
2862                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2863                                         (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
2864                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2865                                 );
2866                         }
2867                         else
2868                         {
2869                                 vec = v3f(
2870                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2871                                         (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
2872                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2873                                 );
2874                         }
2875
2876                         v3f rp = orp + vec;
2877                         if(rp.X < 0)
2878                                 rp.X = 0;
2879                         else if(rp.X >= ar.X)
2880                                 rp.X = ar.X-1;
2881                         if(rp.Y < route_y_min)
2882                                 rp.Y = route_y_min;
2883                         else if(rp.Y >= route_y_max)
2884                                 rp.Y = route_y_max-1;
2885                         if(rp.Z < 0)
2886                                 rp.Z = 0;
2887                         else if(rp.Z >= ar.Z)
2888                                 rp.Z = ar.Z-1;
2889                         vec = rp - orp;
2890
2891                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
2892                         {
2893                                 v3f fp = orp + vec * f;
2894                                 v3s16 cp(fp.X, fp.Y, fp.Z);
2895
2896                                 s16 d0 = -rs/2;
2897                                 s16 d1 = d0 + rs - 1;
2898                                 for(s16 z0=d0; z0<=d1; z0++)
2899                                 {
2900                                         //s16 si = rs - MYMAX(0, abs(z0)-rs/4);
2901                                         s16 si = rs - MYMAX(0, abs(z0)-rs/7);
2902                                         for(s16 x0=-si; x0<=si-1; x0++)
2903                                         {
2904                                                 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
2905                                                 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
2906                                                 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
2907                                                 //s16 si2 = rs - abs(x0);
2908                                                 for(s16 y0=-si2+1+2; y0<=si2-1; y0++)
2909                                                 {
2910                                                         s16 z = cp.Z + z0;
2911                                                         s16 y = cp.Y + y0;
2912                                                         s16 x = cp.X + x0;
2913                                                         v3s16 p(x,y,z);
2914                                                         /*if(isInArea(p, ar) == false)
2915                                                                 continue;*/
2916                                                         // Check only height
2917                                                         if(y < 0 || y >= ar.Y)
2918                                                                 continue;
2919                                                         p += of;
2920                                                         
2921                                                         //assert(vmanip.m_area.contains(p));
2922                                                         if(vmanip.m_area.contains(p) == false)
2923                                                         {
2924                                                                 dstream<<"WARNING: "<<__FUNCTION_NAME
2925                                                                                 <<":"<<__LINE__<<": "
2926                                                                                 <<"point not in area"
2927                                                                                 <<std::endl;
2928                                                                 continue;
2929                                                         }
2930                                                         
2931                                                         // Just set it to air, it will be changed to
2932                                                         // water afterwards
2933                                                         u32 i = vmanip.m_area.index(p);
2934                                                         vmanip.m_data[i] = airnode;
2935
2936                                                         if(bruise_surface == false)
2937                                                         {
2938                                                                 // Set tunnel flag
2939                                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON;
2940                                                         }
2941                                                 }
2942                                         }
2943                                 }
2944                         }
2945
2946                         orp = rp;
2947                 }
2948         
2949         }
2950
2951         }//timer1
2952         {
2953         // 46ms @cs=8
2954         //TimeTaker timer1("ore veins");
2955
2956         /*
2957                 Make ore veins
2958         */
2959         for(u32 jj=0; jj<relative_volume/1000; jj++)
2960         {
2961                 s16 max_vein_diameter = 3;
2962
2963                 // Allowed route area size in nodes
2964                 v3s16 ar(
2965                         sectorpos_base_size*MAP_BLOCKSIZE,
2966                         h_blocks*MAP_BLOCKSIZE,
2967                         sectorpos_base_size*MAP_BLOCKSIZE
2968                 );
2969
2970                 // Area starting point in nodes
2971                 v3s16 of(
2972                         sectorpos_base.X*MAP_BLOCKSIZE,
2973                         y_blocks_min*MAP_BLOCKSIZE,
2974                         sectorpos_base.Y*MAP_BLOCKSIZE
2975                 );
2976
2977                 // Allow a bit more
2978                 //(this should be more than the maximum radius of the tunnel)
2979                 s16 insure = 3;
2980                 s16 more = max_spread_amount - max_vein_diameter/2 - insure;
2981                 ar += v3s16(1,0,1) * more * 2;
2982                 of -= v3s16(1,0,1) * more;
2983                 
2984                 // Randomize starting position
2985                 v3f orp(
2986                         (float)(myrand()%ar.X)+0.5,
2987                         (float)(myrand()%ar.Y)+0.5,
2988                         (float)(myrand()%ar.Z)+0.5
2989                 );
2990
2991                 // Randomize mineral
2992                 u8 mineral;
2993                 if(myrand()%3 != 0)
2994                         mineral = MINERAL_COAL;
2995                 else
2996                         mineral = MINERAL_IRON;
2997
2998                 /*
2999                         Generate some vein starting from orp
3000                 */
3001
3002                 for(u16 j=0; j<2; j++)
3003                 {
3004                         /*v3f rp(
3005                                 (float)(myrand()%ar.X)+0.5,
3006                                 (float)(myrand()%ar.Y)+0.5,
3007                                 (float)(myrand()%ar.Z)+0.5
3008                         );
3009                         v3f vec = rp - orp;*/
3010                         
3011                         v3s16 maxlen(5, 5, 5);
3012                         v3f vec(
3013                                 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
3014                                 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
3015                                 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
3016                         );
3017                         v3f rp = orp + vec;
3018                         if(rp.X < 0)
3019                                 rp.X = 0;
3020                         else if(rp.X >= ar.X)
3021                                 rp.X = ar.X;
3022                         if(rp.Y < 0)
3023                                 rp.Y = 0;
3024                         else if(rp.Y >= ar.Y)
3025                                 rp.Y = ar.Y;
3026                         if(rp.Z < 0)
3027                                 rp.Z = 0;
3028                         else if(rp.Z >= ar.Z)
3029                                 rp.Z = ar.Z;
3030                         vec = rp - orp;
3031
3032                         // Randomize size
3033                         s16 min_d = 0;
3034                         s16 max_d = max_vein_diameter;
3035                         s16 rs = myrand_range(min_d, max_d);
3036                         
3037                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
3038                         {
3039                                 v3f fp = orp + vec * f;
3040                                 v3s16 cp(fp.X, fp.Y, fp.Z);
3041                                 s16 d0 = -rs/2;
3042                                 s16 d1 = d0 + rs - 1;
3043                                 for(s16 z0=d0; z0<=d1; z0++)
3044                                 {
3045                                         s16 si = rs - abs(z0);
3046                                         for(s16 x0=-si; x0<=si-1; x0++)
3047                                         {
3048                                                 s16 si2 = rs - abs(x0);
3049                                                 for(s16 y0=-si2+1; y0<=si2-1; y0++)
3050                                                 {
3051                                                         // Don't put mineral to every place
3052                                                         if(myrand()%5 != 0)
3053                                                                 continue;
3054
3055                                                         s16 z = cp.Z + z0;
3056                                                         s16 y = cp.Y + y0;
3057                                                         s16 x = cp.X + x0;
3058                                                         v3s16 p(x,y,z);
3059                                                         /*if(isInArea(p, ar) == false)
3060                                                                 continue;*/
3061                                                         // Check only height
3062                                                         if(y < 0 || y >= ar.Y)
3063                                                                 continue;
3064                                                         p += of;
3065                                                         
3066                                                         assert(vmanip.m_area.contains(p));
3067                                                         
3068                                                         // Just set it to air, it will be changed to
3069                                                         // water afterwards
3070                                                         u32 i = vmanip.m_area.index(p);
3071                                                         MapNode *n = &vmanip.m_data[i];
3072                                                         if(n->d == CONTENT_STONE)
3073                                                                 n->param = mineral;
3074                                                 }
3075                                         }
3076                                 }
3077                         }
3078
3079                         orp = rp;
3080                 }
3081         
3082         }
3083
3084         }//timer1
3085         {
3086         // 15ms @cs=8
3087         //TimeTaker timer1("add mud");
3088
3089         /*
3090                 Add mud to the central chunk
3091         */
3092         
3093         for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3094         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)
3095         {
3096                 // Node position in 2d
3097                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3098                 
3099                 // Randomize mud amount
3100                 s16 mud_add_amount = get_mud_amount(m_seed, v2f(p2d.X,p2d.Y))/age_count;
3101
3102                 // Find ground level
3103                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
3104
3105                 /*
3106                         If topmost node is grass, change it to mud.
3107                         It might be if it was flown to there from a neighboring
3108                         chunk and then converted.
3109                 */
3110                 {
3111                         u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
3112                         MapNode *n = &vmanip.m_data[i];
3113                         if(n->d == CONTENT_GRASS)
3114                                 n->d = CONTENT_MUD;
3115                 }
3116
3117                 /*
3118                         Add mud on ground
3119                 */
3120                 {
3121                         s16 mudcount = 0;
3122                         v3s16 em = vmanip.m_area.getExtent();
3123                         s16 y_start = surface_y+1;
3124                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3125                         for(s16 y=y_start; y<=y_nodes_max; y++)
3126                         {
3127                                 if(mudcount >= mud_add_amount)
3128                                         break;
3129                                         
3130                                 MapNode &n = vmanip.m_data[i];
3131                                 n.d = CONTENT_MUD;
3132                                 mudcount++;
3133
3134                                 vmanip.m_area.add_y(em, i, 1);
3135                         }
3136                 }
3137
3138         }
3139
3140         }//timer1
3141         {
3142         // 340ms @cs=8
3143         //TimeTaker timer1("flow mud");
3144
3145         /*
3146                 Flow mud away from steep edges
3147         */
3148
3149         // Limit area by 1 because mud is flown into neighbors.
3150         s16 mudflow_minpos = 0-max_spread_amount+1;
3151         s16 mudflow_maxpos = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
3152
3153         // Iterate a few times
3154         for(s16 k=0; k<3; k++)
3155         {
3156
3157         for(s16 x=mudflow_minpos;
3158                         x<=mudflow_maxpos;
3159                         x++)
3160         for(s16 z=mudflow_minpos;
3161                         z<=mudflow_maxpos;
3162                         z++)
3163         {
3164                 // Invert coordinates every 2nd iteration
3165                 if(k%2 == 0)
3166                 {
3167                         x = mudflow_maxpos - (x-mudflow_minpos);
3168                         z = mudflow_maxpos - (z-mudflow_minpos);
3169                 }
3170
3171                 // Node position in 2d
3172                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3173                 
3174                 v3s16 em = vmanip.m_area.getExtent();
3175                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3176                 s16 y=y_nodes_max;
3177
3178                 for(;; y--)
3179                 {
3180                         MapNode *n = NULL;
3181                         // Find mud
3182                         for(; y>=y_nodes_min; y--)
3183                         {
3184                                 n = &vmanip.m_data[i];
3185                                 //if(content_walkable(n->d))
3186                                 //      break;
3187                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
3188                                         break;
3189                                         
3190                                 vmanip.m_area.add_y(em, i, -1);
3191                         }
3192
3193                         // Stop if out of area
3194                         //if(vmanip.m_area.contains(i) == false)
3195                         if(y < y_nodes_min)
3196                                 break;
3197
3198                         /*// If not mud, do nothing to it
3199                         MapNode *n = &vmanip.m_data[i];
3200                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3201                                 continue;*/
3202
3203                         /*
3204                                 Don't flow it if the stuff under it is not mud
3205                         */
3206                         {
3207                                 u32 i2 = i;
3208                                 vmanip.m_area.add_y(em, i2, -1);
3209                                 // Cancel if out of area
3210                                 if(vmanip.m_area.contains(i2) == false)
3211                                         continue;
3212                                 MapNode *n2 = &vmanip.m_data[i2];
3213                                 if(n2->d != CONTENT_MUD && n2->d != CONTENT_GRASS)
3214                                         continue;
3215                         }
3216
3217                         // Make it exactly mud
3218                         n->d = CONTENT_MUD;
3219                         
3220                         /*s16 recurse_count = 0;
3221         mudflow_recurse:*/
3222
3223                         v3s16 dirs4[4] = {
3224                                 v3s16(0,0,1), // back
3225                                 v3s16(1,0,0), // right
3226                                 v3s16(0,0,-1), // front
3227                                 v3s16(-1,0,0), // left
3228                         };
3229
3230                         // Theck that upper is air or doesn't exist.
3231                         // Cancel dropping if upper keeps it in place
3232                         u32 i3 = i;
3233                         vmanip.m_area.add_y(em, i3, 1);
3234                         if(vmanip.m_area.contains(i3) == true
3235                                         && content_walkable(vmanip.m_data[i3].d) == true)
3236                         {
3237                                 continue;
3238                         }
3239
3240                         // Drop mud on side
3241                         
3242                         for(u32 di=0; di<4; di++)
3243                         {
3244                                 v3s16 dirp = dirs4[di];
3245                                 u32 i2 = i;
3246                                 // Move to side
3247                                 vmanip.m_area.add_p(em, i2, dirp);
3248                                 // Fail if out of area
3249                                 if(vmanip.m_area.contains(i2) == false)
3250                                         continue;
3251                                 // Check that side is air
3252                                 MapNode *n2 = &vmanip.m_data[i2];
3253                                 if(content_walkable(n2->d))
3254                                         continue;
3255                                 // Check that under side is air
3256                                 vmanip.m_area.add_y(em, i2, -1);
3257                                 if(vmanip.m_area.contains(i2) == false)
3258                                         continue;
3259                                 n2 = &vmanip.m_data[i2];
3260                                 if(content_walkable(n2->d))
3261                                         continue;
3262                                 /*// Check that under that is air (need a drop of 2)
3263                                 vmanip.m_area.add_y(em, i2, -1);
3264                                 if(vmanip.m_area.contains(i2) == false)
3265                                         continue;
3266                                 n2 = &vmanip.m_data[i2];
3267                                 if(content_walkable(n2->d))
3268                                         continue;*/
3269                                 // Loop further down until not air
3270                                 do{
3271                                         vmanip.m_area.add_y(em, i2, -1);
3272                                         // Fail if out of area
3273                                         if(vmanip.m_area.contains(i2) == false)
3274                                                 continue;
3275                                         n2 = &vmanip.m_data[i2];
3276                                 }while(content_walkable(n2->d) == false);
3277                                 // Loop one up so that we're in air
3278                                 vmanip.m_area.add_y(em, i2, 1);
3279                                 n2 = &vmanip.m_data[i2];
3280
3281                                 // Move mud to new place
3282                                 *n2 = *n;
3283                                 // Set old place to be air
3284                                 *n = MapNode(CONTENT_AIR);
3285
3286                                 // Done
3287                                 break;
3288                         }
3289                 }
3290         }
3291         
3292         }
3293
3294         }//timer1
3295         {
3296         // 50ms @cs=8
3297         //TimeTaker timer1("add water");
3298
3299         /*
3300                 Add water to the central chunk (and a bit more)
3301         */
3302         
3303         for(s16 x=0-max_spread_amount;
3304                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3305                         x++)
3306         for(s16 z=0-max_spread_amount;
3307                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3308                         z++)
3309         {
3310                 // Node position in 2d
3311                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3312                 
3313                 // Find ground level
3314                 //s16 surface_y = find_ground_level(vmanip, p2d);
3315
3316                 /*
3317                         If ground level is over water level, skip.
3318                         NOTE: This leaves caves near water without water,
3319                         which looks especially crappy when the nearby water
3320                         won't start flowing either for some reason
3321                 */
3322                 /*if(surface_y > WATER_LEVEL)
3323                         continue;*/
3324
3325                 /*
3326                         Add water on ground
3327                 */
3328                 {
3329                         v3s16 em = vmanip.m_area.getExtent();
3330                         u8 light = LIGHT_MAX;
3331                         // Start at global water surface level
3332                         s16 y_start = WATER_LEVEL;
3333                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3334                         MapNode *n = &vmanip.m_data[i];
3335
3336                         /*// Add first one to transforming liquid queue, if water
3337                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
3338                         {
3339                                 v3s16 p = v3s16(p2d.X, y_start, p2d.Y);
3340                                 m_transforming_liquid.push_back(p);
3341                         }*/
3342
3343                         for(s16 y=y_start; y>=y_nodes_min; y--)
3344                         {
3345                                 n = &vmanip.m_data[i];
3346                                 
3347                                 // Stop when there is no water and no air
3348                                 if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
3349                                                 && n->d != CONTENT_WATER)
3350                                 {
3351                                         /*// Add bottom one to transforming liquid queue
3352                                         vmanip.m_area.add_y(em, i, 1);
3353                                         n = &vmanip.m_data[i];
3354                                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
3355                                         {
3356                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
3357                                                 m_transforming_liquid.push_back(p);
3358                                         }*/
3359
3360                                         break;
3361                                 }
3362                                 
3363                                 // Make water only not in dungeons
3364                                 if(!(vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
3365                                 {
3366                                         n->d = CONTENT_WATERSOURCE;
3367                                         //n->setLight(LIGHTBANK_DAY, light);
3368
3369                                         // Add to transforming liquid queue (in case it'd
3370                                         // start flowing)
3371                                         v3s16 p = v3s16(p2d.X, y, p2d.Y);
3372                                         m_transforming_liquid.push_back(p);
3373                                 }
3374                                 
3375                                 // Next one
3376                                 vmanip.m_area.add_y(em, i, -1);
3377                                 if(light > 0)
3378                                         light--;
3379                         }
3380                 }
3381
3382         }
3383
3384         }//timer1
3385         
3386         } // Aging loop
3387
3388         {
3389         //TimeTaker timer1("convert mud to sand");
3390
3391         /*
3392                 Convert mud to sand
3393         */
3394         
3395         //s16 mud_add_amount = myrand_range(2, 4);
3396         //s16 mud_add_amount = 0;
3397         
3398         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3399         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3400         for(s16 x=0-max_spread_amount+1;
3401                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3402                         x++)
3403         for(s16 z=0-max_spread_amount+1;
3404                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3405                         z++)
3406         {
3407                 // Node position in 2d
3408                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3409                 
3410                 // Determine whether to have sand here
3411                 bool have_sand = get_have_sand(p2d);
3412
3413                 if(have_sand == false)
3414                         continue;
3415
3416                 // Find ground level
3417                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
3418                 
3419                 if(surface_y > WATER_LEVEL + 2)
3420                         continue;
3421
3422                 {
3423                         v3s16 em = vmanip.m_area.getExtent();
3424                         s16 y_start = surface_y;
3425                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3426                         u32 not_sand_counter = 0;
3427                         for(s16 y=y_start; y>=y_nodes_min; y--)
3428                         {
3429                                 MapNode *n = &vmanip.m_data[i];
3430                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
3431                                 {
3432                                         n->d = CONTENT_SAND;
3433                                 }
3434                                 else
3435                                 {
3436                                         not_sand_counter++;
3437                                         if(not_sand_counter > 3)
3438                                                 break;
3439                                 }
3440
3441                                 vmanip.m_area.add_y(em, i, -1);
3442                         }
3443                 }
3444
3445         }
3446
3447         }//timer1
3448         {
3449         // 1ms @cs=8
3450         //TimeTaker timer1("generate trees");
3451
3452         /*
3453                 Generate some trees
3454         */
3455         {
3456                 // Divide area into parts
3457                 s16 div = 8;
3458                 s16 sidelen = sectorpos_base_size*MAP_BLOCKSIZE / div;
3459                 double area = sidelen * sidelen;
3460                 for(s16 x0=0; x0<div; x0++)
3461                 for(s16 z0=0; z0<div; z0++)
3462                 {
3463                         // Center position of part of division
3464                         v2s16 p2d_center(
3465                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
3466                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
3467                         );
3468                         // Minimum edge of part of division
3469                         v2s16 p2d_min(
3470                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
3471                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
3472                         );
3473                         // Maximum edge of part of division
3474                         v2s16 p2d_max(
3475                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
3476                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
3477                         );
3478                         // Amount of trees
3479                         u32 tree_count = area * tree_amount_2d(m_seed, p2d_center);
3480                         // Put trees in random places on part of division
3481                         for(u32 i=0; i<tree_count; i++)
3482                         {
3483                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
3484                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
3485                                 s16 y = find_ground_level(vmanip, v2s16(x,z));
3486                                 // Don't make a tree under water level
3487                                 if(y < WATER_LEVEL)
3488                                         continue;
3489                                 v3s16 p(x,y,z);
3490                                 /*
3491                                         Trees grow only on mud and grass
3492                                 */
3493                                 {
3494                                         u32 i = vmanip.m_area.index(v3s16(p));
3495                                         MapNode *n = &vmanip.m_data[i];
3496                                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3497                                                 continue;
3498                                 }
3499                                 p.Y++;
3500                                 // Make a tree
3501                                 make_tree(vmanip, p);
3502                         }
3503                 }
3504                 /*u32 tree_max = relative_area / 60;
3505                 //u32 count = myrand_range(0, tree_max);
3506                 for(u32 i=0; i<count; i++)
3507                 {
3508                         s16 x = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
3509                         s16 z = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
3510                         x += sectorpos_base.X*MAP_BLOCKSIZE;
3511                         z += sectorpos_base.Y*MAP_BLOCKSIZE;
3512                         s16 y = find_ground_level(vmanip, v2s16(x,z));
3513                         // Don't make a tree under water level
3514                         if(y < WATER_LEVEL)
3515                                 continue;
3516                         v3s16 p(x,y+1,z);
3517                         // Make a tree
3518                         make_tree(vmanip, p);
3519                 }*/
3520         }
3521
3522         }//timer1
3523
3524         {
3525         // 19ms @cs=8
3526         //TimeTaker timer1("grow grass");
3527
3528         /*
3529                 Grow grass
3530         */
3531
3532         /*for(s16 x=0-4; x<sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
3533         for(s16 z=0-4; z<sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
3534         for(s16 x=0-max_spread_amount;
3535                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3536                         x++)
3537         for(s16 z=0-max_spread_amount;
3538                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3539                         z++)
3540         {
3541                 // Node position in 2d
3542                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3543                 
3544                 /*
3545                         Find the lowest surface to which enough light ends up
3546                         to make grass grow.
3547
3548                         Basically just wait until not air and not leaves.
3549                 */
3550                 s16 surface_y = 0;
3551                 {
3552                         v3s16 em = vmanip.m_area.getExtent();
3553                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3554                         s16 y;
3555                         // Go to ground level
3556                         for(y=y_nodes_max; y>=y_nodes_min; y--)
3557                         {
3558                                 MapNode &n = vmanip.m_data[i];
3559                                 if(n.d != CONTENT_AIR
3560                                                 && n.d != CONTENT_LEAVES)
3561                                         break;
3562                                 vmanip.m_area.add_y(em, i, -1);
3563                         }
3564                         if(y >= y_nodes_min)
3565                                 surface_y = y;
3566                         else
3567                                 surface_y = y_nodes_min;
3568                 }
3569                 
3570                 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
3571                 MapNode *n = &vmanip.m_data[i];
3572                 if(n->d == CONTENT_MUD)
3573                         n->d = CONTENT_GRASS;
3574         }
3575
3576         }//timer1
3577
3578         /*
3579                 Initial lighting (sunlight)
3580         */
3581
3582         core::map<v3s16, bool> light_sources;
3583
3584         {
3585         // 750ms @cs=8, can't optimize more
3586         TimeTaker timer1("initial lighting");
3587
3588 #if 0
3589         /*
3590                 Go through the edges and add all nodes that have light to light_sources
3591         */
3592         
3593         // Four edges
3594         for(s16 i=0; i<4; i++)
3595         // Edge length
3596         for(s16 j=lighting_min_d;
3597                         j<=lighting_max_d;
3598                         j++)
3599         {
3600                 s16 x;
3601                 s16 z;
3602                 // +-X
3603                 if(i == 0 || i == 1)
3604                 {
3605                         x = (i==0) ? lighting_min_d : lighting_max_d;
3606                         if(i == 0)
3607                                 z = lighting_min_d;
3608                         else
3609                                 z = lighting_max_d;
3610                 }
3611                 // +-Z
3612                 else
3613                 {
3614                         z = (i==0) ? lighting_min_d : lighting_max_d;
3615                         if(i == 0)
3616                                 x = lighting_min_d;
3617                         else
3618                                 x = lighting_max_d;
3619                 }
3620                 
3621                 // Node position in 2d
3622                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3623
3624                 {
3625                         v3s16 em = vmanip.m_area.getExtent();
3626                         s16 y_start = y_nodes_max;
3627                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3628                         for(s16 y=y_start; y>=y_nodes_min; y--)
3629                         {
3630                                 MapNode *n = &vmanip.m_data[i];
3631                                 if(n->getLight(LIGHTBANK_DAY) != 0)
3632                                 {
3633                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3634                                 }
3635                                 //NOTE: This is broken, at least the index has to
3636                                 // be incremented
3637                         }
3638                 }
3639         }
3640 #endif
3641
3642 #if 1
3643         /*
3644                 Go through the edges and apply sunlight to them, not caring
3645                 about neighbors
3646         */
3647         
3648         // Four edges
3649         for(s16 i=0; i<4; i++)
3650         // Edge length
3651         for(s16 j=lighting_min_d;
3652                         j<=lighting_max_d;
3653                         j++)
3654         {
3655                 s16 x;
3656                 s16 z;
3657                 // +-X
3658                 if(i == 0 || i == 1)
3659                 {
3660                         x = (i==0) ? lighting_min_d : lighting_max_d;
3661                         if(i == 0)
3662                                 z = lighting_min_d;
3663                         else
3664                                 z = lighting_max_d;
3665                 }
3666                 // +-Z
3667                 else
3668                 {
3669                         z = (i==0) ? lighting_min_d : lighting_max_d;
3670                         if(i == 0)
3671                                 x = lighting_min_d;
3672                         else
3673                                 x = lighting_max_d;
3674                 }
3675                 
3676                 // Node position in 2d
3677                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3678                 
3679                 // Loop from top to down
3680                 {
3681                         u8 light = LIGHT_SUN;
3682                         v3s16 em = vmanip.m_area.getExtent();
3683                         s16 y_start = y_nodes_max;
3684                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3685                         for(s16 y=y_start; y>=y_nodes_min; y--)
3686                         {
3687                                 MapNode *n = &vmanip.m_data[i];
3688                                 if(light_propagates_content(n->d) == false)
3689                                 {
3690                                         light = 0;
3691                                 }
3692                                 else if(light != LIGHT_SUN
3693                                         || sunlight_propagates_content(n->d) == false)
3694                                 {
3695                                         if(light > 0)
3696                                                 light--;
3697                                 }
3698                                 
3699                                 n->setLight(LIGHTBANK_DAY, light);
3700                                 n->setLight(LIGHTBANK_NIGHT, 0);
3701                                 
3702                                 if(light != 0)
3703                                 {
3704                                         // Insert light source
3705                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3706                                 }
3707                                 
3708                                 // Increment index by y
3709                                 vmanip.m_area.add_y(em, i, -1);
3710                         }
3711                 }
3712         }
3713 #endif
3714
3715         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3716         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3717         /*for(s16 x=0-max_spread_amount+1;
3718                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3719                         x++)
3720         for(s16 z=0-max_spread_amount+1;
3721                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3722                         z++)*/
3723 #if 1
3724         /*
3725                 This has to be 1 smaller than the actual area, because
3726                 neighboring nodes are checked.
3727         */
3728         for(s16 x=lighting_min_d+1;
3729                         x<=lighting_max_d-1;
3730                         x++)
3731         for(s16 z=lighting_min_d+1;
3732                         z<=lighting_max_d-1;
3733                         z++)
3734         {
3735                 // Node position in 2d
3736                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3737                 
3738                 /*
3739                         Apply initial sunlight
3740                 */
3741                 {
3742                         u8 light = LIGHT_SUN;
3743                         bool add_to_sources = false;
3744                         v3s16 em = vmanip.m_area.getExtent();
3745                         s16 y_start = y_nodes_max;
3746                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3747                         for(s16 y=y_start; y>=y_nodes_min; y--)
3748                         {
3749                                 MapNode *n = &vmanip.m_data[i];
3750
3751                                 if(light_propagates_content(n->d) == false)
3752                                 {
3753                                         light = 0;
3754                                 }
3755                                 else if(light != LIGHT_SUN
3756                                         || sunlight_propagates_content(n->d) == false)
3757                                 {
3758                                         if(light > 0)
3759                                                 light--;
3760                                 }
3761                                 
3762                                 // This doesn't take much time
3763                                 if(add_to_sources == false)
3764                                 {
3765                                         /*
3766                                                 Check sides. If side is not air or water, start
3767                                                 adding to light_sources.
3768                                         */
3769                                         v3s16 dirs4[4] = {
3770                                                 v3s16(0,0,1), // back
3771                                                 v3s16(1,0,0), // right
3772                                                 v3s16(0,0,-1), // front
3773                                                 v3s16(-1,0,0), // left
3774                                         };
3775                                         for(u32 di=0; di<4; di++)
3776                                         {
3777                                                 v3s16 dirp = dirs4[di];
3778                                                 u32 i2 = i;
3779                                                 vmanip.m_area.add_p(em, i2, dirp);
3780                                                 MapNode *n2 = &vmanip.m_data[i2];
3781                                                 if(
3782                                                         n2->d != CONTENT_AIR
3783                                                         && n2->d != CONTENT_WATERSOURCE
3784                                                         && n2->d != CONTENT_WATER
3785                                                 ){
3786                                                         add_to_sources = true;
3787                                                         break;
3788                                                 }
3789                                         }
3790                                 }
3791                                 
3792                                 n->setLight(LIGHTBANK_DAY, light);
3793                                 n->setLight(LIGHTBANK_NIGHT, 0);
3794                                 
3795                                 // This doesn't take much time
3796                                 if(light != 0 && add_to_sources)
3797                                 {
3798                                         // Insert light source
3799                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3800                                 }
3801                                 
3802                                 // Increment index by y
3803                                 vmanip.m_area.add_y(em, i, -1);
3804                         }
3805                 }
3806         }
3807 #endif
3808
3809         }//timer1
3810
3811         // Spread light around
3812         {
3813                 TimeTaker timer("generateChunkRaw() spreadLight");
3814                 vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
3815         }
3816         
3817         /*
3818                 Generation ended
3819         */
3820
3821         timer_generate.stop();
3822
3823         /*
3824                 Blit generated stuff to map
3825         */
3826         {
3827                 // 70ms @cs=8
3828                 //TimeTaker timer("generateChunkRaw() blitBackAll");
3829                 vmanip.blitBackAll(&changed_blocks);
3830         }
3831
3832         /*
3833                 Update day/night difference cache of the MapBlocks
3834         */
3835         {
3836                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
3837                                 i.atEnd() == false; i++)
3838                 {
3839                         MapBlock *block = i.getNode()->getValue();
3840                         block->updateDayNightDiff();
3841                 }
3842         }
3843
3844 #endif
3845         
3846         /*
3847                 Create chunk metadata
3848         */
3849
3850         for(s16 x=-1; x<=1; x++)
3851         for(s16 y=-1; y<=1; y++)
3852         {
3853                 v2s16 chunkpos0 = chunkpos + v2s16(x,y);
3854                 // Add chunk meta information
3855                 MapChunk *chunk = getChunk(chunkpos0);
3856                 if(chunk == NULL)
3857                 {
3858                         chunk = new MapChunk();
3859                         m_chunks.insert(chunkpos0, chunk);
3860                 }
3861                 //chunk->setIsVolatile(true);
3862                 if(chunk->getGenLevel() > GENERATED_PARTLY)
3863                         chunk->setGenLevel(GENERATED_PARTLY);
3864         }
3865
3866         /*
3867                 Set central chunk non-volatile
3868         */
3869         MapChunk *chunk = getChunk(chunkpos);
3870         assert(chunk);
3871         // Set non-volatile
3872         //chunk->setIsVolatile(false);
3873         chunk->setGenLevel(GENERATED_FULLY);
3874         
3875         /*
3876                 Save changed parts of map
3877         */
3878         save(true);
3879
3880         /*
3881                 Return central chunk (which was requested)
3882         */
3883         return chunk;
3884 }
3885
3886 MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
3887                 core::map<v3s16, MapBlock*> &changed_blocks)
3888 {
3889         dstream<<"generateChunk(): Generating chunk "
3890                         <<"("<<chunkpos1.X<<","<<chunkpos1.Y<<")"
3891                         <<std::endl;
3892         
3893         // Shall be not used now
3894         //assert(0);
3895         
3896         /*for(s16 x=-1; x<=1; x++)
3897         for(s16 y=-1; y<=1; y++)*/
3898         for(s16 x=-0; x<=0; x++)
3899         for(s16 y=-0; y<=0; y++)
3900         {
3901                 v2s16 chunkpos0 = chunkpos1 + v2s16(x,y);
3902                 MapChunk *chunk = getChunk(chunkpos0);
3903                 // Skip if already generated
3904                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
3905                         continue;
3906                 generateChunkRaw(chunkpos0, changed_blocks);
3907         }
3908         
3909         assert(chunkNonVolatile(chunkpos1));
3910
3911         MapChunk *chunk = getChunk(chunkpos1);
3912         return chunk;
3913 }
3914
3915 ServerMapSector * ServerMap::createSector(v2s16 p2d)
3916 {
3917         DSTACK("%s: p2d=(%d,%d)",
3918                         __FUNCTION_NAME,
3919                         p2d.X, p2d.Y);
3920         
3921         /*
3922                 Check if it exists already in memory
3923         */
3924         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3925         if(sector != NULL)
3926                 return sector;
3927         
3928         /*
3929                 Try to load it from disk (with blocks)
3930         */
3931         if(loadSectorFull(p2d) == true)
3932         {
3933                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3934                 if(sector == NULL)
3935                 {
3936                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
3937                         throw InvalidPositionException("");
3938                 }
3939                 return sector;
3940         }
3941
3942         /*
3943                 Do not create over-limit
3944         */
3945         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3946         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3947         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3948         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
3949                 throw InvalidPositionException("createSector(): pos. over limit");
3950
3951         /*
3952                 Generate blank sector
3953         */
3954         
3955         sector = new ServerMapSector(this, p2d);
3956         
3957         // Sector position on map in nodes
3958         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
3959
3960         /*
3961                 Insert to container
3962         */
3963         m_sectors.insert(p2d, sector);
3964         
3965         return sector;
3966 }
3967
3968 MapSector * ServerMap::emergeSector(v2s16 p2d,
3969                 core::map<v3s16, MapBlock*> &changed_blocks)
3970 {
3971         DSTACK("%s: p2d=(%d,%d)",
3972                         __FUNCTION_NAME,
3973                         p2d.X, p2d.Y);
3974         
3975         /*
3976                 Check chunk status
3977         */
3978         v2s16 chunkpos = sector_to_chunk(p2d);
3979         /*bool chunk_nonvolatile = false;
3980         MapChunk *chunk = getChunk(chunkpos);
3981         if(chunk && chunk->getIsVolatile() == false)
3982                 chunk_nonvolatile = true;*/
3983         bool chunk_nonvolatile = chunkNonVolatile(chunkpos);
3984
3985         /*
3986                 If chunk is not fully generated, generate chunk
3987         */
3988         if(chunk_nonvolatile == false)
3989         {
3990                 // Generate chunk and neighbors
3991                 generateChunk(chunkpos, changed_blocks);
3992         }
3993         
3994         /*
3995                 Return sector if it exists now
3996         */
3997         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3998         if(sector != NULL)
3999                 return sector;
4000         
4001         /*
4002                 Try to load it from disk
4003         */
4004         if(loadSectorFull(p2d) == true)
4005         {
4006                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
4007                 if(sector == NULL)
4008                 {
4009                         dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<<std::endl;
4010                         throw InvalidPositionException("");
4011                 }
4012                 return sector;
4013         }
4014
4015         /*
4016                 generateChunk should have generated the sector
4017         */
4018         //assert(0);
4019         
4020         dstream<<"WARNING: ServerMap::emergeSector: Cannot find sector ("
4021                         <<p2d.X<<","<<p2d.Y<<" and chunk is already generated. "
4022                         <<std::endl;
4023
4024 #if 1
4025         dstream<<"WARNING: Forcing regeneration of chunk."<<std::endl;
4026
4027         // Generate chunk
4028         generateChunkRaw(chunkpos, changed_blocks, true);
4029
4030         /*
4031                 Return sector if it exists now
4032         */
4033         sector = getSectorNoGenerateNoEx(p2d);
4034         if(sector != NULL)
4035                 return sector;
4036         
4037         dstream<<"ERROR: Could not get sector from anywhere."<<std::endl;
4038         
4039         //assert(0);
4040 #endif
4041         
4042 #if 1
4043         dstream<<"WARNING: Creating an empty sector."<<std::endl;
4044
4045         return createSector(p2d);
4046         
4047 #endif
4048         
4049         /*
4050                 Generate directly
4051         */
4052         //return generateSector();
4053 }
4054
4055 /*
4056         NOTE: This is not used for main map generation, only for blocks
4057         that are very high or low
4058 */
4059 MapBlock * ServerMap::generateBlock(
4060                 v3s16 p,
4061                 MapBlock *original_dummy,
4062                 ServerMapSector *sector,
4063                 core::map<v3s16, MapBlock*> &changed_blocks,
4064                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
4065 )
4066 {
4067         DSTACK("%s: p=(%d,%d,%d)",
4068                         __FUNCTION_NAME,
4069                         p.X, p.Y, p.Z);
4070         
4071         /*dstream<<"generateBlock(): "
4072                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4073                         <<std::endl;*/
4074         
4075         MapBlock *block = original_dummy;
4076                         
4077         v2s16 p2d(p.X, p.Z);
4078         s16 block_y = p.Y;
4079         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
4080         v3s16 p_nodes = p * MAP_BLOCKSIZE;
4081         
4082         /*
4083                 Do not generate over-limit
4084         */
4085         if(blockpos_over_limit(p))
4086         {
4087                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
4088                 throw InvalidPositionException("generateBlock(): pos. over limit");
4089         }
4090
4091         /*
4092                 If block doesn't exist, create one.
4093                 If it exists, it is a dummy. In that case unDummify() it.
4094
4095                 NOTE: This already sets the map as the parent of the block
4096         */
4097         if(block == NULL)
4098         {
4099                 block = sector->createBlankBlockNoInsert(block_y);
4100         }
4101         else
4102         {
4103                 // Remove the block so that nobody can get a half-generated one.
4104                 sector->removeBlock(block);
4105                 // Allocate the block to contain the generated data
4106                 block->unDummify();
4107         }
4108         
4109         u8 water_material = CONTENT_WATERSOURCE;
4110         
4111         s32 lowest_ground_y = 32767;
4112         s32 highest_ground_y = -32768;
4113
4114         enum{
4115                 BT_GROUND,
4116                 BT_SURFACE,
4117                 BT_SKY
4118         } block_type = BT_SURFACE;
4119
4120         {// ground_timer (0ms or ~100ms)
4121         //TimeTaker ground_timer("Ground generation");
4122
4123         /*
4124                 Approximate whether this block is a surface block, an air
4125                 block or a ground block.
4126
4127                 This shall never mark a surface block as non-surface.
4128         */
4129
4130         {
4131                 /*
4132                         Estimate surface at different positions of the block, to
4133                         try to accomodate the effect of turbulence.
4134                 */
4135                 v3f checklist[] = {
4136                         v3f(0,0,0),
4137                         v3f(0,1,0),
4138                         v3f(0,1,1),
4139                         v3f(0,0,1),
4140                         v3f(1,0,0),
4141                         v3f(1,1,0),
4142                         v3f(1,1,1),
4143                         v3f(1,0,1),
4144                         v3f(0.5,0.5,0.5),
4145                 };
4146                 v3f p_nodes_f = intToFloat(p_nodes, 1);
4147                 float surface_y_max = -1000000;
4148                 float surface_y_min = 1000000;
4149                 for(u32 i=0; i<sizeof(checklist)/sizeof(checklist[0]); i++)
4150                 {
4151                         v3f p_map_f = p_nodes_f + checklist[i]*MAP_BLOCKSIZE;
4152
4153                         double depth_guess;
4154                         bool is_ground = is_base_ground(m_seed, p_map_f, &depth_guess);
4155                         
4156                         // Estimate the surface height
4157                         float surface_y_f = p_map_f.Y + depth_guess;
4158
4159                         if(surface_y_f > surface_y_max)
4160                                 surface_y_max = surface_y_f;
4161                         if(surface_y_f < surface_y_min)
4162                                 surface_y_min = surface_y_f;
4163                 }
4164
4165                 float block_low_y_f = p_nodes_f.Y;
4166                 float block_high_y_f = p_nodes_f.Y + MAP_BLOCKSIZE;
4167
4168                 /*dstream<<"surface_y_max="<<surface_y_max
4169                                 <<", surface_y_min="<<surface_y_min
4170                                 <<", block_low_y_f="<<block_low_y_f
4171                                 <<", block_high_y_f="<<block_high_y_f
4172                                 <<std::endl;*/
4173                 
4174                 // A fuzzyness value
4175                 // Must accomodate mud and turbulence holes
4176                 float d_down = 16;
4177                 // Must accomodate a bit less
4178                 float d_up = 5;
4179
4180                 if(block_high_y_f < surface_y_min - d_down)
4181                 {
4182                         //dstream<<"BT_GROUND"<<std::endl;
4183                         // A ground block
4184                         block_type = BT_GROUND;
4185                 }
4186                 else if(block_low_y_f >= surface_y_max + d_up
4187                                 && block_low_y_f > WATER_LEVEL + d_up)
4188                 {
4189                         //dstream<<"BT_SKY"<<std::endl;
4190                         // A sky block
4191                         block_type = BT_SKY;
4192                 }
4193                 else
4194                 {
4195                         //dstream<<"BT_SURFACE"<<std::endl;
4196                         // A surface block
4197                         block_type = BT_SURFACE;
4198                 }
4199
4200                 if(/*block_type == BT_GROUND ||*/ block_type == BT_SKY)
4201                 {
4202                         lowest_ground_y = surface_y_min;
4203                         highest_ground_y = surface_y_max;
4204                 }
4205         }
4206         
4207         if(block_type == BT_SURFACE || block_type == BT_GROUND)
4208         {
4209                 /*
4210                         Generate ground precisely
4211                 */
4212                 
4213                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4214                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4215                 {
4216                         //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
4217
4218                         //s16 surface_y = 0;
4219
4220                         /*s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
4221                                         + AVERAGE_MUD_AMOUNT;
4222
4223                         if(surface_y < lowest_ground_y)
4224                                 lowest_ground_y = surface_y;
4225                         if(surface_y > highest_ground_y)
4226                                 highest_ground_y = surface_y;*/
4227
4228                         v2s16 real_p2d = v2s16(x0,z0) + p2d*MAP_BLOCKSIZE;
4229
4230                         //s32 surface_depth = AVERAGE_MUD_AMOUNT;
4231                         s16 surface_depth = get_mud_amount(m_seed, v2f(real_p2d.X,real_p2d.Y));
4232                         
4233                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4234                         {
4235         #if 1
4236                                 s16 real_y = block_y * MAP_BLOCKSIZE + y0;
4237                                 v3s16 real_pos = v3s16(x0,y0,z0) + p_nodes;
4238                                 MapNode n;
4239                                 /*
4240                                         Calculate lighting
4241                                         
4242                                         NOTE: If there are some man-made structures above the
4243                                         newly created block, they won't be taken into account.
4244                                 */
4245                                 /*if(real_y > surface_y)
4246                                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);*/
4247
4248                                 /*
4249                                         Calculate material
4250                                 */
4251                                 
4252                                 v3f real_pos_f = intToFloat(real_pos, 1);
4253                                 v2f real_pos_f_2d(real_pos_f.X, real_pos_f.Z);
4254                                 double depth_guess;
4255                                 bool is_ground = is_base_ground(m_seed,
4256                                                 real_pos_f, &depth_guess);
4257                                 
4258                                 // Estimate the surface height
4259                                 float surface_y_f = (float)real_y + depth_guess;
4260                                 s16 surface_y = real_y + depth_guess;
4261                                 
4262                                 // Get some statistics of surface height
4263                                 if(surface_y < lowest_ground_y)
4264                                         lowest_ground_y = surface_y;
4265                                 if(surface_y > highest_ground_y)
4266                                         highest_ground_y = surface_y;
4267
4268                                 // If node is not ground, it's air or water
4269                                 if(is_ground == false)
4270                                 {
4271                                         // If under water level, it's water
4272                                         if(real_y < WATER_LEVEL)
4273                                         {
4274                                                 n.d = water_material;
4275                                                 n.setLight(LIGHTBANK_DAY,
4276                                                                 diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
4277                                                 /*
4278                                                         Add to transforming liquid queue (in case it'd
4279                                                         start flowing)
4280                                                 */
4281                                                 m_transforming_liquid.push_back(real_pos);
4282                                         }
4283                                         // else air
4284                                         else
4285                                                 n.d = CONTENT_AIR;
4286                                 }
4287                                 // Else it's ground or dungeons (air)
4288                                 else
4289                                 {
4290                                         // If it's surface_depth under ground, it's stone
4291                                         if((float)real_y <= surface_y_f - surface_depth - 0.75)
4292                                         {
4293                                                 if(is_underground_mud(m_seed, real_pos_f))
4294                                                         n.d = CONTENT_MUD;
4295                                                 else
4296                                                         n.d = CONTENT_STONE;
4297                                         }
4298                                         else if(surface_y_f <= WATER_LEVEL + 2.1
4299                                                         && get_have_sand(m_seed, real_pos_f_2d))
4300                                         {
4301                                                 n.d = CONTENT_SAND;
4302                                         }
4303                                         else
4304                                         {
4305                                                 /*// It is mud if it is under the first ground
4306                                                 // level or under water
4307                                                 if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
4308                                                 {
4309                                                         n.d = CONTENT_MUD;
4310                                                 }
4311                                                 else
4312                                                 {
4313                                                         n.d = CONTENT_GRASS;
4314                                                 }*/
4315
4316                                                 n.d = CONTENT_MUD;
4317                                                 
4318                                                 /*// If under water level, it's mud
4319                                                 if(real_y < WATER_LEVEL)
4320                                                         n.d = CONTENT_MUD;
4321                                                 // Only the topmost node is grass
4322                                                 else if(real_y <= surface_y - 1)
4323                                                         n.d = CONTENT_MUD;
4324                                                 else
4325                                                         n.d = CONTENT_GRASS;*/
4326                                         }
4327                                 }
4328
4329                                 block->setNode(v3s16(x0,y0,z0), n);
4330         #endif
4331         #if 0
4332                                 s16 real_y = block_y * MAP_BLOCKSIZE + y0;
4333                                 MapNode n;
4334                                 /*
4335                                         Calculate lighting
4336                                         
4337                                         NOTE: If there are some man-made structures above the
4338                                         newly created block, they won't be taken into account.
4339                                 */
4340                                 if(real_y > surface_y)
4341                                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
4342
4343                                 /*
4344                                         Calculate material
4345                                 */
4346
4347                                 // If node is over heightmap y, it's air or water
4348                                 if(real_y > surface_y)
4349                                 {
4350                                         // If under water level, it's water
4351                                         if(real_y < WATER_LEVEL)
4352                                         {
4353                                                 n.d = water_material;
4354                                                 n.setLight(LIGHTBANK_DAY,
4355                                                                 diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
4356                                                 /*
4357                                                         Add to transforming liquid queue (in case it'd
4358                                                         start flowing)
4359                                                 */
4360                                                 v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
4361                                                 m_transforming_liquid.push_back(real_pos);
4362                                         }
4363                                         // else air
4364                                         else
4365                                                 n.d = CONTENT_AIR;
4366                                 }
4367                                 // Else it's ground or dungeons (air)
4368                                 else
4369                                 {
4370                                         // If it's surface_depth under ground, it's stone
4371                                         if(real_y <= surface_y - surface_depth)
4372                                         {
4373                                                 n.d = CONTENT_STONE;
4374                                         }
4375                                         else
4376                                         {
4377                                                 // It is mud if it is under the first ground
4378                                                 // level or under water
4379                                                 if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
4380                                                 {
4381                                                         n.d = CONTENT_MUD;
4382                                                 }
4383                                                 else
4384                                                 {
4385                                                         n.d = CONTENT_GRASS;
4386                                                 }
4387
4388                                                 //n.d = CONTENT_MUD;
4389                                                 
4390                                                 /*// If under water level, it's mud
4391                                                 if(real_y < WATER_LEVEL)
4392                                                         n.d = CONTENT_MUD;
4393                                                 // Only the topmost node is grass
4394                                                 else if(real_y <= surface_y - 1)
4395                                                         n.d = CONTENT_MUD;
4396                                                 else
4397                                                         n.d = CONTENT_GRASS;*/
4398                                         }
4399                                 }
4400
4401                                 block->setNode(v3s16(x0,y0,z0), n);
4402         #endif
4403                         }
4404                 }
4405         }// BT_SURFACE
4406         else // BT_GROUND, BT_SKY or anything else
4407         {
4408                 MapNode n_fill;
4409                 if(block_type == BT_GROUND)
4410                 {
4411                         //n_fill.d = CONTENT_STONE;
4412                 }
4413                 else if(block_type == BT_SKY)
4414                 {
4415                         n_fill.d = CONTENT_AIR;
4416                         n_fill.setLight(LIGHTBANK_DAY, LIGHT_SUN);
4417                 }
4418                 else // fallback
4419                 {
4420                         n_fill.d = CONTENT_MESE;
4421                 }
4422
4423
4424                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4425                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4426                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4427                 {
4428                         //MapNode n = block->getNode(v3s16(x0,y0,z0));
4429                         block->setNode(v3s16(x0,y0,z0), n_fill);
4430                 }
4431         }
4432         
4433         }// ground_timer
4434         
4435         /*
4436                 Calculate some helper variables
4437         */
4438         
4439         // Completely underground if the highest part of block is under lowest
4440         // ground height.
4441         // This has to be very sure; it's probably one too strict now but
4442         // that's just better.
4443         bool completely_underground =
4444                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
4445
4446         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
4447
4448         bool mostly_underwater_surface = false;
4449         if(highest_ground_y < WATER_LEVEL
4450                         && some_part_underground && !completely_underground)
4451                 mostly_underwater_surface = true;
4452
4453         /*
4454                 Get local attributes
4455         */
4456
4457         //dstream<<"generateBlock(): Getting local attributes"<<std::endl;
4458
4459         float caves_amount = 0.5;
4460
4461 #if 0
4462         {
4463                 /*
4464                         NOTE: BEWARE: Too big amount of attribute points slows verything
4465                         down by a lot.
4466                         1 interpolation from 5000 points takes 2-3ms.
4467                 */
4468                 //TimeTaker timer("generateBlock() local attribute retrieval");
4469                 v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
4470                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
4471                 caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
4472         }
4473 #endif
4474
4475         //dstream<<"generateBlock(): Done"<<std::endl;
4476
4477         // Set to true if has caves.
4478         // Set when some non-air is changed to air when making caves.
4479         bool has_dungeons = false;
4480
4481 #if 0
4482         /*
4483                 Generate dungeons
4484         */
4485
4486         // Initialize temporary table
4487         const s32 ued = MAP_BLOCKSIZE;
4488         bool underground_emptiness[ued*ued*ued];
4489         for(s32 i=0; i<ued*ued*ued; i++)
4490         {
4491                 underground_emptiness[i] = 0;
4492         }
4493         
4494         // Fill table
4495 #if 0
4496         {
4497                 /*
4498                         Initialize orp and ors. Try to find if some neighboring
4499                         MapBlock has a tunnel ended in its side
4500                 */
4501
4502                 v3f orp(
4503                         (float)(myrand()%ued)+0.5,
4504                         (float)(myrand()%ued)+0.5,
4505                         (float)(myrand()%ued)+0.5
4506                 );
4507                 
4508                 bool found_existing = false;
4509
4510                 // Check z-
4511                 try
4512                 {
4513                         s16 z = -1;
4514                         for(s16 y=0; y<ued; y++)
4515                         for(s16 x=0; x<ued; x++)
4516                         {
4517                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4518                                 if(getNode(ap).d == CONTENT_AIR)
4519                                 {
4520                                         orp = v3f(x+1,y+1,0);
4521                                         found_existing = true;
4522                                         goto continue_generating;
4523                                 }
4524                         }
4525                 }
4526                 catch(InvalidPositionException &e){}
4527                 
4528                 // Check z+
4529                 try
4530                 {
4531                         s16 z = ued;
4532                         for(s16 y=0; y<ued; y++)
4533                         for(s16 x=0; x<ued; x++)
4534                         {
4535                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4536                                 if(getNode(ap).d == CONTENT_AIR)
4537                                 {
4538                                         orp = v3f(x+1,y+1,ued-1);
4539                                         found_existing = true;
4540                                         goto continue_generating;
4541                                 }
4542                         }
4543                 }
4544                 catch(InvalidPositionException &e){}
4545                 
4546                 // Check x-
4547                 try
4548                 {
4549                         s16 x = -1;
4550                         for(s16 y=0; y<ued; y++)
4551                         for(s16 z=0; z<ued; z++)
4552                         {
4553                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4554                                 if(getNode(ap).d == CONTENT_AIR)
4555                                 {
4556                                         orp = v3f(0,y+1,z+1);
4557                                         found_existing = true;
4558                                         goto continue_generating;
4559                                 }
4560                         }
4561                 }
4562                 catch(InvalidPositionException &e){}
4563                 
4564                 // Check x+
4565                 try
4566                 {
4567                         s16 x = ued;
4568                         for(s16 y=0; y<ued; y++)
4569                         for(s16 z=0; z<ued; z++)
4570                         {
4571                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4572                                 if(getNode(ap).d == CONTENT_AIR)
4573                                 {
4574                                         orp = v3f(ued-1,y+1,z+1);
4575                                         found_existing = true;
4576                                         goto continue_generating;
4577                                 }
4578                         }
4579                 }
4580                 catch(InvalidPositionException &e){}
4581
4582                 // Check y-
4583                 try
4584                 {
4585                         s16 y = -1;
4586                         for(s16 x=0; x<ued; x++)
4587                         for(s16 z=0; z<ued; z++)
4588                         {
4589                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4590                                 if(getNode(ap).d == CONTENT_AIR)
4591                                 {
4592                                         orp = v3f(x+1,0,z+1);
4593                                         found_existing = true;
4594                                         goto continue_generating;
4595                                 }
4596                         }
4597                 }
4598                 catch(InvalidPositionException &e){}
4599                 
4600                 // Check y+
4601                 try
4602                 {
4603                         s16 y = ued;
4604                         for(s16 x=0; x<ued; x++)
4605                         for(s16 z=0; z<ued; z++)
4606                         {
4607                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4608                                 if(getNode(ap).d == CONTENT_AIR)
4609                                 {
4610                                         orp = v3f(x+1,ued-1,z+1);
4611                                         found_existing = true;
4612                                         goto continue_generating;
4613                                 }
4614                         }
4615                 }
4616                 catch(InvalidPositionException &e){}
4617
4618 continue_generating:
4619                 
4620                 /*
4621                         Choose whether to actually generate dungeon
4622                 */
4623                 bool do_generate_dungeons = true;
4624                 // Don't generate if no part is underground
4625                 if(!some_part_underground)
4626                 {
4627                         do_generate_dungeons = false;
4628                 }
4629                 // Don't generate if mostly underwater surface
4630                 /*else if(mostly_underwater_surface)
4631                 {
4632                         do_generate_dungeons = false;
4633                 }*/
4634                 // Partly underground = cave
4635                 else if(!completely_underground)
4636                 {
4637                         //do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
4638                         do_generate_dungeons = false;
4639                 }
4640                 // Found existing dungeon underground
4641                 else if(found_existing && completely_underground)
4642                 {
4643                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
4644                 }
4645                 // Underground and no dungeons found
4646                 else
4647                 {
4648                         do_generate_dungeons = (rand() % 300 <= (s32)(caves_amount*100));
4649                 }
4650
4651                 if(do_generate_dungeons)
4652                 {
4653                         /*
4654                                 Generate some tunnel starting from orp and ors
4655                         */
4656                         for(u16 i=0; i<3; i++)
4657                         {
4658                                 v3f rp(
4659                                         (float)(myrand()%ued)+0.5,
4660                                         (float)(myrand()%ued)+0.5,
4661                                         (float)(myrand()%ued)+0.5
4662                                 );
4663                                 s16 min_d = 0;
4664                                 s16 max_d = 4;
4665                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
4666                                 
4667                                 v3f vec = rp - orp;
4668
4669                                 for(float f=0; f<1.0; f+=0.04)
4670                                 {
4671                                         v3f fp = orp + vec * f;
4672                                         v3s16 cp(fp.X, fp.Y, fp.Z);
4673                                         s16 d0 = -rs/2;
4674                                         s16 d1 = d0 + rs - 1;
4675                                         for(s16 z0=d0; z0<=d1; z0++)
4676                                         {
4677                                                 s16 si = rs - abs(z0);
4678                                                 for(s16 x0=-si; x0<=si-1; x0++)
4679                                                 {
4680                                                         s16 si2 = rs - abs(x0);
4681                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
4682                                                         {
4683                                                                 s16 z = cp.Z + z0;
4684                                                                 s16 y = cp.Y + y0;
4685                                                                 s16 x = cp.X + x0;
4686                                                                 v3s16 p(x,y,z);
4687                                                                 if(isInArea(p, ued) == false)
4688                                                                         continue;
4689                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
4690                                                         }
4691                                                 }
4692                                         }
4693                                 }
4694
4695                                 orp = rp;
4696                         }
4697                 }
4698         }
4699 #endif
4700
4701         /*
4702                 Apply temporary cave data to block
4703         */
4704
4705         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4706         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4707         {
4708                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4709                 {
4710                         MapNode n = block->getNode(v3s16(x0,y0,z0));
4711
4712                         // Create dungeons
4713                         if(underground_emptiness[
4714                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
4715                                         +ued*(y0*ued/MAP_BLOCKSIZE)
4716                                         +(x0*ued/MAP_BLOCKSIZE)])
4717                         {
4718                                 if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
4719                                 {
4720                                         // Has now caves
4721                                         has_dungeons = true;
4722                                         // Set air to node
4723                                         n.d = CONTENT_AIR;
4724                                 }
4725                         }
4726
4727                         block->setNode(v3s16(x0,y0,z0), n);
4728                 }
4729         }
4730 #endif
4731         
4732         /*
4733                 This is used for guessing whether or not the block should
4734                 receive sunlight from the top if the block above doesn't exist
4735         */
4736         block->setIsUnderground(completely_underground);
4737
4738         /*
4739                 Force lighting update if some part of block is partly
4740                 underground and has caves.
4741         */
4742         /*if(some_part_underground && !completely_underground && has_dungeons)
4743         {
4744                 //dstream<<"Half-ground caves"<<std::endl;
4745                 lighting_invalidated_blocks[block->getPos()] = block;
4746         }*/
4747         
4748         // DEBUG: Always update lighting
4749         //lighting_invalidated_blocks[block->getPos()] = block;
4750
4751         /*
4752                 Add some minerals
4753         */
4754
4755         if(some_part_underground)
4756         {
4757                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
4758
4759                 /*
4760                         Add meseblocks
4761                 */
4762                 for(s16 i=0; i<underground_level/4 + 1; i++)
4763                 {
4764                         if(myrand()%50 == 0)
4765                         {
4766                                 v3s16 cp(
4767                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4768                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4769                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4770                                 );
4771
4772                                 MapNode n;
4773                                 n.d = CONTENT_MESE;
4774                                 
4775                                 for(u16 i=0; i<27; i++)
4776                                 {
4777                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4778                                                 if(myrand()%8 == 0)
4779                                                         block->setNode(cp+g_27dirs[i], n);
4780                                 }
4781                         }
4782                 }
4783
4784                 /*
4785                         Add coal
4786                 */
4787                 u16 coal_amount = 60;
4788                 u16 coal_rareness = 120 / coal_amount;
4789                 if(coal_rareness == 0)
4790                         coal_rareness = 1;
4791                 if(myrand()%coal_rareness == 0)
4792                 {
4793                         u16 a = myrand() % 16;
4794                         u16 amount = coal_amount * a*a*a / 1000;
4795                         for(s16 i=0; i<amount; i++)
4796                         {
4797                                 v3s16 cp(
4798                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4799                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4800                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4801                                 );
4802
4803                                 MapNode n;
4804                                 n.d = CONTENT_STONE;
4805                                 n.param = MINERAL_COAL;
4806
4807                                 for(u16 i=0; i<27; i++)
4808                                 {
4809                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4810                                                 if(myrand()%8 == 0)
4811                                                         block->setNode(cp+g_27dirs[i], n);
4812                                 }
4813                         }
4814                 }
4815
4816                 /*
4817                         Add iron
4818                 */
4819                 u16 iron_amount = 40;
4820                 u16 iron_rareness = 80 / iron_amount;
4821                 if(iron_rareness == 0)
4822                         iron_rareness = 1;
4823                 if(myrand()%iron_rareness == 0)
4824                 {
4825                         u16 a = myrand() % 16;
4826                         u16 amount = iron_amount * a*a*a / 1000;
4827                         for(s16 i=0; i<amount; i++)
4828                         {
4829                                 v3s16 cp(
4830                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4831                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4832                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4833                                 );
4834
4835                                 MapNode n;
4836                                 n.d = CONTENT_STONE;
4837                                 n.param = MINERAL_IRON;
4838
4839                                 for(u16 i=0; i<27; i++)
4840                                 {
4841                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4842                                                 if(myrand()%8 == 0)
4843                                                         block->setNode(cp+g_27dirs[i], n);
4844                                 }
4845                         }
4846                 }
4847         }
4848         
4849         /*
4850                 Create a few rats in empty blocks underground
4851         */
4852         if(completely_underground)
4853         {
4854                 //for(u16 i=0; i<2; i++)
4855                 {
4856                         v3s16 cp(
4857                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4858                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4859                                 (myrand()%(MAP_BLOCKSIZE-2))+1
4860                         );
4861
4862                         // Check that the place is empty
4863                         //if(!is_ground_content(block->getNode(cp).d))
4864                         if(1)
4865                         {
4866                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp, BS));
4867                                 block->addObject(obj);
4868                         }
4869                 }
4870         }
4871         
4872         /*
4873                 Add block to sector
4874         */
4875         sector->insertBlock(block);
4876         
4877         // Lighting is invalid after generation for surface blocks
4878         if(block_type == BT_SURFACE)
4879         {
4880                 block->setLightingExpired(true);
4881                 lighting_invalidated_blocks.insert(p, block);
4882         }
4883         // Lighting is not invalid for other blocks
4884         else
4885         {
4886                 block->setLightingExpired(false);
4887         }
4888
4889         /*
4890                 Add trees
4891         */
4892 #if 1
4893         if(some_part_underground && !completely_underground)
4894         {
4895                 MapVoxelManipulator vm(this);
4896                 
4897                 double a = tree_amount_2d(m_seed, v2s16(p_nodes.X+8, p_nodes.Z+8));
4898                 u16 tree_count = (u16)(a*MAP_BLOCKSIZE*MAP_BLOCKSIZE);
4899                 for(u16 i=0; i<tree_count/2; i++)
4900                 {
4901                         v3s16 tree_p = p_nodes + v3s16(
4902                                 myrand_range(0,MAP_BLOCKSIZE-1),
4903                                 8,
4904                                 myrand_range(0,MAP_BLOCKSIZE-1)
4905                         );
4906                         double depth_guess;
4907                         /*bool is_ground =*/ is_base_ground(m_seed,
4908                                         intToFloat(tree_p, 1), &depth_guess);
4909                         tree_p.Y += (depth_guess - 0.5);
4910                         if(tree_p.Y <= WATER_LEVEL)
4911                                 continue;
4912                         make_tree(vm, tree_p);
4913                 }
4914
4915                 vm.blitBack(changed_blocks);
4916         }
4917 #endif
4918         
4919 #if 0
4920         /*
4921                 Debug information
4922         */
4923         dstream
4924         <<"lighting_invalidated_blocks.size()"
4925         <<", has_dungeons"
4926         <<", completely_ug"
4927         <<", some_part_ug"
4928         <<"  "<<lighting_invalidated_blocks.size()
4929         <<", "<<has_dungeons
4930         <<", "<<completely_underground
4931         <<", "<<some_part_underground
4932         <<std::endl;
4933 #endif
4934
4935         return block;
4936 }
4937
4938 MapBlock * ServerMap::createBlock(v3s16 p)
4939 {
4940         DSTACK("%s: p=(%d,%d,%d)",
4941                         __FUNCTION_NAME, p.X, p.Y, p.Z);
4942         
4943         /*
4944                 Do not create over-limit
4945         */
4946         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4947         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4948         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4949         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4950         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4951         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4952                 throw InvalidPositionException("createBlock(): pos. over limit");
4953         
4954         v2s16 p2d(p.X, p.Z);
4955         s16 block_y = p.Y;
4956         /*
4957                 This will create or load a sector if not found in memory.
4958                 If block exists on disk, it will be loaded.
4959
4960                 NOTE: On old save formats, this will be slow, as it generates
4961                       lighting on blocks for them.
4962         */
4963         ServerMapSector *sector;
4964         try{
4965                 sector = (ServerMapSector*)createSector(p2d);
4966                 assert(sector->getId() == MAPSECTOR_SERVER);
4967         }
4968         catch(InvalidPositionException &e)
4969         {
4970                 dstream<<"createBlock: createSector() failed"<<std::endl;
4971                 throw e;
4972         }
4973         /*
4974                 NOTE: This should not be done, or at least the exception
4975                 should not be passed on as std::exception, because it
4976                 won't be catched at all.
4977         */
4978         /*catch(std::exception &e)
4979         {
4980                 dstream<<"createBlock: createSector() failed: "
4981                                 <<e.what()<<std::endl;
4982                 throw e;
4983         }*/
4984
4985         /*
4986                 Try to get a block from the sector
4987         */
4988
4989         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4990         if(block)
4991                 return block;
4992         // Create blank
4993         block = sector->createBlankBlock(block_y);
4994         return block;
4995 }
4996
4997 MapBlock * ServerMap::emergeBlock(
4998                 v3s16 p,
4999                 bool only_from_disk,
5000                 core::map<v3s16, MapBlock*> &changed_blocks,
5001                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
5002 )
5003 {
5004         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
5005                         __FUNCTION_NAME,
5006                         p.X, p.Y, p.Z, only_from_disk);
5007         
5008         /*
5009                 Do not generate over-limit
5010         */
5011         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5012         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5013         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5014         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5015         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5016         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
5017                 throw InvalidPositionException("emergeBlock(): pos. over limit");
5018         
5019         v2s16 p2d(p.X, p.Z);
5020         s16 block_y = p.Y;
5021         /*
5022                 This will create or load a sector if not found in memory.
5023                 If block exists on disk, it will be loaded.
5024         */
5025         ServerMapSector *sector;
5026         try{
5027                 sector = (ServerMapSector*)emergeSector(p2d, changed_blocks);
5028                 assert(sector->getId() == MAPSECTOR_SERVER);
5029         }
5030         catch(InvalidPositionException &e)
5031         {
5032                 dstream<<"emergeBlock: emergeSector() failed: "
5033                                 <<e.what()<<std::endl;
5034                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
5035                                 <<std::endl
5036                                 <<"You could try to delete it."<<std::endl;
5037                 throw e;
5038         }
5039         catch(VersionMismatchException &e)
5040         {
5041                 dstream<<"emergeBlock: emergeSector() failed: "
5042                                 <<e.what()<<std::endl;
5043                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
5044                                 <<std::endl
5045                                 <<"You could try to delete it."<<std::endl;
5046                 throw e;
5047         }
5048         /*
5049                 NOTE: This should not be done, or at least the exception
5050                 should not be passed on as std::exception, because it
5051                 won't be catched at all.
5052         */
5053         /*catch(std::exception &e)
5054         {
5055                 dstream<<"emergeBlock: emergeSector() failed: "
5056                                 <<e.what()<<std::endl;
5057                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
5058                                 <<std::endl
5059                                 <<"You could try to delete it."<<std::endl;
5060                 throw e;
5061         }*/
5062
5063         /*
5064                 Try to get a block from the sector
5065         */
5066
5067         bool does_not_exist = false;
5068         bool lighting_expired = false;
5069         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
5070
5071         if(block == NULL)
5072         {
5073                 does_not_exist = true;
5074         }
5075         else if(block->isDummy() == true)
5076         {
5077                 does_not_exist = true;
5078         }
5079         else if(block->getLightingExpired())
5080         {
5081                 lighting_expired = true;
5082         }
5083         else
5084         {
5085                 // Valid block
5086                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
5087                 return block;
5088         }
5089         
5090         /*
5091                 If block was not found on disk and not going to generate a
5092                 new one, make sure there is a dummy block in place.
5093         */
5094         if(only_from_disk && (does_not_exist || lighting_expired))
5095         {
5096                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
5097
5098                 if(block == NULL)
5099                 {
5100                         // Create dummy block
5101                         block = new MapBlock(this, p, true);
5102
5103                         // Add block to sector
5104                         sector->insertBlock(block);
5105                 }
5106                 // Done.
5107                 return block;
5108         }
5109
5110         //dstream<<"Not found on disk, generating."<<std::endl;
5111         // 0ms
5112         //TimeTaker("emergeBlock() generate");
5113
5114         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
5115
5116         /*
5117                 If the block doesn't exist, generate the block.
5118         */
5119         if(does_not_exist)
5120         {
5121                 block = generateBlock(p, block, sector, changed_blocks,
5122                                 lighting_invalidated_blocks);
5123
5124                 lighting_expired = block->getLightingExpired();
5125         }
5126
5127         if(lighting_expired)
5128         {
5129                 lighting_invalidated_blocks.insert(p, block);
5130         }
5131
5132         /*
5133                 Initially update sunlight
5134         */
5135         
5136         if(lighting_expired)
5137         {
5138                 core::map<v3s16, bool> light_sources;
5139                 bool black_air_left = false;
5140                 bool bottom_invalid =
5141                                 block->propagateSunlight(light_sources, true,
5142                                 &black_air_left, true);
5143
5144                 // If sunlight didn't reach everywhere and part of block is
5145                 // above ground, lighting has to be properly updated
5146                 //if(black_air_left && some_part_underground)
5147                 if(black_air_left)
5148                 {
5149                         lighting_invalidated_blocks[block->getPos()] = block;
5150                 }
5151
5152                 if(bottom_invalid)
5153                 {
5154                         lighting_invalidated_blocks[block->getPos()] = block;
5155                 }
5156         }
5157         
5158         return block;
5159 }
5160
5161 s16 ServerMap::findGroundLevel(v2s16 p2d)
5162 {
5163         /*
5164                 Uh, just do something random...
5165         */
5166         // Find existing map from top to down
5167         s16 max=63;
5168         s16 min=-64;
5169         v3s16 p(p2d.X, max, p2d.Y);
5170         for(; p.Y>min; p.Y--)
5171         {
5172                 MapNode n = getNodeNoEx(p);
5173                 if(n.d != CONTENT_IGNORE)
5174                         break;
5175         }
5176         if(p.Y == min)
5177                 goto plan_b;
5178         // If this node is not air, go to plan b
5179         if(getNodeNoEx(p).d != CONTENT_AIR)
5180                 goto plan_b;
5181         // Search existing walkable and return it
5182         for(; p.Y>min; p.Y--)
5183         {
5184                 MapNode n = getNodeNoEx(p);
5185                 if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
5186                         return p.Y;
5187         }
5188         // Move to plan b
5189 plan_b:
5190         /*
5191                 Plan B: Get from map generator perlin noise function
5192         */
5193         double level = base_rock_level_2d(m_seed, p2d);
5194         return (s16)level;
5195 }
5196
5197 void ServerMap::createDir(std::string path)
5198 {
5199         if(fs::CreateDir(path) == false)
5200         {
5201                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
5202                                 <<"\""<<path<<"\""<<std::endl;
5203                 throw BaseException("ServerMap failed to create directory");
5204         }
5205 }
5206
5207 std::string ServerMap::getSectorSubDir(v2s16 pos)
5208 {
5209         char cc[9];
5210         snprintf(cc, 9, "%.4x%.4x",
5211                         (unsigned int)pos.X&0xffff,
5212                         (unsigned int)pos.Y&0xffff);
5213
5214         return std::string(cc);
5215 }
5216
5217 std::string ServerMap::getSectorDir(v2s16 pos)
5218 {
5219         return m_savedir + "/sectors/" + getSectorSubDir(pos);
5220 }
5221
5222 v2s16 ServerMap::getSectorPos(std::string dirname)
5223 {
5224         if(dirname.size() != 8)
5225                 throw InvalidFilenameException("Invalid sector directory name");
5226         unsigned int x, y;
5227         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
5228         if(r != 2)
5229                 throw InvalidFilenameException("Invalid sector directory name");
5230         v2s16 pos((s16)x, (s16)y);
5231         return pos;
5232 }
5233
5234 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
5235 {
5236         v2s16 p2d = getSectorPos(sectordir);
5237
5238         if(blockfile.size() != 4){
5239                 throw InvalidFilenameException("Invalid block filename");
5240         }
5241         unsigned int y;
5242         int r = sscanf(blockfile.c_str(), "%4x", &y);
5243         if(r != 1)
5244                 throw InvalidFilenameException("Invalid block filename");
5245         return v3s16(p2d.X, y, p2d.Y);
5246 }
5247
5248 void ServerMap::save(bool only_changed)
5249 {
5250         DSTACK(__FUNCTION_NAME);
5251         if(m_map_saving_enabled == false)
5252         {
5253                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
5254                 return;
5255         }
5256         
5257         if(only_changed == false)
5258                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
5259                                 <<std::endl;
5260         
5261         saveMapMeta();
5262         saveChunkMeta();
5263         
5264         u32 sector_meta_count = 0;
5265         u32 block_count = 0;
5266         
5267         { //sectorlock
5268         JMutexAutoLock lock(m_sector_mutex);
5269         
5270         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
5271         for(; i.atEnd() == false; i++)
5272         {
5273                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
5274                 assert(sector->getId() == MAPSECTOR_SERVER);
5275         
5276                 if(sector->differs_from_disk || only_changed == false)
5277                 {
5278                         saveSectorMeta(sector);
5279                         sector_meta_count++;
5280                 }
5281                 core::list<MapBlock*> blocks;
5282                 sector->getBlocks(blocks);
5283                 core::list<MapBlock*>::Iterator j;
5284                 for(j=blocks.begin(); j!=blocks.end(); j++)
5285                 {
5286                         MapBlock *block = *j;
5287                         if(block->getChangedFlag() || only_changed == false)
5288                         {
5289                                 saveBlock(block);
5290                                 block_count++;
5291
5292                                 /*dstream<<"ServerMap: Written block ("
5293                                                 <<block->getPos().X<<","
5294                                                 <<block->getPos().Y<<","
5295                                                 <<block->getPos().Z<<")"
5296                                                 <<std::endl;*/
5297                         }
5298                 }
5299         }
5300
5301         }//sectorlock
5302         
5303         /*
5304                 Only print if something happened or saved whole map
5305         */
5306         if(only_changed == false || sector_meta_count != 0
5307                         || block_count != 0)
5308         {
5309                 dstream<<DTIME<<"ServerMap: Written: "
5310                                 <<sector_meta_count<<" sector metadata files, "
5311                                 <<block_count<<" block files"
5312                                 <<std::endl;
5313         }
5314 }
5315
5316 void ServerMap::loadAll()
5317 {
5318         DSTACK(__FUNCTION_NAME);
5319         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
5320         
5321         loadMapMeta();
5322         loadChunkMeta();
5323
5324         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
5325
5326         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
5327         
5328         JMutexAutoLock lock(m_sector_mutex);
5329         
5330         s32 counter = 0;
5331         s32 printed_counter = -100000;
5332         s32 count = list.size();
5333
5334         std::vector<fs::DirListNode>::iterator i;
5335         for(i=list.begin(); i!=list.end(); i++)
5336         {
5337                 if(counter > printed_counter + 10)
5338                 {
5339                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
5340                         printed_counter = counter;
5341                 }
5342                 counter++;
5343
5344                 MapSector *sector = NULL;
5345
5346                 // We want directories
5347                 if(i->dir == false)
5348                         continue;
5349                 try{
5350                         sector = loadSectorMeta(i->name);
5351                 }
5352                 catch(InvalidFilenameException &e)
5353                 {
5354                         // This catches unknown crap in directory
5355                 }
5356                 
5357                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
5358                                 (m_savedir+"/sectors/"+i->name);
5359                 std::vector<fs::DirListNode>::iterator i2;
5360                 for(i2=list2.begin(); i2!=list2.end(); i2++)
5361                 {
5362                         // We want files
5363                         if(i2->dir)
5364                                 continue;
5365                         try{
5366                                 loadBlock(i->name, i2->name, sector);
5367                         }
5368                         catch(InvalidFilenameException &e)
5369                         {
5370                                 // This catches unknown crap in directory
5371                         }
5372                 }
5373         }
5374         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
5375 }
5376
5377 #if 0
5378 void ServerMap::saveMasterHeightmap()
5379 {
5380         DSTACK(__FUNCTION_NAME);
5381         
5382         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
5383
5384         createDir(m_savedir);
5385         
5386         /*std::string fullpath = m_savedir + "/master_heightmap";
5387         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5388         if(o.good() == false)
5389                 throw FileNotGoodException("Cannot open master heightmap");*/
5390         
5391         // Format used for writing
5392         //u8 version = SER_FMT_VER_HIGHEST;
5393 }
5394
5395 void ServerMap::loadMasterHeightmap()
5396 {
5397         DSTACK(__FUNCTION_NAME);
5398         
5399         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
5400
5401         /*std::string fullpath = m_savedir + "/master_heightmap";
5402         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5403         if(is.good() == false)
5404                 throw FileNotGoodException("Cannot open master heightmap");*/
5405 }
5406 #endif
5407
5408 void ServerMap::saveMapMeta()
5409 {
5410         DSTACK(__FUNCTION_NAME);
5411         
5412         dstream<<"INFO: ServerMap::saveMapMeta(): "
5413                         <<"seed="<<m_seed<<", chunksize="<<m_chunksize
5414                         <<std::endl;
5415
5416         createDir(m_savedir);
5417         
5418         std::string fullpath = m_savedir + "/map_meta.txt";
5419         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
5420         if(os.good() == false)
5421         {
5422                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
5423                                 <<"could not open"<<fullpath<<std::endl;
5424                 throw FileNotGoodException("Cannot open chunk metadata");
5425         }
5426         
5427         Settings params;
5428         params.setU64("seed", m_seed);
5429         params.setS32("chunksize", m_chunksize);
5430
5431         params.writeLines(os);
5432
5433         os<<"[end_of_params]\n";
5434         
5435 }
5436
5437 void ServerMap::loadMapMeta()
5438 {
5439         DSTACK(__FUNCTION_NAME);
5440         
5441         dstream<<"INFO: ServerMap::loadMapMeta(): Loading chunk metadata"
5442                         <<std::endl;
5443
5444         std::string fullpath = m_savedir + "/map_meta.txt";
5445         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5446         if(is.good() == false)
5447         {
5448                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
5449                                 <<"could not open"<<fullpath<<std::endl;
5450                 throw FileNotGoodException("Cannot open chunk metadata");
5451         }
5452
5453         Settings params;
5454
5455         for(;;)
5456         {
5457                 if(is.eof())
5458                         throw SerializationError
5459                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
5460                 std::string line;
5461                 std::getline(is, line);
5462                 std::string trimmedline = trim(line);
5463                 if(trimmedline == "[end_of_params]")
5464                         break;
5465                 params.parseConfigLine(line);
5466         }
5467
5468         m_seed = params.getU64("seed");
5469         m_chunksize = params.getS32("chunksize");
5470
5471         dstream<<"INFO: ServerMap::loadMapMeta(): "
5472                         <<"seed="<<m_seed<<", chunksize="<<m_chunksize
5473                         <<std::endl;
5474 }
5475
5476 void ServerMap::saveChunkMeta()
5477 {
5478         DSTACK(__FUNCTION_NAME);
5479         
5480         u32 count = m_chunks.size();
5481
5482         dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
5483                         <<count<<" chunks"<<std::endl;
5484
5485         createDir(m_savedir);
5486         
5487         std::string fullpath = m_savedir + "/chunk_meta";
5488         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
5489         if(os.good() == false)
5490         {
5491                 dstream<<"ERROR: ServerMap::saveChunkMeta(): "
5492                                 <<"could not open"<<fullpath<<std::endl;
5493                 throw FileNotGoodException("Cannot open chunk metadata");
5494         }
5495         
5496         u8 version = 0;
5497         
5498         // Write version
5499         os.write((char*)&version, 1);
5500
5501         u8 buf[4];
5502         
5503         // Write count
5504         writeU32(buf, count);
5505         os.write((char*)buf, 4);
5506         
5507         for(core::map<v2s16, MapChunk*>::Iterator
5508                         i = m_chunks.getIterator();
5509                         i.atEnd()==false; i++)
5510         {
5511                 v2s16 p = i.getNode()->getKey();
5512                 MapChunk *chunk = i.getNode()->getValue();
5513                 // Write position
5514                 writeV2S16(buf, p);
5515                 os.write((char*)buf, 4);
5516                 // Write chunk data
5517                 chunk->serialize(os, version);
5518         }
5519 }
5520
5521 void ServerMap::loadChunkMeta()
5522 {
5523         DSTACK(__FUNCTION_NAME);
5524         
5525         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading chunk metadata"
5526                         <<std::endl;
5527
5528         std::string fullpath = m_savedir + "/chunk_meta";
5529         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5530         if(is.good() == false)
5531         {
5532                 dstream<<"ERROR: ServerMap::loadChunkMeta(): "
5533                                 <<"could not open"<<fullpath<<std::endl;
5534                 throw FileNotGoodException("Cannot open chunk metadata");
5535         }
5536
5537         u8 version = 0;
5538         
5539         // Read version
5540         is.read((char*)&version, 1);
5541
5542         u8 buf[4];
5543         
5544         // Read count
5545         is.read((char*)buf, 4);
5546         u32 count = readU32(buf);
5547
5548         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading metadata of "
5549                         <<count<<" chunks"<<std::endl;
5550         
5551         for(u32 i=0; i<count; i++)
5552         {
5553                 v2s16 p;
5554                 MapChunk *chunk = new MapChunk();
5555                 // Read position
5556                 is.read((char*)buf, 4);
5557                 p = readV2S16(buf);
5558                 // Read chunk data
5559                 chunk->deSerialize(is, version);
5560                 m_chunks.insert(p, chunk);
5561         }
5562 }
5563
5564 void ServerMap::saveSectorMeta(ServerMapSector *sector)
5565 {
5566         DSTACK(__FUNCTION_NAME);
5567         // Format used for writing
5568         u8 version = SER_FMT_VER_HIGHEST;
5569         // Get destination
5570         v2s16 pos = sector->getPos();
5571         createDir(m_savedir);
5572         createDir(m_savedir+"/sectors");
5573         std::string dir = getSectorDir(pos);
5574         createDir(dir);
5575         
5576         std::string fullpath = dir + "/meta";
5577         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5578         if(o.good() == false)
5579                 throw FileNotGoodException("Cannot open sector metafile");
5580
5581         sector->serialize(o, version);
5582         
5583         sector->differs_from_disk = false;
5584 }
5585
5586 MapSector* ServerMap::loadSectorMeta(std::string dirname)
5587 {
5588         DSTACK(__FUNCTION_NAME);
5589         // Get destination
5590         v2s16 p2d = getSectorPos(dirname);
5591         std::string dir = m_savedir + "/sectors/" + dirname;
5592         
5593         std::string fullpath = dir + "/meta";
5594         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5595         if(is.good() == false)
5596                 throw FileNotGoodException("Cannot open sector metafile");
5597
5598         ServerMapSector *sector = ServerMapSector::deSerialize
5599                         (is, this, p2d, m_sectors);
5600         
5601         sector->differs_from_disk = false;
5602
5603         return sector;
5604 }
5605
5606 bool ServerMap::loadSectorFull(v2s16 p2d)
5607 {
5608         DSTACK(__FUNCTION_NAME);
5609         std::string sectorsubdir = getSectorSubDir(p2d);
5610
5611         MapSector *sector = NULL;
5612
5613         JMutexAutoLock lock(m_sector_mutex);
5614
5615         try{
5616                 sector = loadSectorMeta(sectorsubdir);
5617         }
5618         catch(InvalidFilenameException &e)
5619         {
5620                 return false;
5621         }
5622         catch(FileNotGoodException &e)
5623         {
5624                 return false;
5625         }
5626         catch(std::exception &e)
5627         {
5628                 return false;
5629         }
5630         
5631         /*
5632                 Load blocks
5633         */
5634         std::vector<fs::DirListNode> list2 = fs::GetDirListing
5635                         (m_savedir+"/sectors/"+sectorsubdir);
5636         std::vector<fs::DirListNode>::iterator i2;
5637         for(i2=list2.begin(); i2!=list2.end(); i2++)
5638         {
5639                 // We want files
5640                 if(i2->dir)
5641                         continue;
5642                 try{
5643                         loadBlock(sectorsubdir, i2->name, sector);
5644                 }
5645                 catch(InvalidFilenameException &e)
5646                 {
5647                         // This catches unknown crap in directory
5648                 }
5649         }
5650         return true;
5651 }
5652
5653 void ServerMap::saveBlock(MapBlock *block)
5654 {
5655         DSTACK(__FUNCTION_NAME);
5656         /*
5657                 Dummy blocks are not written
5658         */
5659         if(block->isDummy())
5660         {
5661                 /*v3s16 p = block->getPos();
5662                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
5663                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
5664                 return;
5665         }
5666
5667         // Format used for writing
5668         u8 version = SER_FMT_VER_HIGHEST;
5669         // Get destination
5670         v3s16 p3d = block->getPos();
5671         v2s16 p2d(p3d.X, p3d.Z);
5672         createDir(m_savedir);
5673         createDir(m_savedir+"/sectors");
5674         std::string dir = getSectorDir(p2d);
5675         createDir(dir);
5676         
5677         // Block file is map/sectors/xxxxxxxx/xxxx
5678         char cc[5];
5679         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
5680         std::string fullpath = dir + "/" + cc;
5681         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5682         if(o.good() == false)
5683                 throw FileNotGoodException("Cannot open block data");
5684
5685         /*
5686                 [0] u8 serialization version
5687                 [1] data
5688         */
5689         o.write((char*)&version, 1);
5690         
5691         block->serialize(o, version);
5692
5693         /*
5694                 Versions up from 9 have block objects.
5695         */
5696         if(version >= 9)
5697         {
5698                 block->serializeObjects(o, version);
5699         }
5700         
5701         // We just wrote it to the disk
5702         block->resetChangedFlag();
5703 }
5704
5705 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
5706 {
5707         DSTACK(__FUNCTION_NAME);
5708
5709         try{
5710
5711                 // Block file is map/sectors/xxxxxxxx/xxxx
5712                 std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
5713                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5714                 if(is.good() == false)
5715                         throw FileNotGoodException("Cannot open block file");
5716
5717                 v3s16 p3d = getBlockPos(sectordir, blockfile);
5718                 v2s16 p2d(p3d.X, p3d.Z);
5719                 
5720                 assert(sector->getPos() == p2d);
5721                 
5722                 u8 version = SER_FMT_VER_INVALID;
5723                 is.read((char*)&version, 1);
5724
5725                 if(is.fail())
5726                         throw SerializationError("ServerMap::loadBlock(): Failed"
5727                                         " to read MapBlock version");
5728
5729                 /*u32 block_size = MapBlock::serializedLength(version);
5730                 SharedBuffer<u8> data(block_size);
5731                 is.read((char*)*data, block_size);*/
5732
5733                 // This will always return a sector because we're the server
5734                 //MapSector *sector = emergeSector(p2d);
5735
5736                 MapBlock *block = NULL;
5737                 bool created_new = false;
5738                 try{
5739                         block = sector->getBlockNoCreate(p3d.Y);
5740                 }
5741                 catch(InvalidPositionException &e)
5742                 {
5743                         block = sector->createBlankBlockNoInsert(p3d.Y);
5744                         created_new = true;
5745                 }
5746                 
5747                 // deserialize block data
5748                 block->deSerialize(is, version);
5749                 
5750                 /*
5751                         Versions up from 9 have block objects.
5752                 */
5753                 if(version >= 9)
5754                 {
5755                         block->updateObjects(is, version, NULL, 0);
5756                 }
5757
5758                 if(created_new)
5759                         sector->insertBlock(block);
5760                 
5761                 /*
5762                         Convert old formats to new and save
5763                 */
5764
5765                 // Save old format blocks in new format
5766                 if(version < SER_FMT_VER_HIGHEST)
5767                 {
5768                         saveBlock(block);
5769                 }
5770                 
5771                 // We just loaded it from the disk, so it's up-to-date.
5772                 block->resetChangedFlag();
5773
5774         }
5775         catch(SerializationError &e)
5776         {
5777                 dstream<<"WARNING: Invalid block data on disk "
5778                                 "(SerializationError). Ignoring. "
5779                                 "A new one will be generated."
5780                                 <<std::endl;
5781         }
5782 }
5783
5784 void ServerMap::PrintInfo(std::ostream &out)
5785 {
5786         out<<"ServerMap: ";
5787 }
5788
5789 #ifndef SERVER
5790
5791 /*
5792         ClientMap
5793 */
5794
5795 ClientMap::ClientMap(
5796                 Client *client,
5797                 MapDrawControl &control,
5798                 scene::ISceneNode* parent,
5799                 scene::ISceneManager* mgr,
5800                 s32 id
5801 ):
5802         Map(dout_client),
5803         scene::ISceneNode(parent, mgr, id),
5804         m_client(client),
5805         m_control(control),
5806         m_camera_position(0,0,0),
5807         m_camera_direction(0,0,1)
5808 {
5809         m_camera_mutex.Init();
5810         assert(m_camera_mutex.IsInitialized());
5811         
5812         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
5813                         BS*1000000,BS*1000000,BS*1000000);
5814 }
5815
5816 ClientMap::~ClientMap()
5817 {
5818         /*JMutexAutoLock lock(mesh_mutex);
5819         
5820         if(mesh != NULL)
5821         {
5822                 mesh->drop();
5823                 mesh = NULL;
5824         }*/
5825 }
5826
5827 MapSector * ClientMap::emergeSector(v2s16 p2d)
5828 {
5829         DSTACK(__FUNCTION_NAME);
5830         // Check that it doesn't exist already
5831         try{
5832                 return getSectorNoGenerate(p2d);
5833         }
5834         catch(InvalidPositionException &e)
5835         {
5836         }
5837         
5838         // Create a sector
5839         ClientMapSector *sector = new ClientMapSector(this, p2d);
5840         
5841         {
5842                 JMutexAutoLock lock(m_sector_mutex);
5843                 m_sectors.insert(p2d, sector);
5844         }
5845         
5846         return sector;
5847 }
5848
5849 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
5850 {
5851         DSTACK(__FUNCTION_NAME);
5852         ClientMapSector *sector = NULL;
5853
5854         JMutexAutoLock lock(m_sector_mutex);
5855         
5856         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
5857
5858         if(n != NULL)
5859         {
5860                 sector = (ClientMapSector*)n->getValue();
5861                 assert(sector->getId() == MAPSECTOR_CLIENT);
5862         }
5863         else
5864         {
5865                 sector = new ClientMapSector(this, p2d);
5866                 {
5867                         JMutexAutoLock lock(m_sector_mutex);
5868                         m_sectors.insert(p2d, sector);
5869                 }
5870         }
5871
5872         sector->deSerialize(is);
5873 }
5874
5875 void ClientMap::OnRegisterSceneNode()
5876 {
5877         if(IsVisible)
5878         {
5879                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
5880                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
5881         }
5882
5883         ISceneNode::OnRegisterSceneNode();
5884 }
5885
5886 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
5887 {
5888         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
5889         DSTACK(__FUNCTION_NAME);
5890
5891         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
5892
5893         /*
5894                 Get time for measuring timeout.
5895                 
5896                 Measuring time is very useful for long delays when the
5897                 machine is swapping a lot.
5898         */
5899         int time1 = time(0);
5900
5901         u32 daynight_ratio = m_client->getDayNightRatio();
5902
5903         m_camera_mutex.Lock();
5904         v3f camera_position = m_camera_position;
5905         v3f camera_direction = m_camera_direction;
5906         m_camera_mutex.Unlock();
5907
5908         /*
5909                 Get all blocks and draw all visible ones
5910         */
5911
5912         v3s16 cam_pos_nodes(
5913                         camera_position.X / BS,
5914                         camera_position.Y / BS,
5915                         camera_position.Z / BS);
5916
5917         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
5918
5919         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
5920         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
5921
5922         // Take a fair amount as we will be dropping more out later
5923         v3s16 p_blocks_min(
5924                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
5925                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
5926                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
5927         v3s16 p_blocks_max(
5928                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
5929                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
5930                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
5931         
5932         u32 vertex_count = 0;
5933         
5934         // For limiting number of mesh updates per frame
5935         u32 mesh_update_count = 0;
5936         
5937         u32 blocks_would_have_drawn = 0;
5938         u32 blocks_drawn = 0;
5939
5940         //NOTE: The sectors map should be locked but we're not doing it
5941         // because it'd cause too much delays
5942
5943         int timecheck_counter = 0;
5944         core::map<v2s16, MapSector*>::Iterator si;
5945         si = m_sectors.getIterator();
5946         for(; si.atEnd() == false; si++)
5947         {
5948                 {
5949                         timecheck_counter++;
5950                         if(timecheck_counter > 50)
5951                         {
5952                                 timecheck_counter = 0;
5953                                 int time2 = time(0);
5954                                 if(time2 > time1 + 4)
5955                                 {
5956                                         dstream<<"ClientMap::renderMap(): "
5957                                                 "Rendering takes ages, returning."
5958                                                 <<std::endl;
5959                                         return;
5960                                 }
5961                         }
5962                 }
5963
5964                 MapSector *sector = si.getNode()->getValue();
5965                 v2s16 sp = sector->getPos();
5966                 
5967                 if(m_control.range_all == false)
5968                 {
5969                         if(sp.X < p_blocks_min.X
5970                         || sp.X > p_blocks_max.X
5971                         || sp.Y < p_blocks_min.Z
5972                         || sp.Y > p_blocks_max.Z)
5973                                 continue;
5974                 }
5975
5976                 core::list< MapBlock * > sectorblocks;
5977                 sector->getBlocks(sectorblocks);
5978                 
5979                 /*
5980                         Draw blocks
5981                 */
5982
5983                 core::list< MapBlock * >::Iterator i;
5984                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5985                 {
5986                         MapBlock *block = *i;
5987
5988                         /*
5989                                 Compare block position to camera position, skip
5990                                 if not seen on display
5991                         */
5992                         
5993                         float range = 100000 * BS;
5994                         if(m_control.range_all == false)
5995                                 range = m_control.wanted_range * BS;
5996                         
5997                         float d = 0.0;
5998                         if(isBlockInSight(block->getPos(), camera_position,
5999                                         camera_direction, range, &d) == false)
6000                         {
6001                                 continue;
6002                         }
6003                         
6004                         // This is ugly
6005                         /*if(m_control.range_all == false &&
6006                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
6007                                 continue;*/
6008
6009 #if 1
6010                         /*
6011                                 Update expired mesh (used for day/night change)
6012                         */
6013
6014                         bool mesh_expired = false;
6015                         
6016                         {
6017                                 JMutexAutoLock lock(block->mesh_mutex);
6018
6019                                 mesh_expired = block->getMeshExpired();
6020
6021                                 // Mesh has not been expired and there is no mesh:
6022                                 // block has no content
6023                                 if(block->mesh == NULL && mesh_expired == false)
6024                                         continue;
6025                         }
6026
6027                         f32 faraway = BS*50;
6028                         //f32 faraway = m_control.wanted_range * BS;
6029                         
6030                         /*
6031                                 This has to be done with the mesh_mutex unlocked
6032                         */
6033                         // Pretty random but this should work somewhat nicely
6034                         if(mesh_expired && (
6035                                         (mesh_update_count < 3
6036                                                 && (d < faraway || mesh_update_count < 2)
6037                                         )
6038                                         || 
6039                                         (m_control.range_all && mesh_update_count < 20)
6040                                 )
6041                         )
6042                         /*if(mesh_expired && mesh_update_count < 6
6043                                         && (d < faraway || mesh_update_count < 3))*/
6044                         {
6045                                 mesh_update_count++;
6046
6047                                 // Mesh has been expired: generate new mesh
6048                                 //block->updateMeshes(daynight_i);
6049                                 block->updateMesh(daynight_ratio);
6050
6051                                 mesh_expired = false;
6052                         }
6053                         
6054                         /*
6055                                 Don't draw an expired mesh that is far away
6056                         */
6057                         /*if(mesh_expired && d >= faraway)
6058                         //if(mesh_expired)
6059                         {
6060                                 // Instead, delete it
6061                                 JMutexAutoLock lock(block->mesh_mutex);
6062                                 if(block->mesh)
6063                                 {
6064                                         block->mesh->drop();
6065                                         block->mesh = NULL;
6066                                 }
6067                                 // And continue to next block
6068                                 continue;
6069                         }*/
6070 #endif
6071                         /*
6072                                 Draw the faces of the block
6073                         */
6074                         {
6075                                 JMutexAutoLock lock(block->mesh_mutex);
6076
6077                                 scene::SMesh *mesh = block->mesh;
6078
6079                                 if(mesh == NULL)
6080                                         continue;
6081                                 
6082                                 blocks_would_have_drawn++;
6083                                 if(blocks_drawn >= m_control.wanted_max_blocks
6084                                                 && m_control.range_all == false
6085                                                 && d > m_control.wanted_min_range * BS)
6086                                         continue;
6087                                 blocks_drawn++;
6088
6089                                 u32 c = mesh->getMeshBufferCount();
6090
6091                                 for(u32 i=0; i<c; i++)
6092                                 {
6093                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
6094                                         const video::SMaterial& material = buf->getMaterial();
6095                                         video::IMaterialRenderer* rnd =
6096                                                         driver->getMaterialRenderer(material.MaterialType);
6097                                         bool transparent = (rnd && rnd->isTransparent());
6098                                         // Render transparent on transparent pass and likewise.
6099                                         if(transparent == is_transparent_pass)
6100                                         {
6101                                                 /*
6102                                                         This *shouldn't* hurt too much because Irrlicht
6103                                                         doesn't change opengl textures if the old
6104                                                         material is set again.
6105                                                 */
6106                                                 driver->setMaterial(buf->getMaterial());
6107                                                 driver->drawMeshBuffer(buf);
6108                                                 vertex_count += buf->getVertexCount();
6109                                         }
6110                                 }
6111                         }
6112                 } // foreach sectorblocks
6113         }
6114         
6115         m_control.blocks_drawn = blocks_drawn;
6116         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
6117
6118         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
6119                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
6120 }
6121
6122 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
6123                 core::map<v3s16, MapBlock*> *affected_blocks)
6124 {
6125         bool changed = false;
6126         /*
6127                 Add it to all blocks touching it
6128         */
6129         v3s16 dirs[7] = {
6130                 v3s16(0,0,0), // this
6131                 v3s16(0,0,1), // back
6132                 v3s16(0,1,0), // top
6133                 v3s16(1,0,0), // right
6134                 v3s16(0,0,-1), // front
6135                 v3s16(0,-1,0), // bottom
6136                 v3s16(-1,0,0), // left
6137         };
6138         for(u16 i=0; i<7; i++)
6139         {
6140                 v3s16 p2 = p + dirs[i];
6141                 // Block position of neighbor (or requested) node
6142                 v3s16 blockpos = getNodeBlockPos(p2);
6143                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
6144                 if(blockref == NULL)
6145                         continue;
6146                 // Relative position of requested node
6147                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
6148                 if(blockref->setTempMod(relpos, mod))
6149                 {
6150                         changed = true;
6151                 }
6152         }
6153         if(changed && affected_blocks!=NULL)
6154         {
6155                 for(u16 i=0; i<7; i++)
6156                 {
6157                         v3s16 p2 = p + dirs[i];
6158                         // Block position of neighbor (or requested) node
6159                         v3s16 blockpos = getNodeBlockPos(p2);
6160                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
6161                         if(blockref == NULL)
6162                                 continue;
6163                         affected_blocks->insert(blockpos, blockref);
6164                 }
6165         }
6166         return changed;
6167 }
6168
6169 bool ClientMap::clearTempMod(v3s16 p,
6170                 core::map<v3s16, MapBlock*> *affected_blocks)
6171 {
6172         bool changed = false;
6173         v3s16 dirs[7] = {
6174                 v3s16(0,0,0), // this
6175                 v3s16(0,0,1), // back
6176                 v3s16(0,1,0), // top
6177                 v3s16(1,0,0), // right
6178                 v3s16(0,0,-1), // front
6179                 v3s16(0,-1,0), // bottom
6180                 v3s16(-1,0,0), // left
6181         };
6182         for(u16 i=0; i<7; i++)
6183         {
6184                 v3s16 p2 = p + dirs[i];
6185                 // Block position of neighbor (or requested) node
6186                 v3s16 blockpos = getNodeBlockPos(p2);
6187                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
6188                 if(blockref == NULL)
6189                         continue;
6190                 // Relative position of requested node
6191                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
6192                 if(blockref->clearTempMod(relpos))
6193                 {
6194                         changed = true;
6195                 }
6196         }
6197         if(changed && affected_blocks!=NULL)
6198         {
6199                 for(u16 i=0; i<7; i++)
6200                 {
6201                         v3s16 p2 = p + dirs[i];
6202                         // Block position of neighbor (or requested) node
6203                         v3s16 blockpos = getNodeBlockPos(p2);
6204                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
6205                         if(blockref == NULL)
6206                                 continue;
6207                         affected_blocks->insert(blockpos, blockref);
6208                 }
6209         }
6210         return changed;
6211 }
6212
6213 void ClientMap::expireMeshes(bool only_daynight_diffed)
6214 {
6215         TimeTaker timer("expireMeshes()");
6216
6217         core::map<v2s16, MapSector*>::Iterator si;
6218         si = m_sectors.getIterator();
6219         for(; si.atEnd() == false; si++)
6220         {
6221                 MapSector *sector = si.getNode()->getValue();
6222
6223                 core::list< MapBlock * > sectorblocks;
6224                 sector->getBlocks(sectorblocks);
6225                 
6226                 core::list< MapBlock * >::Iterator i;
6227                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
6228                 {
6229                         MapBlock *block = *i;
6230
6231                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
6232                         {
6233                                 continue;
6234                         }
6235                         
6236                         {
6237                                 JMutexAutoLock lock(block->mesh_mutex);
6238                                 if(block->mesh != NULL)
6239                                 {
6240                                         /*block->mesh->drop();
6241                                         block->mesh = NULL;*/
6242                                         block->setMeshExpired(true);
6243                                 }
6244                         }
6245                 }
6246         }
6247 }
6248
6249 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
6250 {
6251         assert(mapType() == MAPTYPE_CLIENT);
6252
6253         try{
6254                 v3s16 p = blockpos + v3s16(0,0,0);
6255                 MapBlock *b = getBlockNoCreate(p);
6256                 b->updateMesh(daynight_ratio);
6257         }
6258         catch(InvalidPositionException &e){}
6259         // Leading edge
6260         try{
6261                 v3s16 p = blockpos + v3s16(-1,0,0);
6262                 MapBlock *b = getBlockNoCreate(p);
6263                 b->updateMesh(daynight_ratio);
6264         }
6265         catch(InvalidPositionException &e){}
6266         try{
6267                 v3s16 p = blockpos + v3s16(0,-1,0);
6268                 MapBlock *b = getBlockNoCreate(p);
6269                 b->updateMesh(daynight_ratio);
6270         }
6271         catch(InvalidPositionException &e){}
6272         try{
6273                 v3s16 p = blockpos + v3s16(0,0,-1);
6274                 MapBlock *b = getBlockNoCreate(p);
6275                 b->updateMesh(daynight_ratio);
6276         }
6277         catch(InvalidPositionException &e){}
6278         /*// Trailing edge
6279         try{
6280                 v3s16 p = blockpos + v3s16(1,0,0);
6281                 MapBlock *b = getBlockNoCreate(p);
6282                 b->updateMesh(daynight_ratio);
6283         }
6284         catch(InvalidPositionException &e){}
6285         try{
6286                 v3s16 p = blockpos + v3s16(0,1,0);
6287                 MapBlock *b = getBlockNoCreate(p);
6288                 b->updateMesh(daynight_ratio);
6289         }
6290         catch(InvalidPositionException &e){}
6291         try{
6292                 v3s16 p = blockpos + v3s16(0,0,1);
6293                 MapBlock *b = getBlockNoCreate(p);
6294                 b->updateMesh(daynight_ratio);
6295         }
6296         catch(InvalidPositionException &e){}*/
6297 }
6298
6299 void ClientMap::PrintInfo(std::ostream &out)
6300 {
6301         out<<"ClientMap: ";
6302 }
6303
6304 #endif // !SERVER
6305
6306 /*
6307         MapVoxelManipulator
6308 */
6309
6310 MapVoxelManipulator::MapVoxelManipulator(Map *map)
6311 {
6312         m_map = map;
6313 }
6314
6315 MapVoxelManipulator::~MapVoxelManipulator()
6316 {
6317         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
6318                         <<std::endl;*/
6319 }
6320
6321 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
6322 {
6323         TimeTaker timer1("emerge", &emerge_time);
6324
6325         // Units of these are MapBlocks
6326         v3s16 p_min = getNodeBlockPos(a.MinEdge);
6327         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
6328
6329         VoxelArea block_area_nodes
6330                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6331
6332         addArea(block_area_nodes);
6333
6334         for(s32 z=p_min.Z; z<=p_max.Z; z++)
6335         for(s32 y=p_min.Y; y<=p_max.Y; y++)
6336         for(s32 x=p_min.X; x<=p_max.X; x++)
6337         {
6338                 v3s16 p(x,y,z);
6339                 core::map<v3s16, bool>::Node *n;
6340                 n = m_loaded_blocks.find(p);
6341                 if(n != NULL)
6342                         continue;
6343                 
6344                 bool block_data_inexistent = false;
6345                 try
6346                 {
6347                         TimeTaker timer1("emerge load", &emerge_load_time);
6348
6349                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
6350                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
6351                                         <<" wanted area: ";
6352                         a.print(dstream);
6353                         dstream<<std::endl;*/
6354                         
6355                         MapBlock *block = m_map->getBlockNoCreate(p);
6356                         if(block->isDummy())
6357                                 block_data_inexistent = true;
6358                         else
6359                                 block->copyTo(*this);
6360                 }
6361                 catch(InvalidPositionException &e)
6362                 {
6363                         block_data_inexistent = true;
6364                 }
6365
6366                 if(block_data_inexistent)
6367                 {
6368                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6369                         // Fill with VOXELFLAG_INEXISTENT
6370                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
6371                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
6372                         {
6373                                 s32 i = m_area.index(a.MinEdge.X,y,z);
6374                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
6375                         }
6376                 }
6377
6378                 m_loaded_blocks.insert(p, !block_data_inexistent);
6379         }
6380
6381         //dstream<<"emerge done"<<std::endl;
6382 }
6383
6384 /*
6385         SUGG: Add an option to only update eg. water and air nodes.
6386               This will make it interfere less with important stuff if
6387                   run on background.
6388 */
6389 void MapVoxelManipulator::blitBack
6390                 (core::map<v3s16, MapBlock*> & modified_blocks)
6391 {
6392         if(m_area.getExtent() == v3s16(0,0,0))
6393                 return;
6394         
6395         //TimeTaker timer1("blitBack");
6396
6397         /*dstream<<"blitBack(): m_loaded_blocks.size()="
6398                         <<m_loaded_blocks.size()<<std::endl;*/
6399         
6400         /*
6401                 Initialize block cache
6402         */
6403         v3s16 blockpos_last;
6404         MapBlock *block = NULL;
6405         bool block_checked_in_modified = false;
6406
6407         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
6408         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
6409         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
6410         {
6411                 v3s16 p(x,y,z);
6412
6413                 u8 f = m_flags[m_area.index(p)];
6414                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
6415                         continue;
6416
6417                 MapNode &n = m_data[m_area.index(p)];
6418                         
6419                 v3s16 blockpos = getNodeBlockPos(p);
6420                 
6421                 try
6422                 {
6423                         // Get block
6424                         if(block == NULL || blockpos != blockpos_last){
6425                                 block = m_map->getBlockNoCreate(blockpos);
6426                                 blockpos_last = blockpos;
6427                                 block_checked_in_modified = false;
6428                         }
6429                         
6430                         // Calculate relative position in block
6431                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
6432
6433                         // Don't continue if nothing has changed here
6434                         if(block->getNode(relpos) == n)
6435                                 continue;
6436
6437                         //m_map->setNode(m_area.MinEdge + p, n);
6438                         block->setNode(relpos, n);
6439                         
6440                         /*
6441                                 Make sure block is in modified_blocks
6442                         */
6443                         if(block_checked_in_modified == false)
6444                         {
6445                                 modified_blocks[blockpos] = block;
6446                                 block_checked_in_modified = true;
6447                         }
6448                 }
6449                 catch(InvalidPositionException &e)
6450                 {
6451                 }
6452         }
6453 }
6454
6455 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
6456                 MapVoxelManipulator(map)
6457 {
6458 }
6459
6460 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
6461 {
6462 }
6463
6464 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
6465 {
6466         // Just create the area so that it can be pointed to
6467         VoxelManipulator::emerge(a, caller_id);
6468 }
6469
6470 void ManualMapVoxelManipulator::initialEmerge(
6471                 v3s16 blockpos_min, v3s16 blockpos_max)
6472 {
6473         TimeTaker timer1("initialEmerge", &emerge_time);
6474
6475         // Units of these are MapBlocks
6476         v3s16 p_min = blockpos_min;
6477         v3s16 p_max = blockpos_max;
6478
6479         VoxelArea block_area_nodes
6480                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6481         
6482         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
6483         if(size_MB >= 1)
6484         {
6485                 dstream<<"initialEmerge: area: ";
6486                 block_area_nodes.print(dstream);
6487                 dstream<<" ("<<size_MB<<"MB)";
6488                 dstream<<std::endl;
6489         }
6490
6491         addArea(block_area_nodes);
6492
6493         for(s32 z=p_min.Z; z<=p_max.Z; z++)
6494         for(s32 y=p_min.Y; y<=p_max.Y; y++)
6495         for(s32 x=p_min.X; x<=p_max.X; x++)
6496         {
6497                 v3s16 p(x,y,z);
6498                 core::map<v3s16, bool>::Node *n;
6499                 n = m_loaded_blocks.find(p);
6500                 if(n != NULL)
6501                         continue;
6502                 
6503                 bool block_data_inexistent = false;
6504                 try
6505                 {
6506                         TimeTaker timer1("emerge load", &emerge_load_time);
6507
6508                         MapBlock *block = m_map->getBlockNoCreate(p);
6509                         if(block->isDummy())
6510                                 block_data_inexistent = true;
6511                         else
6512                                 block->copyTo(*this);
6513                 }
6514                 catch(InvalidPositionException &e)
6515                 {
6516                         block_data_inexistent = true;
6517                 }
6518
6519                 if(block_data_inexistent)
6520                 {
6521                         /*
6522                                 Mark area inexistent
6523                         */
6524                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6525                         // Fill with VOXELFLAG_INEXISTENT
6526                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
6527                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
6528                         {
6529                                 s32 i = m_area.index(a.MinEdge.X,y,z);
6530                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
6531                         }
6532                 }
6533
6534                 m_loaded_blocks.insert(p, !block_data_inexistent);
6535         }
6536 }
6537
6538 void ManualMapVoxelManipulator::blitBackAll(
6539                 core::map<v3s16, MapBlock*> * modified_blocks)
6540 {
6541         if(m_area.getExtent() == v3s16(0,0,0))
6542                 return;
6543         
6544         /*
6545                 Copy data of all blocks
6546         */
6547         for(core::map<v3s16, bool>::Iterator
6548                         i = m_loaded_blocks.getIterator();
6549                         i.atEnd() == false; i++)
6550         {
6551                 bool existed = i.getNode()->getValue();
6552                 if(existed == false)
6553                         continue;
6554                 v3s16 p = i.getNode()->getKey();
6555                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
6556                 if(block == NULL)
6557                 {
6558                         dstream<<"WARNING: "<<__FUNCTION_NAME
6559                                         <<": got NULL block "
6560                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
6561                                         <<std::endl;
6562                         continue;
6563                 }
6564
6565                 block->copyFrom(*this);
6566
6567                 if(modified_blocks)
6568                         modified_blocks->insert(p, block);
6569         }
6570 }
6571
6572 //END