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