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