651bece4f35f191908da0460edb0efc52552d6de
[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         // TODO: Save to and load from a file
1714         m_seed = (((u64)(myrand()%0xffff)<<0)
1715                         + ((u64)(myrand()%0xffff)<<16)
1716                         + ((u64)(myrand()%0xffff)<<32)
1717                         + ((u64)(myrand()%0xffff)<<48));
1718
1719         /*
1720                 Experimental and debug stuff
1721         */
1722         
1723         {
1724         }
1725         
1726         /*
1727                 Try to load map; if not found, create a new one.
1728         */
1729
1730         m_savedir = savedir;
1731         m_map_saving_enabled = false;
1732         
1733         try
1734         {
1735                 // If directory exists, check contents and load if possible
1736                 if(fs::PathExists(m_savedir))
1737                 {
1738                         // If directory is empty, it is safe to save into it.
1739                         if(fs::GetDirListing(m_savedir).size() == 0)
1740                         {
1741                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1742                                                 <<std::endl;
1743                                 m_map_saving_enabled = true;
1744                         }
1745                         else
1746                         {
1747                                 // Load map metadata (seed)
1748                                 loadMapMeta();
1749                                 
1750                                 /*// Load sector (0,0) and throw and exception on fail
1751                                 if(loadSectorFull(v2s16(0,0)) == false)
1752                                         throw LoadError("Failed to load sector (0,0)");*/
1753
1754                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1755                                                 "metadata and sector (0,0) from "<<savedir<<
1756                                                 ", assuming valid save directory."
1757                                                 <<std::endl;*/
1758
1759                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1760                                                 <<"and chunk metadata from "<<savedir
1761                                                 <<", assuming valid save directory."
1762                                                 <<std::endl;
1763
1764                                 m_map_saving_enabled = true;
1765                                 // Map loaded, not creating new one
1766                                 return;
1767                         }
1768                 }
1769                 // If directory doesn't exist, it is safe to save to it
1770                 else{
1771                         m_map_saving_enabled = true;
1772                 }
1773         }
1774         catch(std::exception &e)
1775         {
1776                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1777                                 <<", exception: "<<e.what()<<std::endl;
1778                 dstream<<"Please remove the map or fix it."<<std::endl;
1779                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1780         }
1781
1782         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1783         
1784         // Create zero sector
1785         emergeSector(v2s16(0,0));
1786
1787         // Initially write whole map
1788         save(false);
1789 }
1790
1791 ServerMap::~ServerMap()
1792 {
1793         try
1794         {
1795                 if(m_map_saving_enabled)
1796                 {
1797                         //save(false);
1798                         // Save only changed parts
1799                         save(true);
1800                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1801                 }
1802                 else
1803                 {
1804                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1805                 }
1806         }
1807         catch(std::exception &e)
1808         {
1809                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1810                                 <<", exception: "<<e.what()<<std::endl;
1811         }
1812 }
1813
1814 /*
1815         Some helper functions for the map generator
1816 */
1817
1818 s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
1819 {
1820         v3s16 em = vmanip.m_area.getExtent();
1821         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1822         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1823         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1824         s16 y;
1825         for(y=y_nodes_max; y>=y_nodes_min; y--)
1826         {
1827                 MapNode &n = vmanip.m_data[i];
1828                 if(content_walkable(n.d))
1829                         break;
1830                         
1831                 vmanip.m_area.add_y(em, i, -1);
1832         }
1833         if(y >= y_nodes_min)
1834                 return y;
1835         else
1836                 return y_nodes_min;
1837 }
1838
1839 s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
1840 {
1841         v3s16 em = vmanip.m_area.getExtent();
1842         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1843         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1844         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1845         s16 y;
1846         for(y=y_nodes_max; y>=y_nodes_min; y--)
1847         {
1848                 MapNode &n = vmanip.m_data[i];
1849                 if(content_walkable(n.d)
1850                                 && n.d != CONTENT_TREE
1851                                 && n.d != CONTENT_LEAVES)
1852                         break;
1853                         
1854                 vmanip.m_area.add_y(em, i, -1);
1855         }
1856         if(y >= y_nodes_min)
1857                 return y;
1858         else
1859                 return y_nodes_min;
1860 }
1861
1862 void make_tree(VoxelManipulator &vmanip, v3s16 p0)
1863 {
1864         MapNode treenode(CONTENT_TREE);
1865         MapNode leavesnode(CONTENT_LEAVES);
1866         leavesnode.setLight(LIGHTBANK_DAY, LIGHT_MAX-1);
1867
1868         vmanip.emerge(VoxelArea(p0-v3s16(2,0,2),p0+v3s16(2,7+2,2)));
1869
1870         s16 trunk_h = myrand_range(4, 7);
1871         v3s16 p1 = p0;
1872         for(s16 ii=0; ii<trunk_h; ii++)
1873         {
1874                 if(vmanip.m_area.contains(p1))
1875                         vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
1876                 p1.Y++;
1877         }
1878         
1879         // p1 is now the last piece of the trunk
1880         p1.Y -= 1;
1881
1882         VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
1883         //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
1884         Buffer<u8> leaves_d(leaves_a.getVolume());
1885         for(s32 i=0; i<leaves_a.getVolume(); i++)
1886                 leaves_d[i] = 0;
1887         
1888         // Force leaves at near the end of the trunk
1889         {
1890                 s16 d = 1;
1891                 for(s16 z=-d; z<=d; z++)
1892                 for(s16 y=-d; y<=d; y++)
1893                 for(s16 x=-d; x<=d; x++)
1894                 {
1895                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
1896                 }
1897         }
1898         
1899         // Add leaves randomly
1900         for(u32 iii=0; iii<7; iii++)
1901         {
1902                 s16 d = 1;
1903
1904                 v3s16 p(
1905                         myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
1906                         myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
1907                         myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
1908                 );
1909                 
1910                 for(s16 z=0; z<=d; z++)
1911                 for(s16 y=0; y<=d; y++)
1912                 for(s16 x=0; x<=d; x++)
1913                 {
1914                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
1915                 }
1916         }
1917         
1918         // Blit leaves to vmanip
1919         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
1920         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
1921         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
1922         {
1923                 v3s16 p(x,y,z);
1924                 p += p1;
1925                 if(vmanip.m_area.contains(p) == false)
1926                         continue;
1927                 u32 vi = vmanip.m_area.index(p);
1928                 if(vmanip.m_data[vi].d != CONTENT_AIR)
1929                         continue;
1930                 u32 i = leaves_a.index(x,y,z);
1931                 if(leaves_d[i] == 1)
1932                         vmanip.m_data[vi] = leavesnode;
1933         }
1934 }
1935
1936 /*
1937         Noise functions. Make sure seed is mangled differently in each one.
1938 */
1939
1940 // Amount of trees per area in nodes
1941 double tree_amount_2d(u64 seed, v2s16 p)
1942 {
1943         double noise = noise2d_perlin(
1944                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1945                         seed+2, 5, 0.7);
1946         double zeroval = -0.5;
1947         if(noise < zeroval)
1948                 return 0;
1949         else
1950                 return 0.03 * (noise-zeroval) / (1.0-zeroval);
1951 }
1952
1953 #define AVERAGE_MUD_AMOUNT 4.0
1954
1955 double get_mud_amount(u64 seed, v2f p)
1956 {
1957         return ((float)AVERAGE_MUD_AMOUNT + 2.5 * noise2d_perlin(
1958                         0.5+p.X/200, 0.5+p.Y/200,
1959                         seed+1, 5, 0.65));
1960 }
1961
1962 bool get_have_sand_coast(u64 seed, v2f p)
1963 {
1964         double sandnoise = noise2d_perlin(
1965                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1966                         seed+59420, 3, 0.50);
1967         return (sandnoise > -0.25);
1968 }
1969
1970 bool get_have_sand_ground(u64 seed, v2f p)
1971 {
1972         double sandnoise = noise2d_perlin(
1973                         0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1974                         seed+54290232, 6, 0.65);
1975         return (sandnoise > 1.0);
1976 }
1977
1978 // -1->0, 0->1, 1->0
1979 double contour(double v)
1980 {
1981         v = fabs(v);
1982         if(v >= 1.0)
1983                 return 0.0;
1984         return (1.0-v);
1985 }
1986
1987 // -1->0, -r->1, 0->1, r->1, 1->0
1988 double contour_flat_top(double v, double r)
1989 {
1990         v = fabs(v);
1991         if(v >= 1.0)
1992                 return 0.0;
1993         double rmax = 0.999;
1994         if(r >= rmax)
1995                 r = rmax;
1996         if(v <= r)
1997                 return 1.0;
1998         v -= r;
1999         return ((1.0-r)-v) / (1.0-r);
2000         //return easeCurve(((1.0-r)-v) / (1.0-r));
2001 }
2002
2003 double base_rock_level_2d(u64 seed, v2f p)
2004 {
2005         // The ground level (return value)
2006         double h = WATER_LEVEL-1.5;
2007         
2008         // Raises from 0 when parameter is -1...1
2009         /*double m2 = contour_flat_top(-0.8 + 2.0 * noise2d_perlin(
2010                         0.0+(float)p.X/1500., 0.0+(float)p.Y/1500.,
2011                         (seed>>32)+34758, 5, 0.55), 0.10);*/
2012         /*double m2 = 1.0;
2013         if(m2 > 0.0001)
2014         {
2015                 // HUGE mountains
2016                 double m1 = 200.0 + 300.0 * noise2d_perlin(
2017                                 0.0+(float)p.X/1000., 0.0+(float)p.Y/1000.,
2018                                 (seed>>32)+98525, 8, 0.5);
2019                 h += m1 * m2;
2020                 //h += 30 * m2;
2021         }*/
2022
2023         /*double tm2 = contour_flat_top(-1.0 + 3.0 * noise2d_perlin(
2024                         0.0+(float)p.X/300., 0.0+(float)p.Y/300.,
2025                         (seed>>32)+78593, 5, 0.55), 0.15);
2026         h += 30 * tm2;*/
2027
2028 #if 0
2029         {
2030                 // Large mountains
2031                 double m3 = 100.0 - 600.0 * noise2d_perlin_abs(
2032                                 0.324+(float)p.X/2000., 0.423+(float)p.Y/2000.,
2033                                 (seed>>32)+985251, 9, 0.55);
2034                 if(m3 > h)
2035                         h = m3;
2036         }
2037 #endif
2038
2039 #if 0
2040         {
2041                 // More mountain ranges
2042                 double d = 100;
2043                 double a1 = d*2.0 - d*7 * noise2d_perlin_abs(
2044                                 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000.,
2045                                 seed+850342, 7, 0.55);
2046                 /*if(a1 > d)
2047                         a1 = d + sqrt(a1-d);*/
2048                 a1 = (1.0 - exp(-a1/d))*d;
2049                 /*if(a1 > h)
2050                         h = a1;*/
2051                 if(a1 > 0)
2052                         h += a1;
2053         }
2054 #endif
2055
2056 #if 0
2057         {
2058                 // More mountain ranges
2059                 double d = 60;
2060                 double a1 = d*2.0 - d*7 * noise2d_perlin_abs(
2061                                 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000.,
2062                                 seed+850342, 7, 0.55);
2063                 /*if(a1 > d)
2064                         a1 = d + sqrt(a1-d);*/
2065                 a1 = (1.0 - exp(-a1/d))*d;
2066                 /*if(a1 > h)
2067                         h = a1;*/
2068                 if(a1 > 0)
2069                         h += a1;
2070         }
2071 #endif
2072
2073 #if 0
2074         {
2075                 // Very steep mountain ranges
2076                 double d = 120;
2077                 double a1 = d*2 - d*6.5 * noise2d_perlin_abs(
2078                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2079                                 seed+850342, 6, 0.6);
2080                 /*if(a1 > d)
2081                         a1 = d + sqrt(a1-d);*/
2082                 a1 = (1.0 - exp(-a1/d))*d;
2083                 /*if(a1 > h)
2084                         h = a1;*/
2085                 if(a1 > 0)
2086                         h += a1;
2087                 /*double a = noise2d_perlin_abs(
2088                                 0.94+(float)p.X/2000., 0.26+(float)p.Y/2000.,
2089                                 (seed>>32)+65012102, 8, 0.50);
2090                 double m4 = 100.0 - 400.0 * a;
2091                 if(m4 > h)
2092                         h = m4;*/
2093         }
2094 #endif
2095         
2096         /*
2097                 The stuff before this comment is usually not used.
2098                 The stuff after this comment is usually used.
2099         */
2100
2101 #if 1
2102         {
2103                 // Mountains
2104                 double m4 = 1.0 - 3.0 * noise2d_perlin_abs(
2105                                 0.324+(float)p.X/1000., 0.423+(float)p.Y/1000.,
2106                                 (seed>>32)+65012102, 8, 0.57);
2107                 m4 *= 120;
2108                 if(m4 > h)
2109                         h = m4;
2110         }
2111 #endif
2112
2113 #if 1
2114         // Some kind of hill chains or something
2115         {
2116                 double a1 = 1.0 - 2.5 * noise2d_perlin_abs(
2117                                 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2118                                 seed+850342, 5, 0.6);
2119                 a1 *= 30;
2120                 double d = 15;
2121                 if(a1 > d)
2122                         a1 = d + sqrt(a1-d);
2123                 /*if(a1 > h)
2124                         h = a1;*/
2125                 if(a1 > 0)
2126                         h += a1;
2127         }
2128 #endif
2129
2130 #if 1
2131         double base = -2. + 25. * noise2d_perlin(
2132                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2133                         (seed>>32)+653876, 7, 0.65);
2134 #else
2135         double base = 0;
2136 #endif
2137         
2138 #if 1
2139         /*
2140                 Combined with turbulence, this thing here is able to make very
2141                 awesome terrain, albeit rarely.
2142
2143                 This is also responsible for small islands.
2144         */
2145
2146         double higher = 40. * noise2d_perlin(
2147                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2148                         seed+39292, 6, 0.50);
2149         /*double higher = 50. * noise2d_perlin_abs(
2150                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2151                         seed+85039, 5, 0.63);*/
2152         //higher = 25;
2153
2154         if(higher > base)
2155         {
2156                 // Steepness factor of cliffs
2157                 double b = 1.0 + 1.0 * noise2d_perlin(
2158                                 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2159                                 seed-932, 6, 0.7);
2160                 b = rangelim(b, 0.0, 1000.0);
2161 #if 1
2162                 b = pow(b, 5);
2163                 b *= 16;
2164                 b = rangelim(b, 3.0, 1000.0);
2165                 //dstream<<"b="<<b<<std::endl;
2166                 //double b = 20;
2167                 // Offset to more low
2168                 //double a_off = -0.30;
2169                 double a_off = -0.20;
2170                 // High/low selector
2171                 double a = (double)0.5 + b * (a_off + noise2d_perlin(
2172                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2173                                 seed-359, 7, 0.70));
2174 #endif
2175 #if 0
2176                 /*b = pow(b, 5);
2177                 b *= 2;
2178                 b = rangelim(b, 3.0, 20.0);*/
2179                 //b = 10.0;
2180                 double a = -1.5 + 5.0 * (noise2d_perlin_abs(
2181                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2182                                 seed-359, 6, 0.6));
2183                 a *= 3.0;
2184                 /*double a = 5.0 * (noise2d_perlin(
2185                                 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2186                                 seed-359, 5, 0.6));*/
2187                 //a = contour_flat_top(a, 0.2);
2188 #endif
2189                 // Limit
2190                 a = rangelim(a, 0.0, 1.0);
2191                 a = easeCurve(a);
2192
2193                 //dstream<<"a="<<a<<std::endl;
2194
2195                 /*double h2 = higher * a;
2196                 if(h2 > h)
2197                         h = h2;*/
2198                 
2199                 h += base*(1.0-a) + higher*a;
2200         }
2201         else
2202         {
2203                 h += base;
2204         }
2205 #else
2206         h += base;
2207 #endif
2208
2209         return h;
2210 }
2211
2212 double base_rock_level_2d(u64 seed, v2s16 p)
2213 {
2214         return base_rock_level_2d(seed, v2f((float)p.X, (float)p.Y));
2215 }
2216
2217 double get_turbulence_factor_2d(u64 seed, v2f p)
2218 {
2219         double vv = -0.50 + 2.0 * noise2d_perlin(
2220                         0.5+p.X/100,
2221                         0.5+p.Y/100,
2222                         seed+85498783983, 4, 0.5);
2223         vv = rangelim(vv, 0.0, 1.0);
2224         return vv;
2225 }
2226
2227 #define TURBULENCE_BOTTOM_CUTOFF_Y (WATER_LEVEL-7)
2228
2229 double get_turbulence_factor_y(u64 seed, f32 y)
2230 {
2231         double d = 14;
2232         double min = TURBULENCE_BOTTOM_CUTOFF_Y;
2233         if(y < min)
2234                 return 0.0;
2235         else if(y < min + d)
2236                 return ((y-min)/d);
2237         return 1.0;
2238 }
2239
2240 v2f get_raw_turbulence(u64 seed, v3f p)
2241 {
2242         double f = 8;
2243
2244         double v1 = f * noise3d_perlin(
2245                         0.5+p.X/100,
2246                         0.5+p.Y/100,
2247                         0.5+p.Z/100,
2248                         seed+4045, 5, 0.65);
2249
2250         double v2 = f * noise3d_perlin(
2251                         0.5+p.X/100,
2252                         0.5+p.Y/100,
2253                         0.5+p.Z/100,
2254                         seed+9495, 5, 0.65);
2255         
2256         return v2f(v1, v2);
2257 }
2258
2259 // Shouldn't be used, provided for compatibility.
2260 v2f base_ground_turbulence(u64 seed, v3f p)
2261 {
2262         double tfxz = get_turbulence_factor_2d(seed, v2f(p.X,p.Z));
2263         double tfy = get_turbulence_factor_y(seed, p.Y);
2264         v2f t = get_raw_turbulence(seed, p);
2265         return t*tfxz*tfy;
2266 }
2267
2268 #if 0
2269 v2f base_ground_turbulence(u64 seed, v3f p)
2270 {
2271 #if 1
2272         double f = 8;
2273
2274 #if 1
2275         // Cut off at a minimum height
2276         {
2277                 double d = 15;
2278                 double min = WATER_LEVEL-5;
2279                 if(p.Y < min)
2280                         return v2f(0,0);
2281                 else if(p.Y < min + d)
2282                         f *= ((p.Y-min)/d);
2283         }
2284 #endif
2285
2286 #if 1
2287         double vv = 0.50 + 1.0 * noise3d_perlin(
2288                         0.5+p.X/250,
2289                         0.5+p.Y/250,
2290                         0.5+p.Z/250,
2291                         seed+1324381, 4, 0.5);
2292         double vve = rangelim(vv, 0.0, 1.0);
2293         /*double vv = 1.0 - 2.0 * noise3d_perlin_abs(
2294                         0.5+p.X/250,
2295                         0.5+p.Y/250,
2296                         0.5+p.Z/250,
2297                         seed+1324031, 4, 0.5);
2298         double vve = 1.0 - exp(-MYMAX(0, vv*2.0));*/
2299         //double vve = rangelim(vv, 0, 1.0);
2300         //dstream<<"vve="<<vve<<std::endl;
2301         
2302         /*// Limit turbulence near water level
2303         double a = contour((p.Y-WATER_LEVEL)/10.0);
2304         vve = (1.-a) * vve;*/
2305
2306         // Increase turbulence in elevated heights
2307         double ah = WATER_LEVEL + 30;
2308         if(p.Y > ah)
2309         {
2310                 vve *= p.Y/ah;
2311         }
2312 #else
2313         double vve = 1;
2314 #endif
2315
2316         double v1 = f * noise3d_perlin(
2317                         0.5+p.X/100,
2318                         0.5+p.Y/100,
2319                         0.5+p.Z/100,
2320                         seed+4045, 5, 0.65);
2321
2322         double v2 = f * noise3d_perlin(
2323                         0.5+p.X/100,
2324                         0.5+p.Y/100,
2325                         0.5+p.Z/100,
2326                         seed+9495, 5, 0.65);
2327         
2328         return v2f(v1*vve, v2*vve);
2329 #else
2330         return v2f(0,0);
2331 #endif
2332 }
2333 #endif
2334
2335 bool is_carved(u64 seed, v3f p)
2336 {
2337 #if 1
2338         double v1 = noise3d_perlin_abs(
2339                         0.5+p.X/200,
2340                         0.5+p.Y/200,
2341                         0.5+p.Z/200,
2342                         seed+657890854, 5, 0.7);
2343         
2344         if(v1 > 1.45)
2345                 return true;
2346 #endif
2347
2348         double f = 10.0;
2349         double y_div = 1.0;
2350
2351         double v4 = contour(f*noise3d_perlin(
2352                         0.5+p.X/200,
2353                         0.5+p.Y/200*y_div,
2354                         0.5+p.Z/200,
2355                         seed+87592, 5, 0.7));
2356         // Tilted 90 degrees
2357         double v5 = contour(f*noise3d_perlin(
2358                         0.5+p.X/200,
2359                         0.5+p.Z/200,
2360                         0.5+p.Y/200*y_div,
2361                         seed+98594, 5, 0.7));
2362         
2363         double v45 = v4*v5;
2364         if(v45 > 2.5/f)
2365                 return true;
2366         
2367         return false;
2368 }
2369
2370 bool is_underground_mud(u64 seed, v3f p)
2371 {
2372         double v1 = noise3d_perlin_abs(
2373                         0.5+p.X/50,
2374                         0.5+p.Y/50,
2375                         0.5+p.Z/50,
2376                         seed+83401, 5, 0.75);
2377         return (v1 > 1.3);
2378 }
2379         
2380 /*
2381         if depth_guess!=NULL, it is set to a guessed value of how deep
2382         underground the position is.
2383 */
2384 bool is_base_ground(u64 seed, v3f p, double *depth_guess=NULL)
2385 {
2386 #if 0
2387         // This is used for testing the output of the cave function
2388         {
2389                 if(depth_guess)
2390                         *depth_guess = 10;
2391                 if(p.Y > 50)
2392                         return false;
2393                 return is_carved(seed, p);
2394         }
2395 #endif
2396 #if 0
2397         // This is used for testing the output of the underground mud function
2398         {
2399                 if(depth_guess)
2400                         *depth_guess = 10;
2401                 if(p.Y > 50)
2402                         return false;
2403                 return is_underground_mud(seed, p);
2404         }
2405 #endif
2406
2407         bool is_ground = true;
2408
2409 #if 1
2410         if(is_carved(seed, p))
2411                 is_ground = false;
2412 #endif
2413         
2414         if(depth_guess || is_ground == true)
2415         {
2416                 v2f t = base_ground_turbulence(seed, p);
2417
2418                 double surface_y_f = base_rock_level_2d(seed, v2f(p.X+t.X, p.Z+t.Y));
2419
2420 #if 0
2421                 if(depth_guess)
2422                 {
2423                         // Find highest surface near current
2424                         v3f dirs[4] = {
2425                                 v3f(1,0,0),
2426                                 v3f(-1,0,0),
2427                                 v3f(0,0,1),
2428                                 v3f(0,0,-1)
2429                         };
2430                         double s2 = surface_y_f;
2431                         for(u32 i=0; i<4; i++)
2432                         {
2433                                 v3f dir = dirs[i];
2434                                 // Get turbulence at around there
2435                                 v2f t2 = base_ground_turbulence(seed, p+dir);
2436                                 // Get ground height
2437                                 v2f l = v2f(p.X+t2.X+dir.X, p.Z+t2.Y+dir.Z);
2438                                 double s = base_rock_level_2d(seed, l);
2439                                 if(s > s2)
2440                                         s2 = s;
2441                         }
2442                         *depth_guess = s2 - p.Y;
2443                 }
2444 #endif
2445 #if 1
2446                 if(depth_guess)
2447                 {
2448                         // Check a bit lower also, take highest surface
2449                         v2f t2 = base_ground_turbulence(seed, p + v3f(0,-2,0));
2450                         double s2 = base_rock_level_2d(seed, v2f(p.X+t2.X, p.Z+t2.Y));
2451                         if(s2 > surface_y_f)
2452                                 *depth_guess = s2 - p.Y;
2453                         else
2454                                 *depth_guess = surface_y_f - p.Y;
2455                 }
2456 #endif
2457 #if 0
2458                 if(depth_guess)
2459                         *depth_guess = surface_y_f - p.Y;
2460 #endif
2461
2462                 if(p.Y > surface_y_f)
2463                         is_ground = false;
2464         }
2465         
2466         /*if(depth_guess)
2467         {
2468                 // Guess surface point
2469                 v3f p2(p.X, surface_y_f, p.Z);
2470                 v2f t2 = base_ground_turbulence
2471                 double u1 = 
2472                 double s1 = base_rock_level_2d(seed, v2f(p.X+v1,p.Z+v2));
2473         }*/
2474
2475         return is_ground;
2476 }
2477
2478 #define VMANIP_FLAG_DUNGEON VOXELFLAG_CHECKED1
2479
2480 /*
2481         This is the main map generation method
2482 */
2483
2484 #if 0
2485 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
2486                 core::map<v3s16, MapBlock*> &changed_blocks,
2487                 bool force)
2488 {
2489         DSTACK(__FUNCTION_NAME);
2490
2491         // Shall be not used now
2492         //assert(0);
2493
2494 #if 0
2495
2496         /*
2497                 Don't generate if already fully generated
2498         */
2499         if(force == false)
2500         {
2501                 MapChunk *chunk = getChunk(chunkpos);
2502                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
2503                 {
2504                         dstream<<"generateChunkRaw(): Chunk "
2505                                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2506                                         <<" already generated"<<std::endl;
2507                         return chunk;
2508                 }
2509         }
2510
2511         dstream<<"generateChunkRaw(): Generating chunk "
2512                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2513                         <<std::endl;
2514         
2515         TimeTaker timer("generateChunkRaw()");
2516         
2517         // The distance how far into the neighbors the generator is allowed to go.
2518         s16 max_spread_amount_sectors = 2;
2519         assert(max_spread_amount_sectors <= m_chunksize);
2520         s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
2521
2522         // Minimum amount of space left on sides for mud to fall in
2523         //s16 min_mud_fall_space = 2;
2524         
2525         // Maximum diameter of stone obstacles in X and Z
2526         /*s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
2527         assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);*/
2528         
2529         s16 y_blocks_min = -4;
2530         s16 y_blocks_max = 3;
2531         s16 h_blocks = y_blocks_max - y_blocks_min + 1;
2532         s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
2533         s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
2534
2535         v2s16 sectorpos_base = chunk_to_sector(chunkpos);
2536         s16 sectorpos_base_size = m_chunksize;
2537
2538         /*v2s16 sectorpos_bigbase = chunk_to_sector(chunkpos - v2s16(1,1));
2539         s16 sectorpos_bigbase_size = m_chunksize * 3;*/
2540         v2s16 sectorpos_bigbase =
2541                         sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
2542         s16 sectorpos_bigbase_size =
2543                         sectorpos_base_size + 2 * max_spread_amount_sectors;
2544
2545         v3s16 bigarea_blocks_min(
2546                 sectorpos_bigbase.X,
2547                 y_blocks_min,
2548                 sectorpos_bigbase.Y
2549         );
2550
2551         v3s16 bigarea_blocks_max(
2552                 sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
2553                 y_blocks_max,
2554                 sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
2555         );
2556         
2557         // Relative values to control amount of stuff in one chunk
2558         /*u32 relative_area = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2559                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE;*/
2560         u32 relative_volume = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2561                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE
2562                         *(u32)h_blocks*MAP_BLOCKSIZE;
2563                 
2564         /*
2565                 The limiting edges of the lighting update, inclusive.
2566         */
2567         s16 lighting_min_d = 0-max_spread_amount;
2568         s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
2569
2570         /*
2571                 Create the whole area of this and the neighboring chunks
2572         */
2573         {
2574                 TimeTaker timer("generateChunkRaw() create area");
2575                 
2576                 for(s16 x=0; x<sectorpos_bigbase_size; x++)
2577                 for(s16 z=0; z<sectorpos_bigbase_size; z++)
2578                 {
2579                         v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
2580                         ServerMapSector *sector = createSector(sectorpos);
2581                         assert(sector);
2582
2583                         for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
2584                         {
2585                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
2586                                 MapBlock *block = createBlock(blockpos);
2587
2588                                 // Lighting won't be calculated
2589                                 //block->setLightingExpired(true);
2590                                 // Lighting will be calculated
2591                                 block->setLightingExpired(false);
2592
2593                                 /*
2594                                         Block gets sunlight if this is true.
2595
2596                                         This should be set to true when the top side of a block
2597                                         is completely exposed to the sky.
2598
2599                                         Actually this doesn't matter now because the
2600                                         initial lighting is done here.
2601                                 */
2602                                 block->setIsUnderground(y != y_blocks_max);
2603                         }
2604                 }
2605         }
2606         
2607         /*
2608                 Now we have a big empty area.
2609
2610                 Make a ManualMapVoxelManipulator that contains this and the
2611                 neighboring chunks
2612         */
2613
2614         ManualMapVoxelManipulator vmanip(this);
2615         // Add the area we just generated
2616         {
2617                 TimeTaker timer("generateChunkRaw() initialEmerge");
2618                 vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2619         }
2620
2621         // Clear all flags
2622         vmanip.clearFlag(0xff);
2623
2624         TimeTaker timer_generate("generateChunkRaw() generate");
2625
2626         // Maximum height of the stone surface and obstacles.
2627         // This is used to disable dungeon generation from going too high.
2628         s16 stone_surface_max_y = 0;
2629
2630         /*
2631                 Generate general ground level to full area
2632         */
2633         
2634         {
2635         // 22ms @cs=8
2636         TimeTaker timer1("ground level");
2637         dstream<<"Generating base ground..."<<std::endl;
2638
2639         for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
2640         for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
2641         {
2642                 // Node position
2643                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2644                 
2645                 /*
2646                         Skip if already generated
2647                 */
2648                 {
2649                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2650                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
2651                                 continue;
2652                 }
2653
2654                 v2f p2df(p2d.X, p2d.Y);
2655
2656                 {
2657                         // Use fast index incrementing
2658                         v3s16 em = vmanip.m_area.getExtent();
2659                         s16 min = y_nodes_min;
2660                         s16 max = y_nodes_max;
2661                         /*s16 min = -10;
2662                         s16 max = 20;*/
2663                         //float surface_y_f = base_rock_level_2d(m_seed, p2df);
2664                         u32 i = vmanip.m_area.index(v3s16(p2d.X, min, p2d.Y));
2665                         for(s16 y=min; y<=max; y++)
2666                         {
2667 #if 1
2668                                 bool is = is_base_ground(m_seed, v3f(p2df.X,y,p2df.Y));
2669                                 if(is)
2670                                         vmanip.m_data[i].d = CONTENT_STONE;
2671                                 else
2672                                         vmanip.m_data[i].d = CONTENT_AIR;
2673 #endif
2674 #if 0
2675                                 double v = noise3d_perlin(
2676                                                 0.5+(float)p2d.X/200,
2677                                                 0.5+(float)y/200,
2678                                                 0.5+(float)p2d.Y/200,
2679                                                 m_seed+293, 6, 0.55);
2680                                 if(v > 0.0)
2681                                         vmanip.m_data[i].d = CONTENT_STONE;
2682                                 else
2683                                         vmanip.m_data[i].d = CONTENT_AIR;
2684 #endif
2685 #if 0
2686                                 /*double v1 = 5 * noise3d_perlin(
2687                                                 0.5+(float)p2df.X/200,
2688                                                 0.5+(float)y/200,
2689                                                 0.5+(float)p2df.Y/200,
2690                                                 m_seed+293, 6, 0.55);
2691
2692                                 double v2 = 5 * noise3d_perlin(
2693                                                 0.5+(float)p2df.X/200,
2694                                                 0.5+(float)y/200,
2695                                                 0.5+(float)p2df.Y/200,
2696                                                 m_seed+293, 6, 0.55);*/
2697
2698                                 double v1 = 0;
2699                                 double v2 = 0;
2700
2701                                 float surface_y_f = base_rock_level_2d(m_seed, p2df+v2f(v1,v2));
2702
2703                                 if(y <= surface_y_f)
2704                                         vmanip.m_data[i].d = CONTENT_STONE;
2705                                 else
2706                                         vmanip.m_data[i].d = CONTENT_AIR;
2707 #endif
2708
2709                                 vmanip.m_area.add_y(em, i, 1);
2710                         }
2711                 }
2712
2713 #if 0
2714                 // Node position
2715                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2716
2717                 /*
2718                         Skip if already generated
2719                 */
2720                 {
2721                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2722                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
2723                                 continue;
2724                 }
2725
2726                 // Ground height at this point
2727                 float surface_y_f = 0.0;
2728
2729                 // Use perlin noise for ground height
2730                 surface_y_f = base_rock_level_2d(m_seed, p2d);
2731                 
2732                 /*// Experimental stuff
2733                 {
2734                         float a = highlands_level_2d(m_seed, p2d);
2735                         if(a > surface_y_f)
2736                                 surface_y_f = a;
2737                 }*/
2738
2739                 // Convert to integer
2740                 s16 surface_y = (s16)surface_y_f;
2741                 
2742                 // Log it
2743                 if(surface_y > stone_surface_max_y)
2744                         stone_surface_max_y = surface_y;
2745
2746                 /*
2747                         Fill ground with stone
2748                 */
2749                 {
2750                         // Use fast index incrementing
2751                         v3s16 em = vmanip.m_area.getExtent();
2752                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
2753                         for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++)
2754                         {
2755                                 vmanip.m_data[i].d = CONTENT_STONE;
2756
2757                                 vmanip.m_area.add_y(em, i, 1);
2758                         }
2759                 }
2760 #endif
2761         }
2762         
2763         }//timer1
2764
2765         /*
2766                 Randomize some parameters
2767         */
2768         
2769         s32 stone_obstacle_count = 0;
2770         /*s32 stone_obstacle_count =
2771                         rangelim((1.0+noise2d(m_seed+897,
2772                         sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2773         
2774         s16 stone_obstacle_max_height = 0;
2775         /*s16 stone_obstacle_max_height =
2776                         rangelim((1.0+noise2d(m_seed+5902,
2777                         sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2778
2779         /*
2780                 Loop this part, it will make stuff look older and newer nicely
2781         */
2782         u32 age_count = 2;
2783         for(u32 i_age=0; i_age<age_count; i_age++)
2784         { // Aging loop
2785
2786         {
2787         // 8ms @cs=8
2788         //TimeTaker timer1("stone obstacles");
2789
2790         /*
2791                 Add some random stone obstacles
2792         */
2793         
2794         for(s32 ri=0; ri<stone_obstacle_count; ri++)
2795         {
2796                 // Randomize max height so usually stuff will be quite low
2797                 s16 maxheight_randomized = myrand_range(0, stone_obstacle_max_height);
2798
2799                 //s16 stone_obstacle_max_size = sectorpos_base_size * MAP_BLOCKSIZE - 10;
2800                 s16 stone_obstacle_max_size = MAP_BLOCKSIZE*4-4;
2801
2802                 v3s16 ob_size(
2803                         myrand_range(5, stone_obstacle_max_size),
2804                         myrand_range(0, maxheight_randomized),
2805                         myrand_range(5, stone_obstacle_max_size)
2806                 );
2807                 
2808                 // Don't make stupid small rectangle bumps
2809                 if(ob_size.Y < 5)
2810                         continue;
2811                 
2812                 v2s16 ob_place(
2813                         myrand_range(1+ob_size.X/2+2,
2814                                         sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.X/2-2),
2815                         myrand_range(1+ob_size.Z/2+2,
2816                                         sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.Z/2-2)
2817                 );
2818                 
2819                 // Minimum space left on top of the obstacle
2820                 s16 min_head_space = 12;
2821                 
2822                 for(s16 x=-ob_size.X/2; x<ob_size.X/2; x++)
2823                 for(s16 z=-ob_size.Z/2; z<ob_size.Z/2; z++)
2824                 {
2825                         // Node position in 2d
2826                         v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + ob_place + v2s16(x,z);
2827                         
2828                         // Find stone ground level
2829                         // (ignore everything else than mud in already generated chunks)
2830                         // and mud amount over the stone level
2831                         s16 surface_y = 0;
2832                         s16 mud_amount = 0;
2833                         {
2834                                 v3s16 em = vmanip.m_area.getExtent();
2835                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2836                                 s16 y;
2837                                 // Go to ground level
2838                                 for(y=y_nodes_max; y>=y_nodes_min; y--)
2839                                 {
2840                                         MapNode *n = &vmanip.m_data[i];
2841                                         /*if(content_walkable(n.d)
2842                                                         && n.d != CONTENT_MUD
2843                                                         && n.d != CONTENT_GRASS)
2844                                                 break;*/
2845                                         if(n->d == CONTENT_STONE)
2846                                                 break;
2847                                         
2848                                         if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
2849                                         {
2850                                                 mud_amount++;
2851                                                 /*
2852                                                         Change to mud because otherwise we might
2853                                                         be throwing mud on grass at the next
2854                                                         step
2855                                                 */
2856                                                 n->d = CONTENT_MUD;
2857                                         }
2858                                                 
2859                                         vmanip.m_area.add_y(em, i, -1);
2860                                 }
2861                                 if(y >= y_nodes_min)
2862                                         surface_y = y;
2863                                 else
2864                                         surface_y = y_nodes_min;
2865                         }
2866
2867
2868                         /*
2869                                 Add stone on ground
2870                         */
2871                         {
2872                                 v3s16 em = vmanip.m_area.getExtent();
2873                                 s16 y_start = surface_y+1;
2874                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2875                                 s16 y;
2876                                 // Add stone
2877                                 s16 count = 0;
2878                                 for(y=y_start; y<=y_nodes_max - min_head_space; y++)
2879                                 {
2880                                         MapNode &n = vmanip.m_data[i];
2881                                         n.d = CONTENT_STONE;
2882
2883                                         if(y > stone_surface_max_y)
2884                                                 stone_surface_max_y = y;
2885
2886                                         count++;
2887                                         if(count >= ob_size.Y)
2888                                                 break;
2889                                                 
2890                                         vmanip.m_area.add_y(em, i, 1);
2891                                 }
2892                                 // Add mud
2893                                 count = 0;
2894                                 for(; y<=y_nodes_max - min_head_space; y++)
2895                                 {
2896                                         MapNode &n = vmanip.m_data[i];
2897                                         n.d = CONTENT_MUD;
2898                                         count++;
2899                                         if(count >= mud_amount)
2900                                                 break;
2901                                                 
2902                                         vmanip.m_area.add_y(em, i, 1);
2903                                 }
2904                         }
2905
2906                 }
2907         }
2908
2909         }//timer1
2910         {
2911         // 24ms @cs=8
2912         //TimeTaker timer1("dungeons");
2913
2914         /*
2915                 Make dungeons
2916         */
2917         u32 dungeons_count = relative_volume / 600000;
2918         u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
2919         if(stone_surface_max_y < WATER_LEVEL)
2920                 bruises_count = 0;
2921         /*u32 dungeons_count = 0;
2922         u32 bruises_count = 0;*/
2923         for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
2924         {
2925                 s16 min_tunnel_diameter = 2;
2926                 s16 max_tunnel_diameter = 6;
2927                 u16 tunnel_routepoints = 25;
2928                 
2929                 bool bruise_surface = (jj < bruises_count);
2930
2931                 if(bruise_surface)
2932                 {
2933                         min_tunnel_diameter = 5;
2934                         max_tunnel_diameter = myrand_range(10, 20);
2935                         /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
2936                         max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
2937                         
2938                         /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(m_seed+42,
2939                                         sectorpos_base.X, sectorpos_base.Y)), 0, 15);*/
2940
2941                         tunnel_routepoints = 5;
2942                 }
2943
2944                 // Allowed route area size in nodes
2945                 v3s16 ar(
2946                         sectorpos_base_size*MAP_BLOCKSIZE,
2947                         h_blocks*MAP_BLOCKSIZE,
2948                         sectorpos_base_size*MAP_BLOCKSIZE
2949                 );
2950
2951                 // Area starting point in nodes
2952                 v3s16 of(
2953                         sectorpos_base.X*MAP_BLOCKSIZE,
2954                         y_blocks_min*MAP_BLOCKSIZE,
2955                         sectorpos_base.Y*MAP_BLOCKSIZE
2956                 );
2957
2958                 // Allow a bit more
2959                 //(this should be more than the maximum radius of the tunnel)
2960                 //s16 insure = 5; // Didn't work with max_d = 20
2961                 s16 insure = 10;
2962                 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
2963                 ar += v3s16(1,0,1) * more * 2;
2964                 of -= v3s16(1,0,1) * more;
2965                 
2966                 s16 route_y_min = 0;
2967                 // Allow half a diameter + 7 over stone surface
2968                 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
2969
2970                 /*// If dungeons, don't go through surface too often
2971                 if(bruise_surface == false)
2972                         route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
2973
2974                 // Limit maximum to area
2975                 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
2976
2977                 if(bruise_surface)
2978                 {
2979                         /*// Minimum is at y=0
2980                         route_y_min = -of.Y - 0;*/
2981                         // Minimum is at y=max_tunnel_diameter/4
2982                         //route_y_min = -of.Y + max_tunnel_diameter/4;
2983                         //s16 min = -of.Y + max_tunnel_diameter/4;
2984                         s16 min = -of.Y + 0;
2985                         route_y_min = myrand_range(min, min + max_tunnel_diameter);
2986                         route_y_min = rangelim(route_y_min, 0, route_y_max);
2987                 }
2988
2989                 /*dstream<<"route_y_min = "<<route_y_min
2990                                 <<", route_y_max = "<<route_y_max<<std::endl;*/
2991
2992                 s16 route_start_y_min = route_y_min;
2993                 s16 route_start_y_max = route_y_max;
2994
2995                 // Start every 2nd dungeon from surface
2996                 bool coming_from_surface = (jj % 2 == 0 && bruise_surface == false);
2997
2998                 if(coming_from_surface)
2999                 {
3000                         route_start_y_min = -of.Y + stone_surface_max_y + 5;
3001                 }
3002                 
3003                 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
3004                 route_start_y_max = rangelim(route_start_y_max, 0, ar.Y-1);
3005
3006                 // Randomize starting position
3007                 v3f orp(
3008                         (float)(myrand()%ar.X)+0.5,
3009                         (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
3010                         (float)(myrand()%ar.Z)+0.5
3011                 );
3012
3013                 MapNode airnode(CONTENT_AIR);
3014                 
3015                 /*
3016                         Generate some tunnel starting from orp
3017                 */
3018                 
3019                 for(u16 j=0; j<tunnel_routepoints; j++)
3020                 {
3021                         // Randomize size
3022                         s16 min_d = min_tunnel_diameter;
3023                         s16 max_d = max_tunnel_diameter;
3024                         s16 rs = myrand_range(min_d, max_d);
3025                         
3026                         v3s16 maxlen;
3027                         if(bruise_surface)
3028                         {
3029                                 maxlen = v3s16(rs*7,rs*7,rs*7);
3030                         }
3031                         else
3032                         {
3033                                 maxlen = v3s16(15, myrand_range(1, 20), 15);
3034                         }
3035
3036                         v3f vec;
3037                         
3038                         if(coming_from_surface && j < 3)
3039                         {
3040                                 vec = v3f(
3041                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
3042                                         (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
3043                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
3044                                 );
3045                         }
3046                         else
3047                         {
3048                                 vec = v3f(
3049                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
3050                                         (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
3051                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
3052                                 );
3053                         }
3054
3055                         v3f rp = orp + vec;
3056                         if(rp.X < 0)
3057                                 rp.X = 0;
3058                         else if(rp.X >= ar.X)
3059                                 rp.X = ar.X-1;
3060                         if(rp.Y < route_y_min)
3061                                 rp.Y = route_y_min;
3062                         else if(rp.Y >= route_y_max)
3063                                 rp.Y = route_y_max-1;
3064                         if(rp.Z < 0)
3065                                 rp.Z = 0;
3066                         else if(rp.Z >= ar.Z)
3067                                 rp.Z = ar.Z-1;
3068                         vec = rp - orp;
3069
3070                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
3071                         {
3072                                 v3f fp = orp + vec * f;
3073                                 v3s16 cp(fp.X, fp.Y, fp.Z);
3074
3075                                 s16 d0 = -rs/2;
3076                                 s16 d1 = d0 + rs - 1;
3077                                 for(s16 z0=d0; z0<=d1; z0++)
3078                                 {
3079                                         //s16 si = rs - MYMAX(0, abs(z0)-rs/4);
3080                                         s16 si = rs - MYMAX(0, abs(z0)-rs/7);
3081                                         for(s16 x0=-si; x0<=si-1; x0++)
3082                                         {
3083                                                 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
3084                                                 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
3085                                                 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
3086                                                 //s16 si2 = rs - abs(x0);
3087                                                 for(s16 y0=-si2+1+2; y0<=si2-1; y0++)
3088                                                 {
3089                                                         s16 z = cp.Z + z0;
3090                                                         s16 y = cp.Y + y0;
3091                                                         s16 x = cp.X + x0;
3092                                                         v3s16 p(x,y,z);
3093                                                         /*if(isInArea(p, ar) == false)
3094                                                                 continue;*/
3095                                                         // Check only height
3096                                                         if(y < 0 || y >= ar.Y)
3097                                                                 continue;
3098                                                         p += of;
3099                                                         
3100                                                         //assert(vmanip.m_area.contains(p));
3101                                                         if(vmanip.m_area.contains(p) == false)
3102                                                         {
3103                                                                 dstream<<"WARNING: "<<__FUNCTION_NAME
3104                                                                                 <<":"<<__LINE__<<": "
3105                                                                                 <<"point not in area"
3106                                                                                 <<std::endl;
3107                                                                 continue;
3108                                                         }
3109                                                         
3110                                                         // Just set it to air, it will be changed to
3111                                                         // water afterwards
3112                                                         u32 i = vmanip.m_area.index(p);
3113                                                         vmanip.m_data[i] = airnode;
3114
3115                                                         if(bruise_surface == false)
3116                                                         {
3117                                                                 // Set tunnel flag
3118                                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON;
3119                                                         }
3120                                                 }
3121                                         }
3122                                 }
3123                         }
3124
3125                         orp = rp;
3126                 }
3127         
3128         }
3129
3130         }//timer1
3131         {
3132         // 46ms @cs=8
3133         //TimeTaker timer1("ore veins");
3134
3135         /*
3136                 Make ore veins
3137         */
3138         for(u32 jj=0; jj<relative_volume/1000; jj++)
3139         {
3140                 s16 max_vein_diameter = 3;
3141
3142                 // Allowed route area size in nodes
3143                 v3s16 ar(
3144                         sectorpos_base_size*MAP_BLOCKSIZE,
3145                         h_blocks*MAP_BLOCKSIZE,
3146                         sectorpos_base_size*MAP_BLOCKSIZE
3147                 );
3148
3149                 // Area starting point in nodes
3150                 v3s16 of(
3151                         sectorpos_base.X*MAP_BLOCKSIZE,
3152                         y_blocks_min*MAP_BLOCKSIZE,
3153                         sectorpos_base.Y*MAP_BLOCKSIZE
3154                 );
3155
3156                 // Allow a bit more
3157                 //(this should be more than the maximum radius of the tunnel)
3158                 s16 insure = 3;
3159                 s16 more = max_spread_amount - max_vein_diameter/2 - insure;
3160                 ar += v3s16(1,0,1) * more * 2;
3161                 of -= v3s16(1,0,1) * more;
3162                 
3163                 // Randomize starting position
3164                 v3f orp(
3165                         (float)(myrand()%ar.X)+0.5,
3166                         (float)(myrand()%ar.Y)+0.5,
3167                         (float)(myrand()%ar.Z)+0.5
3168                 );
3169
3170                 // Randomize mineral
3171                 u8 mineral;
3172                 if(myrand()%3 != 0)
3173                         mineral = MINERAL_COAL;
3174                 else
3175                         mineral = MINERAL_IRON;
3176
3177                 /*
3178                         Generate some vein starting from orp
3179                 */
3180
3181                 for(u16 j=0; j<2; j++)
3182                 {
3183                         /*v3f rp(
3184                                 (float)(myrand()%ar.X)+0.5,
3185                                 (float)(myrand()%ar.Y)+0.5,
3186                                 (float)(myrand()%ar.Z)+0.5
3187                         );
3188                         v3f vec = rp - orp;*/
3189                         
3190                         v3s16 maxlen(5, 5, 5);
3191                         v3f vec(
3192                                 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
3193                                 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
3194                                 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
3195                         );
3196                         v3f rp = orp + vec;
3197                         if(rp.X < 0)
3198                                 rp.X = 0;
3199                         else if(rp.X >= ar.X)
3200                                 rp.X = ar.X;
3201                         if(rp.Y < 0)
3202                                 rp.Y = 0;
3203                         else if(rp.Y >= ar.Y)
3204                                 rp.Y = ar.Y;
3205                         if(rp.Z < 0)
3206                                 rp.Z = 0;
3207                         else if(rp.Z >= ar.Z)
3208                                 rp.Z = ar.Z;
3209                         vec = rp - orp;
3210
3211                         // Randomize size
3212                         s16 min_d = 0;
3213                         s16 max_d = max_vein_diameter;
3214                         s16 rs = myrand_range(min_d, max_d);
3215                         
3216                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
3217                         {
3218                                 v3f fp = orp + vec * f;
3219                                 v3s16 cp(fp.X, fp.Y, fp.Z);
3220                                 s16 d0 = -rs/2;
3221                                 s16 d1 = d0 + rs - 1;
3222                                 for(s16 z0=d0; z0<=d1; z0++)
3223                                 {
3224                                         s16 si = rs - abs(z0);
3225                                         for(s16 x0=-si; x0<=si-1; x0++)
3226                                         {
3227                                                 s16 si2 = rs - abs(x0);
3228                                                 for(s16 y0=-si2+1; y0<=si2-1; y0++)
3229                                                 {
3230                                                         // Don't put mineral to every place
3231                                                         if(myrand()%5 != 0)
3232                                                                 continue;
3233
3234                                                         s16 z = cp.Z + z0;
3235                                                         s16 y = cp.Y + y0;
3236                                                         s16 x = cp.X + x0;
3237                                                         v3s16 p(x,y,z);
3238                                                         /*if(isInArea(p, ar) == false)
3239                                                                 continue;*/
3240                                                         // Check only height
3241                                                         if(y < 0 || y >= ar.Y)
3242                                                                 continue;
3243                                                         p += of;
3244                                                         
3245                                                         assert(vmanip.m_area.contains(p));
3246                                                         
3247                                                         // Just set it to air, it will be changed to
3248                                                         // water afterwards
3249                                                         u32 i = vmanip.m_area.index(p);
3250                                                         MapNode *n = &vmanip.m_data[i];
3251                                                         if(n->d == CONTENT_STONE)
3252                                                                 n->param = mineral;
3253                                                 }
3254                                         }
3255                                 }
3256                         }
3257
3258                         orp = rp;
3259                 }
3260         
3261         }
3262
3263         }//timer1
3264         {
3265         // 15ms @cs=8
3266         //TimeTaker timer1("add mud");
3267
3268         /*
3269                 Add mud to the central chunk
3270         */
3271         
3272         for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3273         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)
3274         {
3275                 // Node position in 2d
3276                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3277                 
3278                 // Randomize mud amount
3279                 s16 mud_add_amount = get_mud_amount(m_seed, v2f(p2d.X,p2d.Y))/age_count;
3280
3281                 // Find ground level
3282                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
3283
3284                 /*
3285                         If topmost node is grass, change it to mud.
3286                         It might be if it was flown to there from a neighboring
3287                         chunk and then converted.
3288                 */
3289                 {
3290                         u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
3291                         MapNode *n = &vmanip.m_data[i];
3292                         if(n->d == CONTENT_GRASS)
3293                                 n->d = CONTENT_MUD;
3294                 }
3295
3296                 /*
3297                         Add mud on ground
3298                 */
3299                 {
3300                         s16 mudcount = 0;
3301                         v3s16 em = vmanip.m_area.getExtent();
3302                         s16 y_start = surface_y+1;
3303                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3304                         for(s16 y=y_start; y<=y_nodes_max; y++)
3305                         {
3306                                 if(mudcount >= mud_add_amount)
3307                                         break;
3308                                         
3309                                 MapNode &n = vmanip.m_data[i];
3310                                 n.d = CONTENT_MUD;
3311                                 mudcount++;
3312
3313                                 vmanip.m_area.add_y(em, i, 1);
3314                         }
3315                 }
3316
3317         }
3318
3319         }//timer1
3320         {
3321         // 340ms @cs=8
3322         //TimeTaker timer1("flow mud");
3323
3324         /*
3325                 Flow mud away from steep edges
3326         */
3327
3328         // Limit area by 1 because mud is flown into neighbors.
3329         s16 mudflow_minpos = 0-max_spread_amount+1;
3330         s16 mudflow_maxpos = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
3331
3332         // Iterate a few times
3333         for(s16 k=0; k<3; k++)
3334         {
3335
3336         for(s16 x=mudflow_minpos;
3337                         x<=mudflow_maxpos;
3338                         x++)
3339         for(s16 z=mudflow_minpos;
3340                         z<=mudflow_maxpos;
3341                         z++)
3342         {
3343                 // Invert coordinates every 2nd iteration
3344                 if(k%2 == 0)
3345                 {
3346                         x = mudflow_maxpos - (x-mudflow_minpos);
3347                         z = mudflow_maxpos - (z-mudflow_minpos);
3348                 }
3349
3350                 // Node position in 2d
3351                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3352                 
3353                 v3s16 em = vmanip.m_area.getExtent();
3354                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3355                 s16 y=y_nodes_max;
3356
3357                 for(;; y--)
3358                 {
3359                         MapNode *n = NULL;
3360                         // Find mud
3361                         for(; y>=y_nodes_min; y--)
3362                         {
3363                                 n = &vmanip.m_data[i];
3364                                 //if(content_walkable(n->d))
3365                                 //      break;
3366                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
3367                                         break;
3368                                         
3369                                 vmanip.m_area.add_y(em, i, -1);
3370                         }
3371
3372                         // Stop if out of area
3373                         //if(vmanip.m_area.contains(i) == false)
3374                         if(y < y_nodes_min)
3375                                 break;
3376
3377                         /*// If not mud, do nothing to it
3378                         MapNode *n = &vmanip.m_data[i];
3379                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3380                                 continue;*/
3381
3382                         /*
3383                                 Don't flow it if the stuff under it is not mud
3384                         */
3385                         {
3386                                 u32 i2 = i;
3387                                 vmanip.m_area.add_y(em, i2, -1);
3388                                 // Cancel if out of area
3389                                 if(vmanip.m_area.contains(i2) == false)
3390                                         continue;
3391                                 MapNode *n2 = &vmanip.m_data[i2];
3392                                 if(n2->d != CONTENT_MUD && n2->d != CONTENT_GRASS)
3393                                         continue;
3394                         }
3395
3396                         // Make it exactly mud
3397                         n->d = CONTENT_MUD;
3398                         
3399                         /*s16 recurse_count = 0;
3400         mudflow_recurse:*/
3401
3402                         v3s16 dirs4[4] = {
3403                                 v3s16(0,0,1), // back
3404                                 v3s16(1,0,0), // right
3405                                 v3s16(0,0,-1), // front
3406                                 v3s16(-1,0,0), // left
3407                         };
3408
3409                         // Theck that upper is air or doesn't exist.
3410                         // Cancel dropping if upper keeps it in place
3411                         u32 i3 = i;
3412                         vmanip.m_area.add_y(em, i3, 1);
3413                         if(vmanip.m_area.contains(i3) == true
3414                                         && content_walkable(vmanip.m_data[i3].d) == true)
3415                         {
3416                                 continue;
3417                         }
3418
3419                         // Drop mud on side
3420                         
3421                         for(u32 di=0; di<4; di++)
3422                         {
3423                                 v3s16 dirp = dirs4[di];
3424                                 u32 i2 = i;
3425                                 // Move to side
3426                                 vmanip.m_area.add_p(em, i2, dirp);
3427                                 // Fail if out of area
3428                                 if(vmanip.m_area.contains(i2) == false)
3429                                         continue;
3430                                 // Check that side is air
3431                                 MapNode *n2 = &vmanip.m_data[i2];
3432                                 if(content_walkable(n2->d))
3433                                         continue;
3434                                 // Check that under side is air
3435                                 vmanip.m_area.add_y(em, i2, -1);
3436                                 if(vmanip.m_area.contains(i2) == false)
3437                                         continue;
3438                                 n2 = &vmanip.m_data[i2];
3439                                 if(content_walkable(n2->d))
3440                                         continue;
3441                                 /*// Check that under that is air (need a drop of 2)
3442                                 vmanip.m_area.add_y(em, i2, -1);
3443                                 if(vmanip.m_area.contains(i2) == false)
3444                                         continue;
3445                                 n2 = &vmanip.m_data[i2];
3446                                 if(content_walkable(n2->d))
3447                                         continue;*/
3448                                 // Loop further down until not air
3449                                 do{
3450                                         vmanip.m_area.add_y(em, i2, -1);
3451                                         // Fail if out of area
3452                                         if(vmanip.m_area.contains(i2) == false)
3453                                                 continue;
3454                                         n2 = &vmanip.m_data[i2];
3455                                 }while(content_walkable(n2->d) == false);
3456                                 // Loop one up so that we're in air
3457                                 vmanip.m_area.add_y(em, i2, 1);
3458                                 n2 = &vmanip.m_data[i2];
3459
3460                                 // Move mud to new place
3461                                 *n2 = *n;
3462                                 // Set old place to be air
3463                                 *n = MapNode(CONTENT_AIR);
3464
3465                                 // Done
3466                                 break;
3467                         }
3468                 }
3469         }
3470         
3471         }
3472
3473         }//timer1
3474         {
3475         // 50ms @cs=8
3476         //TimeTaker timer1("add water");
3477
3478         /*
3479                 Add water to the central chunk (and a bit more)
3480         */
3481         
3482         for(s16 x=0-max_spread_amount;
3483                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3484                         x++)
3485         for(s16 z=0-max_spread_amount;
3486                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3487                         z++)
3488         {
3489                 // Node position in 2d
3490                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3491                 
3492                 // Find ground level
3493                 //s16 surface_y = find_ground_level(vmanip, p2d);
3494
3495                 /*
3496                         If ground level is over water level, skip.
3497                         NOTE: This leaves caves near water without water,
3498                         which looks especially crappy when the nearby water
3499                         won't start flowing either for some reason
3500                 */
3501                 /*if(surface_y > WATER_LEVEL)
3502                         continue;*/
3503
3504                 /*
3505                         Add water on ground
3506                 */
3507                 {
3508                         v3s16 em = vmanip.m_area.getExtent();
3509                         u8 light = LIGHT_MAX;
3510                         // Start at global water surface level
3511                         s16 y_start = WATER_LEVEL;
3512                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3513                         MapNode *n = &vmanip.m_data[i];
3514
3515                         /*// Add first one to transforming liquid queue, if water
3516                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
3517                         {
3518                                 v3s16 p = v3s16(p2d.X, y_start, p2d.Y);
3519                                 m_transforming_liquid.push_back(p);
3520                         }*/
3521
3522                         for(s16 y=y_start; y>=y_nodes_min; y--)
3523                         {
3524                                 n = &vmanip.m_data[i];
3525                                 
3526                                 // Stop when there is no water and no air
3527                                 if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
3528                                                 && n->d != CONTENT_WATER)
3529                                 {
3530                                         /*// Add bottom one to transforming liquid queue
3531                                         vmanip.m_area.add_y(em, i, 1);
3532                                         n = &vmanip.m_data[i];
3533                                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
3534                                         {
3535                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
3536                                                 m_transforming_liquid.push_back(p);
3537                                         }*/
3538
3539                                         break;
3540                                 }
3541                                 
3542                                 // Make water only not in dungeons
3543                                 if(!(vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
3544                                 {
3545                                         n->d = CONTENT_WATERSOURCE;
3546                                         //n->setLight(LIGHTBANK_DAY, light);
3547
3548                                         // Add to transforming liquid queue (in case it'd
3549                                         // start flowing)
3550                                         v3s16 p = v3s16(p2d.X, y, p2d.Y);
3551                                         m_transforming_liquid.push_back(p);
3552                                 }
3553                                 
3554                                 // Next one
3555                                 vmanip.m_area.add_y(em, i, -1);
3556                                 if(light > 0)
3557                                         light--;
3558                         }
3559                 }
3560
3561         }
3562
3563         }//timer1
3564         
3565         } // Aging loop
3566
3567         {
3568         //TimeTaker timer1("convert mud to sand");
3569
3570         /*
3571                 Convert mud to sand
3572         */
3573         
3574         //s16 mud_add_amount = myrand_range(2, 4);
3575         //s16 mud_add_amount = 0;
3576         
3577         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3578         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3579         for(s16 x=0-max_spread_amount+1;
3580                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3581                         x++)
3582         for(s16 z=0-max_spread_amount+1;
3583                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3584                         z++)
3585         {
3586                 // Node position in 2d
3587                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3588                 
3589                 // Determine whether to have sand here
3590                 bool have_sand = get_have_sand_coast(p2d);
3591
3592                 if(have_sand == false)
3593                         continue;
3594
3595                 // Find ground level
3596                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
3597                 
3598                 if(surface_y > WATER_LEVEL + 2)
3599                         continue;
3600
3601                 {
3602                         v3s16 em = vmanip.m_area.getExtent();
3603                         s16 y_start = surface_y;
3604                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3605                         u32 not_sand_counter = 0;
3606                         for(s16 y=y_start; y>=y_nodes_min; y--)
3607                         {
3608                                 MapNode *n = &vmanip.m_data[i];
3609                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
3610                                 {
3611                                         n->d = CONTENT_SAND;
3612                                 }
3613                                 else
3614                                 {
3615                                         not_sand_counter++;
3616                                         if(not_sand_counter > 3)
3617                                                 break;
3618                                 }
3619
3620                                 vmanip.m_area.add_y(em, i, -1);
3621                         }
3622                 }
3623
3624         }
3625
3626         }//timer1
3627         {
3628         // 1ms @cs=8
3629         //TimeTaker timer1("generate trees");
3630
3631         /*
3632                 Generate some trees
3633         */
3634         {
3635                 // Divide area into parts
3636                 s16 div = 8;
3637                 s16 sidelen = sectorpos_base_size*MAP_BLOCKSIZE / div;
3638                 double area = sidelen * sidelen;
3639                 for(s16 x0=0; x0<div; x0++)
3640                 for(s16 z0=0; z0<div; z0++)
3641                 {
3642                         // Center position of part of division
3643                         v2s16 p2d_center(
3644                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
3645                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
3646                         );
3647                         // Minimum edge of part of division
3648                         v2s16 p2d_min(
3649                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
3650                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
3651                         );
3652                         // Maximum edge of part of division
3653                         v2s16 p2d_max(
3654                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
3655                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
3656                         );
3657                         // Amount of trees
3658                         u32 tree_count = area * tree_amount_2d(m_seed, p2d_center);
3659                         // Put trees in random places on part of division
3660                         for(u32 i=0; i<tree_count; i++)
3661                         {
3662                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
3663                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
3664                                 s16 y = find_ground_level(vmanip, v2s16(x,z));
3665                                 // Don't make a tree under water level
3666                                 if(y < WATER_LEVEL)
3667                                         continue;
3668                                 v3s16 p(x,y,z);
3669                                 /*
3670                                         Trees grow only on mud and grass
3671                                 */
3672                                 {
3673                                         u32 i = vmanip.m_area.index(v3s16(p));
3674                                         MapNode *n = &vmanip.m_data[i];
3675                                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3676                                                 continue;
3677                                 }
3678                                 p.Y++;
3679                                 // Make a tree
3680                                 make_tree(vmanip, p);
3681                         }
3682                 }
3683                 /*u32 tree_max = relative_area / 60;
3684                 //u32 count = myrand_range(0, tree_max);
3685                 for(u32 i=0; i<count; i++)
3686                 {
3687                         s16 x = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
3688                         s16 z = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
3689                         x += sectorpos_base.X*MAP_BLOCKSIZE;
3690                         z += sectorpos_base.Y*MAP_BLOCKSIZE;
3691                         s16 y = find_ground_level(vmanip, v2s16(x,z));
3692                         // Don't make a tree under water level
3693                         if(y < WATER_LEVEL)
3694                                 continue;
3695                         v3s16 p(x,y+1,z);
3696                         // Make a tree
3697                         make_tree(vmanip, p);
3698                 }*/
3699         }
3700
3701         }//timer1
3702
3703         {
3704         // 19ms @cs=8
3705         //TimeTaker timer1("grow grass");
3706
3707         /*
3708                 Grow grass
3709         */
3710
3711         /*for(s16 x=0-4; x<sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
3712         for(s16 z=0-4; z<sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
3713         for(s16 x=0-max_spread_amount;
3714                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3715                         x++)
3716         for(s16 z=0-max_spread_amount;
3717                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3718                         z++)
3719         {
3720                 // Node position in 2d
3721                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3722                 
3723                 /*
3724                         Find the lowest surface to which enough light ends up
3725                         to make grass grow.
3726
3727                         Basically just wait until not air and not leaves.
3728                 */
3729                 s16 surface_y = 0;
3730                 {
3731                         v3s16 em = vmanip.m_area.getExtent();
3732                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3733                         s16 y;
3734                         // Go to ground level
3735                         for(y=y_nodes_max; y>=y_nodes_min; y--)
3736                         {
3737                                 MapNode &n = vmanip.m_data[i];
3738                                 if(n.d != CONTENT_AIR
3739                                                 && n.d != CONTENT_LEAVES)
3740                                         break;
3741                                 vmanip.m_area.add_y(em, i, -1);
3742                         }
3743                         if(y >= y_nodes_min)
3744                                 surface_y = y;
3745                         else
3746                                 surface_y = y_nodes_min;
3747                 }
3748                 
3749                 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
3750                 MapNode *n = &vmanip.m_data[i];
3751                 if(n->d == CONTENT_MUD)
3752                         n->d = CONTENT_GRASS;
3753         }
3754
3755         }//timer1
3756
3757         /*
3758                 Initial lighting (sunlight)
3759         */
3760
3761         core::map<v3s16, bool> light_sources;
3762
3763         {
3764         // 750ms @cs=8, can't optimize more
3765         TimeTaker timer1("initial lighting");
3766
3767 #if 0
3768         /*
3769                 Go through the edges and add all nodes that have light to light_sources
3770         */
3771         
3772         // Four edges
3773         for(s16 i=0; i<4; i++)
3774         // Edge length
3775         for(s16 j=lighting_min_d;
3776                         j<=lighting_max_d;
3777                         j++)
3778         {
3779                 s16 x;
3780                 s16 z;
3781                 // +-X
3782                 if(i == 0 || i == 1)
3783                 {
3784                         x = (i==0) ? lighting_min_d : lighting_max_d;
3785                         if(i == 0)
3786                                 z = lighting_min_d;
3787                         else
3788                                 z = lighting_max_d;
3789                 }
3790                 // +-Z
3791                 else
3792                 {
3793                         z = (i==0) ? lighting_min_d : lighting_max_d;
3794                         if(i == 0)
3795                                 x = lighting_min_d;
3796                         else
3797                                 x = lighting_max_d;
3798                 }
3799                 
3800                 // Node position in 2d
3801                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3802
3803                 {
3804                         v3s16 em = vmanip.m_area.getExtent();
3805                         s16 y_start = y_nodes_max;
3806                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3807                         for(s16 y=y_start; y>=y_nodes_min; y--)
3808                         {
3809                                 MapNode *n = &vmanip.m_data[i];
3810                                 if(n->getLight(LIGHTBANK_DAY) != 0)
3811                                 {
3812                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3813                                 }
3814                                 //NOTE: This is broken, at least the index has to
3815                                 // be incremented
3816                         }
3817                 }
3818         }
3819 #endif
3820
3821 #if 1
3822         /*
3823                 Go through the edges and apply sunlight to them, not caring
3824                 about neighbors
3825         */
3826         
3827         // Four edges
3828         for(s16 i=0; i<4; i++)
3829         // Edge length
3830         for(s16 j=lighting_min_d;
3831                         j<=lighting_max_d;
3832                         j++)
3833         {
3834                 s16 x;
3835                 s16 z;
3836                 // +-X
3837                 if(i == 0 || i == 1)
3838                 {
3839                         x = (i==0) ? lighting_min_d : lighting_max_d;
3840                         if(i == 0)
3841                                 z = lighting_min_d;
3842                         else
3843                                 z = lighting_max_d;
3844                 }
3845                 // +-Z
3846                 else
3847                 {
3848                         z = (i==0) ? lighting_min_d : lighting_max_d;
3849                         if(i == 0)
3850                                 x = lighting_min_d;
3851                         else
3852                                 x = lighting_max_d;
3853                 }
3854                 
3855                 // Node position in 2d
3856                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3857                 
3858                 // Loop from top to down
3859                 {
3860                         u8 light = LIGHT_SUN;
3861                         v3s16 em = vmanip.m_area.getExtent();
3862                         s16 y_start = y_nodes_max;
3863                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3864                         for(s16 y=y_start; y>=y_nodes_min; y--)
3865                         {
3866                                 MapNode *n = &vmanip.m_data[i];
3867                                 if(light_propagates_content(n->d) == false)
3868                                 {
3869                                         light = 0;
3870                                 }
3871                                 else if(light != LIGHT_SUN
3872                                         || sunlight_propagates_content(n->d) == false)
3873                                 {
3874                                         if(light > 0)
3875                                                 light--;
3876                                 }
3877                                 
3878                                 n->setLight(LIGHTBANK_DAY, light);
3879                                 n->setLight(LIGHTBANK_NIGHT, 0);
3880                                 
3881                                 if(light != 0)
3882                                 {
3883                                         // Insert light source
3884                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3885                                 }
3886                                 
3887                                 // Increment index by y
3888                                 vmanip.m_area.add_y(em, i, -1);
3889                         }
3890                 }
3891         }
3892 #endif
3893
3894         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3895         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3896         /*for(s16 x=0-max_spread_amount+1;
3897                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3898                         x++)
3899         for(s16 z=0-max_spread_amount+1;
3900                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3901                         z++)*/
3902 #if 1
3903         /*
3904                 This has to be 1 smaller than the actual area, because
3905                 neighboring nodes are checked.
3906         */
3907         for(s16 x=lighting_min_d+1;
3908                         x<=lighting_max_d-1;
3909                         x++)
3910         for(s16 z=lighting_min_d+1;
3911                         z<=lighting_max_d-1;
3912                         z++)
3913         {
3914                 // Node position in 2d
3915                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3916                 
3917                 /*
3918                         Apply initial sunlight
3919                 */
3920                 {
3921                         u8 light = LIGHT_SUN;
3922                         bool add_to_sources = false;
3923                         v3s16 em = vmanip.m_area.getExtent();
3924                         s16 y_start = y_nodes_max;
3925                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3926                         for(s16 y=y_start; y>=y_nodes_min; y--)
3927                         {
3928                                 MapNode *n = &vmanip.m_data[i];
3929
3930                                 if(light_propagates_content(n->d) == false)
3931                                 {
3932                                         light = 0;
3933                                 }
3934                                 else if(light != LIGHT_SUN
3935                                         || sunlight_propagates_content(n->d) == false)
3936                                 {
3937                                         if(light > 0)
3938                                                 light--;
3939                                 }
3940                                 
3941                                 // This doesn't take much time
3942                                 if(add_to_sources == false)
3943                                 {
3944                                         /*
3945                                                 Check sides. If side is not air or water, start
3946                                                 adding to light_sources.
3947                                         */
3948                                         v3s16 dirs4[4] = {
3949                                                 v3s16(0,0,1), // back
3950                                                 v3s16(1,0,0), // right
3951                                                 v3s16(0,0,-1), // front
3952                                                 v3s16(-1,0,0), // left
3953                                         };
3954                                         for(u32 di=0; di<4; di++)
3955                                         {
3956                                                 v3s16 dirp = dirs4[di];
3957                                                 u32 i2 = i;
3958                                                 vmanip.m_area.add_p(em, i2, dirp);
3959                                                 MapNode *n2 = &vmanip.m_data[i2];
3960                                                 if(
3961                                                         n2->d != CONTENT_AIR
3962                                                         && n2->d != CONTENT_WATERSOURCE
3963                                                         && n2->d != CONTENT_WATER
3964                                                 ){
3965                                                         add_to_sources = true;
3966                                                         break;
3967                                                 }
3968                                         }
3969                                 }
3970                                 
3971                                 n->setLight(LIGHTBANK_DAY, light);
3972                                 n->setLight(LIGHTBANK_NIGHT, 0);
3973                                 
3974                                 // This doesn't take much time
3975                                 if(light != 0 && add_to_sources)
3976                                 {
3977                                         // Insert light source
3978                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3979                                 }
3980                                 
3981                                 // Increment index by y
3982                                 vmanip.m_area.add_y(em, i, -1);
3983                         }
3984                 }
3985         }
3986 #endif
3987
3988         }//timer1
3989
3990         // Spread light around
3991         {
3992                 TimeTaker timer("generateChunkRaw() spreadLight");
3993                 vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
3994         }
3995         
3996         /*
3997                 Generation ended
3998         */
3999
4000         timer_generate.stop();
4001
4002         /*
4003                 Blit generated stuff to map
4004         */
4005         {
4006                 // 70ms @cs=8
4007                 //TimeTaker timer("generateChunkRaw() blitBackAll");
4008                 vmanip.blitBackAll(&changed_blocks);
4009         }
4010
4011         /*
4012                 Update day/night difference cache of the MapBlocks
4013         */
4014         {
4015                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
4016                                 i.atEnd() == false; i++)
4017                 {
4018                         MapBlock *block = i.getNode()->getValue();
4019                         block->updateDayNightDiff();
4020                 }
4021         }
4022
4023 #endif
4024         
4025         /*
4026                 Create chunk metadata
4027         */
4028
4029         for(s16 x=-1; x<=1; x++)
4030         for(s16 y=-1; y<=1; y++)
4031         {
4032                 v2s16 chunkpos0 = chunkpos + v2s16(x,y);
4033                 // Add chunk meta information
4034                 MapChunk *chunk = getChunk(chunkpos0);
4035                 if(chunk == NULL)
4036                 {
4037                         chunk = new MapChunk();
4038                         m_chunks.insert(chunkpos0, chunk);
4039                 }
4040                 //chunk->setIsVolatile(true);
4041                 if(chunk->getGenLevel() > GENERATED_PARTLY)
4042                         chunk->setGenLevel(GENERATED_PARTLY);
4043         }
4044
4045         /*
4046                 Set central chunk non-volatile
4047         */
4048         MapChunk *chunk = getChunk(chunkpos);
4049         assert(chunk);
4050         // Set non-volatile
4051         //chunk->setIsVolatile(false);
4052         chunk->setGenLevel(GENERATED_FULLY);
4053         
4054         /*
4055                 Save changed parts of map
4056         */
4057         save(true);
4058
4059         /*
4060                 Return central chunk (which was requested)
4061         */
4062         return chunk;
4063 }
4064 #endif
4065
4066 #if 0
4067 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
4068                 core::map<v3s16, MapBlock*> &changed_blocks,
4069                 bool force)
4070 {
4071         DSTACK(__FUNCTION_NAME);
4072
4073         /*
4074                 Don't generate if already fully generated
4075         */
4076         if(force == false)
4077         {
4078                 MapChunk *chunk = getChunk(chunkpos);
4079                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
4080                 {
4081                         dstream<<"generateChunkRaw(): Chunk "
4082                                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
4083                                         <<" already generated"<<std::endl;
4084                         return chunk;
4085                 }
4086         }
4087
4088 #if 0
4089         dstream<<"generateChunkRaw(): Generating chunk "
4090                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
4091                         <<std::endl;
4092         
4093         TimeTaker timer("generateChunkRaw()");
4094         
4095         // The distance how far into the neighbors the generator is allowed to go.
4096         s16 max_spread_amount_sectors = 1;
4097         assert(max_spread_amount_sectors <= m_chunksize);
4098         s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
4099
4100         // Minimum amount of space left on sides for mud to fall in
4101         //s16 min_mud_fall_space = 2;
4102         
4103         // Maximum diameter of stone obstacles in X and Z
4104         /*s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
4105         assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);*/
4106         
4107         s16 y_blocks_min = -2;
4108         s16 y_blocks_max = 3;
4109         //s16 h_blocks = y_blocks_max - y_blocks_min + 1;
4110         s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
4111         s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
4112
4113         v2s16 sectorpos_base = chunk_to_sector(chunkpos);
4114         s16 sectorpos_base_size = m_chunksize;
4115
4116         /*v2s16 sectorpos_bigbase = chunk_to_sector(chunkpos - v2s16(1,1));
4117         s16 sectorpos_bigbase_size = m_chunksize * 3;*/
4118         v2s16 sectorpos_bigbase =
4119                         sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
4120         s16 sectorpos_bigbase_size =
4121                         sectorpos_base_size + 2 * max_spread_amount_sectors;
4122
4123         v3s16 bigarea_blocks_min(
4124                 sectorpos_bigbase.X,
4125                 y_blocks_min,
4126                 sectorpos_bigbase.Y
4127         );
4128
4129         v3s16 bigarea_blocks_max(
4130                 sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
4131                 y_blocks_max,
4132                 sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
4133         );
4134         
4135         // Relative values to control amount of stuff in one chunk
4136         /*u32 relative_area = (u32)sectorpos_base_size*MAP_BLOCKSIZE
4137                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE;*/
4138         /*u32 relative_volume = (u32)sectorpos_base_size*MAP_BLOCKSIZE
4139                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE
4140                         *(u32)h_blocks*MAP_BLOCKSIZE;*/
4141                 
4142         /*
4143                 The limiting edges of the lighting update, inclusive.
4144         */
4145         s16 lighting_min_d = 0-max_spread_amount;
4146         s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
4147
4148         /*
4149                 Create the whole area of this and the neighboring chunks
4150         */
4151         {
4152                 TimeTaker timer("generateChunkRaw() create area");
4153                 
4154                 for(s16 x=0; x<sectorpos_bigbase_size; x++)
4155                 for(s16 z=0; z<sectorpos_bigbase_size; z++)
4156                 {
4157                         v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
4158                         ServerMapSector *sector = createSector(sectorpos);
4159                         assert(sector);
4160
4161                         for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
4162                         {
4163                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
4164                                 MapBlock *block = createBlock(blockpos);
4165
4166                                 // Lighting won't be calculated
4167                                 //block->setLightingExpired(true);
4168                                 // Lighting will be calculated
4169                                 block->setLightingExpired(false);
4170
4171                                 /*
4172                                         Block gets sunlight if this is true.
4173
4174                                         This should be set to true when the top side of a block
4175                                         is completely exposed to the sky.
4176
4177                                         Actually this doesn't matter now because the
4178                                         initial lighting is done here.
4179                                 */
4180                                 block->setIsUnderground(y != y_blocks_max);
4181                         }
4182                 }
4183         }
4184         
4185         /*
4186                 Now we have a big empty area.
4187
4188                 Make a ManualMapVoxelManipulator that contains this and the
4189                 neighboring chunks
4190         */
4191
4192         ManualMapVoxelManipulator vmanip(this);
4193         // Add the area we just generated
4194         {
4195                 TimeTaker timer("generateChunkRaw() initialEmerge");
4196                 vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
4197         }
4198
4199         // Clear all flags
4200         vmanip.clearFlag(0xff);
4201
4202         TimeTaker timer_generate("generateChunkRaw() generate");
4203
4204         /*
4205                 Generate general ground level to full area
4206         */
4207         
4208         {
4209         // 22ms @cs=8
4210         TimeTaker timer1("ground level");
4211         dstream<<"Generating base ground..."<<std::endl;
4212
4213         for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
4214         for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
4215         {
4216                 // Node position
4217                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
4218                 
4219                 /*
4220                         Skip if already generated
4221                 */
4222                 {
4223                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
4224                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
4225                                 continue;
4226                 }
4227
4228                 v2f p2df(p2d.X, p2d.Y);
4229
4230                 s16 mud_amount = get_mud_amount(m_seed, p2df);
4231                 
4232                 double tfxz = get_turbulence_factor_2d(m_seed, p2df);
4233                 bool turbulence_is_used = (tfxz > 0.001);
4234
4235                 s16 surface_y = 0;
4236                 
4237                 float noturb_surface_y_f = base_rock_level_2d(m_seed, p2df);
4238                 s16 noturb_surface_y = noturb_surface_y_f;
4239
4240                 {
4241                         s16 depth_counter = 0;
4242                         s16 min = y_nodes_min;
4243                         s16 max = y_nodes_max;
4244                         // Use fast index incrementing
4245                         v3s16 em = vmanip.m_area.getExtent();
4246                         u32 i = vmanip.m_area.index(v3s16(p2d.X, max, p2d.Y));
4247                         for(s16 y=max; y>=min; y--)
4248                         {
4249                                 v3f p3df(p2df.X, y, p2df.Y);
4250
4251                                 bool is_ground = false;
4252
4253                                 bool turb_for_node = (turbulence_is_used
4254                                                 && y >= TURBULENCE_BOTTOM_CUTOFF_Y);
4255                                 
4256                                 if(is_carved(m_seed, p3df))
4257                                 {
4258                                         is_ground = false;
4259                                 }
4260                                 else
4261                                 {
4262                                         if(turb_for_node)
4263                                         {
4264                                                 double depth_guess;
4265                                                 is_ground = is_base_ground(m_seed,
4266                                                                 p3df, &depth_guess);
4267                                                 
4268                                                 // Estimate the surface height
4269                                                 surface_y = y + depth_guess;
4270                                         }
4271                                         else
4272                                         {
4273                                                 surface_y = noturb_surface_y;
4274                                         }
4275                                         
4276                                         is_ground = (y <= surface_y);
4277                                 }
4278                                 
4279                                 if(is_ground)
4280                                 {
4281                                         //vmanip.m_data[i].d = CONTENT_STONE;
4282                                         /*if(y > surface_y - mud_amount)
4283                                                 vmanip.m_data[i].d = CONTENT_MUD;
4284                                         else
4285                                                 vmanip.m_data[i].d = CONTENT_STONE;*/
4286                                         if(depth_counter < mud_amount)
4287                                                 vmanip.m_data[i].d = CONTENT_MUD;
4288                                         else
4289                                                 vmanip.m_data[i].d = CONTENT_STONE;
4290                                 }
4291                                 else
4292                                         vmanip.m_data[i].d = CONTENT_AIR;
4293                                 
4294                                 if(is_ground || depth_counter != 0)
4295                                         depth_counter++;
4296
4297 #if 0
4298 #if 1
4299                                 bool is = is_base_ground(m_seed, v3f(p2df.X,y,p2df.Y));
4300                                 if(is)
4301                                         vmanip.m_data[i].d = CONTENT_STONE;
4302                                 else
4303                                         vmanip.m_data[i].d = CONTENT_AIR;
4304 #endif
4305 #endif
4306
4307                                 vmanip.m_area.add_y(em, i, -1);
4308                         }
4309                 }
4310         }
4311         
4312         }//timer1
4313
4314         {
4315         // 50ms @cs=8
4316         //TimeTaker timer1("add water");
4317
4318         /*
4319                 Add water to the central chunk (and a bit more)
4320         */
4321         
4322         for(s16 x=0-max_spread_amount;
4323                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
4324                         x++)
4325         for(s16 z=0-max_spread_amount;
4326                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
4327                         z++)
4328         {
4329                 // Node position in 2d
4330                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
4331                 
4332                 // Find ground level
4333                 //s16 surface_y = find_ground_level(vmanip, p2d);
4334
4335                 /*
4336                         If ground level is over water level, skip.
4337                         NOTE: This leaves caves near water without water,
4338                         which looks especially crappy when the nearby water
4339                         won't start flowing either for some reason
4340                 */
4341                 /*if(surface_y > WATER_LEVEL)
4342                         continue;*/
4343
4344                 /*
4345                         Add water on ground
4346                 */
4347                 {
4348                         v3s16 em = vmanip.m_area.getExtent();
4349                         u8 light = LIGHT_MAX;
4350                         // Start at global water surface level
4351                         s16 y_start = WATER_LEVEL;
4352                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
4353                         MapNode *n = &vmanip.m_data[i];
4354
4355                         /*// Add first one to transforming liquid queue, if water
4356                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
4357                         {
4358                                 v3s16 p = v3s16(p2d.X, y_start, p2d.Y);
4359                                 m_transforming_liquid.push_back(p);
4360                         }*/
4361
4362                         for(s16 y=y_start; y>=y_nodes_min; y--)
4363                         {
4364                                 n = &vmanip.m_data[i];
4365                                 
4366                                 // Stop when there is no water and no air
4367                                 if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
4368                                                 && n->d != CONTENT_WATER)
4369                                 {
4370                                         /*// Add bottom one to transforming liquid queue
4371                                         vmanip.m_area.add_y(em, i, 1);
4372                                         n = &vmanip.m_data[i];
4373                                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
4374                                         {
4375                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
4376                                                 m_transforming_liquid.push_back(p);
4377                                         }*/
4378
4379                                         break;
4380                                 }
4381                                 
4382                                 // Make water only not in dungeons
4383                                 if(!(vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
4384                                 {
4385                                         n->d = CONTENT_WATERSOURCE;
4386                                         //n->setLight(LIGHTBANK_DAY, light);
4387
4388                                         // Add to transforming liquid queue (in case it'd
4389                                         // start flowing)
4390                                         v3s16 p = v3s16(p2d.X, y, p2d.Y);
4391                                         m_transforming_liquid.push_back(p);
4392                                 }
4393                                 
4394                                 // Next one
4395                                 vmanip.m_area.add_y(em, i, -1);
4396                                 if(light > 0)
4397                                         light--;
4398                         }
4399                 }
4400
4401         }
4402
4403         }//timer1
4404
4405         {
4406         //TimeTaker timer1("convert mud to sand");
4407
4408         /*
4409                 Convert mud to sand
4410         */
4411         
4412         //s16 mud_add_amount = myrand_range(2, 4);
4413         //s16 mud_add_amount = 0;
4414         
4415         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
4416         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
4417         for(s16 x=0-max_spread_amount+1;
4418                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
4419                         x++)
4420         for(s16 z=0-max_spread_amount+1;
4421                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
4422                         z++)
4423         {
4424                 // Node position in 2d
4425                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
4426                 
4427                 // Determine whether to have sand here
4428                 bool have_sand = get_have_sand_coast(m_seed, v2f(p2d.X,p2d.Y));
4429
4430                 if(have_sand == false)
4431                         continue;
4432
4433                 // Find ground level
4434                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
4435                 
4436                 if(surface_y > WATER_LEVEL + 2)
4437                         continue;
4438
4439                 {
4440                         v3s16 em = vmanip.m_area.getExtent();
4441                         s16 y_start = surface_y;
4442                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
4443                         u32 not_sand_counter = 0;
4444                         for(s16 y=y_start; y>=y_nodes_min; y--)
4445                         {
4446                                 MapNode *n = &vmanip.m_data[i];
4447                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
4448                                 {
4449                                         n->d = CONTENT_SAND;
4450                                 }
4451                                 else
4452                                 {
4453                                         not_sand_counter++;
4454                                         if(not_sand_counter > 3)
4455                                                 break;
4456                                 }
4457
4458                                 vmanip.m_area.add_y(em, i, -1);
4459                         }
4460                 }
4461
4462         }
4463
4464         }//timer1
4465
4466         {
4467         // 19ms @cs=8
4468         //TimeTaker timer1("grow grass");
4469
4470         /*
4471                 Grow grass
4472         */
4473
4474         /*for(s16 x=0-4; x<sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
4475         for(s16 z=0-4; z<sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
4476         for(s16 x=0-max_spread_amount;
4477                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
4478                         x++)
4479         for(s16 z=0-max_spread_amount;
4480                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
4481                         z++)
4482         {
4483                 // Node position in 2d
4484                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
4485                 
4486                 /*
4487                         Find the lowest surface to which enough light ends up
4488                         to make grass grow.
4489
4490                         Basically just wait until not air and not leaves.
4491                 */
4492                 s16 surface_y = 0;
4493                 {
4494                         v3s16 em = vmanip.m_area.getExtent();
4495                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
4496                         s16 y;
4497                         // Go to ground level
4498                         for(y=y_nodes_max; y>=y_nodes_min; y--)
4499                         {
4500                                 MapNode &n = vmanip.m_data[i];
4501                                 if(n.d != CONTENT_AIR
4502                                                 && n.d != CONTENT_LEAVES)
4503                                         break;
4504                                 vmanip.m_area.add_y(em, i, -1);
4505                         }
4506                         if(y >= y_nodes_min)
4507                                 surface_y = y;
4508                         else
4509                                 surface_y = y_nodes_min;
4510                 }
4511                 
4512                 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
4513                 MapNode *n = &vmanip.m_data[i];
4514                 if(n->d == CONTENT_MUD)
4515                         n->d = CONTENT_GRASS;
4516         }
4517
4518         }//timer1
4519
4520         {
4521         // 1ms @cs=8
4522         //TimeTaker timer1("generate trees");
4523
4524         /*
4525                 Generate some trees
4526         */
4527         {
4528                 // Divide area into parts
4529                 s16 div = 8;
4530                 s16 sidelen = sectorpos_base_size*MAP_BLOCKSIZE / div;
4531                 double area = sidelen * sidelen;
4532                 for(s16 x0=0; x0<div; x0++)
4533                 for(s16 z0=0; z0<div; z0++)
4534                 {
4535                         // Center position of part of division
4536                         v2s16 p2d_center(
4537                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
4538                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
4539                         );
4540                         // Minimum edge of part of division
4541                         v2s16 p2d_min(
4542                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
4543                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
4544                         );
4545                         // Maximum edge of part of division
4546                         v2s16 p2d_max(
4547                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
4548                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
4549                         );
4550                         // Amount of trees
4551                         u32 tree_count = area * tree_amount_2d(m_seed, p2d_center);
4552                         // Put trees in random places on part of division
4553                         for(u32 i=0; i<tree_count; i++)
4554                         {
4555                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
4556                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
4557                                 s16 y = find_ground_level(vmanip, v2s16(x,z));
4558                                 // Don't make a tree under water level
4559                                 if(y < WATER_LEVEL)
4560                                         continue;
4561                                 v3s16 p(x,y,z);
4562                                 /*
4563                                         Trees grow only on mud and grass
4564                                 */
4565                                 {
4566                                         u32 i = vmanip.m_area.index(v3s16(p));
4567                                         MapNode *n = &vmanip.m_data[i];
4568                                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
4569                                                 continue;
4570                                 }
4571                                 p.Y++;
4572                                 // Make a tree
4573                                 make_tree(vmanip, p);
4574                         }
4575                 }
4576                 /*u32 tree_max = relative_area / 60;
4577                 //u32 count = myrand_range(0, tree_max);
4578                 for(u32 i=0; i<count; i++)
4579                 {
4580                         s16 x = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
4581                         s16 z = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
4582                         x += sectorpos_base.X*MAP_BLOCKSIZE;
4583                         z += sectorpos_base.Y*MAP_BLOCKSIZE;
4584                         s16 y = find_ground_level(vmanip, v2s16(x,z));
4585                         // Don't make a tree under water level
4586                         if(y < WATER_LEVEL)
4587                                 continue;
4588                         v3s16 p(x,y+1,z);
4589                         // Make a tree
4590                         make_tree(vmanip, p);
4591                 }*/
4592         }
4593
4594         }//timer1
4595
4596
4597         /*
4598                 Initial lighting (sunlight)
4599         */
4600
4601         core::map<v3s16, bool> light_sources;
4602
4603         {
4604         // 750ms @cs=8, can't optimize more
4605         TimeTaker timer1("initial lighting");
4606
4607 #if 1
4608         /*
4609                 This has to be 1 smaller than the actual area, because
4610                 neighboring nodes are checked.
4611         */
4612         for(s16 x=lighting_min_d+1;
4613                         x<=lighting_max_d-1;
4614                         x++)
4615         for(s16 z=lighting_min_d+1;
4616                         z<=lighting_max_d-1;
4617                         z++)
4618         {
4619                 // Node position in 2d
4620                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
4621                 
4622                 /*
4623                         Apply initial sunlight
4624                 */
4625                 {
4626                         u8 light = LIGHT_SUN;
4627                         bool add_to_sources = false;
4628                         v3s16 em = vmanip.m_area.getExtent();
4629                         s16 y_start = y_nodes_max;
4630                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
4631                         for(s16 y=y_start; y>=y_nodes_min; y--)
4632                         {
4633                                 MapNode *n = &vmanip.m_data[i];
4634
4635                                 if(light_propagates_content(n->d) == false)
4636                                 {
4637                                         light = 0;
4638                                 }
4639                                 else if(light != LIGHT_SUN
4640                                         || sunlight_propagates_content(n->d) == false)
4641                                 {
4642                                         if(light > 0)
4643                                                 light--;
4644                                 }
4645                                 
4646                                 // This doesn't take much time
4647                                 if(add_to_sources == false)
4648                                 {
4649                                         /*
4650                                                 Check sides. If side is not air or water, start
4651                                                 adding to light_sources.
4652                                         */
4653                                         v3s16 dirs4[4] = {
4654                                                 v3s16(0,0,1), // back
4655                                                 v3s16(1,0,0), // right
4656                                                 v3s16(0,0,-1), // front
4657                                                 v3s16(-1,0,0), // left
4658                                         };
4659                                         for(u32 di=0; di<4; di++)
4660                                         {
4661                                                 v3s16 dirp = dirs4[di];
4662                                                 u32 i2 = i;
4663                                                 vmanip.m_area.add_p(em, i2, dirp);
4664                                                 MapNode *n2 = &vmanip.m_data[i2];
4665                                                 if(
4666                                                         n2->d != CONTENT_AIR
4667                                                         && n2->d != CONTENT_WATERSOURCE
4668                                                         && n2->d != CONTENT_WATER
4669                                                 ){
4670                                                         add_to_sources = true;
4671                                                         break;
4672                                                 }
4673                                         }
4674                                 }
4675                                 
4676                                 n->setLight(LIGHTBANK_DAY, light);
4677                                 n->setLight(LIGHTBANK_NIGHT, 0);
4678                                 
4679                                 // This doesn't take much time
4680                                 if(light != 0 && add_to_sources)
4681                                 {
4682                                         // Insert light source
4683                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
4684                                 }
4685                                 
4686                                 // Increment index by y
4687                                 vmanip.m_area.add_y(em, i, -1);
4688                         }
4689                 }
4690         }
4691 #endif
4692
4693         }//timer1
4694
4695         // Spread light around
4696         {
4697                 TimeTaker timer("generateChunkRaw() spreadLight");
4698                 vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
4699         }
4700         
4701         /*
4702                 Generation ended
4703         */
4704
4705         timer_generate.stop();
4706
4707         /*
4708                 Blit generated stuff to map
4709         */
4710         {
4711                 // 70ms @cs=8
4712                 //TimeTaker timer("generateChunkRaw() blitBackAll");
4713                 vmanip.blitBackAll(&changed_blocks);
4714         }
4715
4716         /*
4717                 Update day/night difference cache of the MapBlocks
4718         */
4719         {
4720                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
4721                                 i.atEnd() == false; i++)
4722                 {
4723                         MapBlock *block = i.getNode()->getValue();
4724                         block->updateDayNightDiff();
4725                 }
4726         }
4727 #endif
4728         
4729         /*
4730                 Create chunk metadata
4731         */
4732
4733         for(s16 x=-1; x<=1; x++)
4734         for(s16 y=-1; y<=1; y++)
4735         {
4736                 v2s16 chunkpos0 = chunkpos + v2s16(x,y);
4737                 // Add chunk meta information
4738                 MapChunk *chunk = getChunk(chunkpos0);
4739                 if(chunk == NULL)
4740                 {
4741                         chunk = new MapChunk();
4742                         m_chunks.insert(chunkpos0, chunk);
4743                 }
4744                 //chunk->setIsVolatile(true);
4745                 if(chunk->getGenLevel() > GENERATED_PARTLY)
4746                         chunk->setGenLevel(GENERATED_PARTLY);
4747         }
4748
4749         /*
4750                 Set central chunk non-volatile
4751         */
4752         MapChunk *chunk = getChunk(chunkpos);
4753         assert(chunk);
4754         // Set non-volatile
4755         //chunk->setIsVolatile(false);
4756         chunk->setGenLevel(GENERATED_FULLY);
4757         
4758         /*
4759                 Save changed parts of map
4760         */
4761         save(true);
4762
4763         /*
4764                 Return central chunk (which was requested)
4765         */
4766         return chunk;
4767 }
4768
4769
4770 MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
4771                 core::map<v3s16, MapBlock*> &changed_blocks)
4772 {
4773         dstream<<"generateChunk(): Generating chunk "
4774                         <<"("<<chunkpos1.X<<","<<chunkpos1.Y<<")"
4775                         <<std::endl;
4776         
4777         // Shall be not used now
4778         //assert(0);
4779         
4780         /*for(s16 x=-1; x<=1; x++)
4781         for(s16 y=-1; y<=1; y++)*/
4782         for(s16 x=-0; x<=0; x++)
4783         for(s16 y=-0; y<=0; y++)
4784         {
4785                 v2s16 chunkpos0 = chunkpos1 + v2s16(x,y);
4786                 MapChunk *chunk = getChunk(chunkpos0);
4787                 // Skip if already generated
4788                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
4789                         continue;
4790                 generateChunkRaw(chunkpos0, changed_blocks);
4791         }
4792         
4793         assert(chunkNonVolatile(chunkpos1));
4794
4795         MapChunk *chunk = getChunk(chunkpos1);
4796         return chunk;
4797 }
4798 #endif
4799
4800 ServerMapSector * ServerMap::createSector(v2s16 p2d)
4801 {
4802         DSTACK("%s: p2d=(%d,%d)",
4803                         __FUNCTION_NAME,
4804                         p2d.X, p2d.Y);
4805         
4806         /*
4807                 Check if it exists already in memory
4808         */
4809         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
4810         if(sector != NULL)
4811                 return sector;
4812         
4813         /*
4814                 Try to load it from disk (with blocks)
4815         */
4816         if(loadSectorFull(p2d) == true)
4817         {
4818                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
4819                 if(sector == NULL)
4820                 {
4821                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
4822                         throw InvalidPositionException("");
4823                 }
4824                 return sector;
4825         }
4826
4827         /*
4828                 Do not create over-limit
4829         */
4830         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4831         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4832         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4833         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4834                 throw InvalidPositionException("createSector(): pos. over limit");
4835
4836         /*
4837                 Generate blank sector
4838         */
4839         
4840         sector = new ServerMapSector(this, p2d);
4841         
4842         // Sector position on map in nodes
4843         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
4844
4845         /*
4846                 Insert to container
4847         */
4848         m_sectors.insert(p2d, sector);
4849         
4850         return sector;
4851 }
4852
4853 MapSector * ServerMap::emergeSector(v2s16 p2d,
4854                 core::map<v3s16, MapBlock*> &changed_blocks)
4855 {
4856         DSTACK("%s: p2d=(%d,%d)",
4857                         __FUNCTION_NAME,
4858                         p2d.X, p2d.Y);
4859
4860 #if 0
4861         /*
4862                 Check chunk status
4863         */
4864         v2s16 chunkpos = sector_to_chunk(p2d);
4865         /*bool chunk_nonvolatile = false;
4866         MapChunk *chunk = getChunk(chunkpos);
4867         if(chunk && chunk->getIsVolatile() == false)
4868                 chunk_nonvolatile = true;*/
4869         bool chunk_nonvolatile = chunkNonVolatile(chunkpos);
4870
4871         /*
4872                 If chunk is not fully generated, generate chunk
4873         */
4874         if(chunk_nonvolatile == false)
4875         {
4876                 // Generate chunk and neighbors
4877                 generateChunk(chunkpos, changed_blocks);
4878         }
4879 #endif
4880
4881         /*
4882                 Return sector if it exists now
4883         */
4884         MapSector *sector = getSectorNoGenerateNoEx(p2d);
4885         if(sector != NULL)
4886                 return sector;
4887         
4888         /*
4889                 Try to load it from disk
4890         */
4891         if(loadSectorFull(p2d) == true)
4892         {
4893                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
4894                 if(sector == NULL)
4895                 {
4896                         dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<<std::endl;
4897                         throw InvalidPositionException("");
4898                 }
4899                 return sector;
4900         }
4901
4902         /*
4903                 generateChunk should have generated the sector
4904         */
4905         //assert(0);
4906         
4907         dstream<<"WARNING: ServerMap::emergeSector: Cannot find sector ("
4908                         <<p2d.X<<","<<p2d.Y<<" and chunk is already generated. "
4909                         <<std::endl;
4910
4911 #if 0
4912         dstream<<"WARNING: Forcing regeneration of chunk."<<std::endl;
4913
4914         // Generate chunk
4915         generateChunkRaw(chunkpos, changed_blocks, true);
4916
4917         /*
4918                 Return sector if it exists now
4919         */
4920         sector = getSectorNoGenerateNoEx(p2d);
4921         if(sector != NULL)
4922                 return sector;
4923         
4924         dstream<<"ERROR: Could not get sector from anywhere."<<std::endl;
4925         
4926         //assert(0);
4927 #endif
4928         
4929 #if 1
4930         dstream<<"WARNING: Creating an empty sector."<<std::endl;
4931
4932         return createSector(p2d);
4933         
4934 #endif
4935         
4936         /*
4937                 Generate directly
4938         */
4939         //return generateSector();
4940 }
4941
4942 enum BlockType{
4943         BT_GROUND,
4944         BT_SURFACE,
4945         BT_SKY
4946 };
4947
4948 MapBlock* ServerMap::generateBlockRaw(v3s16 blockpos0,
4949                 core::map<v3s16, MapBlock*> &changed_blocks,
4950                 bool force)
4951 {
4952         DSTACK(__FUNCTION_NAME);
4953         
4954         /*
4955                 Don't generate if already fully generated
4956         */
4957         if(force == false)
4958         {
4959                 MapBlock *block = getBlockNoCreateNoEx(blockpos0);
4960                 if(block != NULL && block->isFullyGenerated())
4961                 {
4962                         dstream<<"generateBlockRaw(): Block "
4963                                         <<"("<<blockpos0.X<<","<<blockpos0.Y
4964                                         <<","<<blockpos0.Z<<")"
4965                                         <<" already generated (not forced)"<<std::endl;
4966                         return block;
4967                 }
4968         }
4969
4970         /*dstream<<"generateBlockRaw(): Generating block "
4971                         <<"("<<blockpos0.X<<","<<blockpos0.Y
4972                         <<","<<blockpos0.Z<<")"
4973                         <<std::endl;*/
4974         
4975         //TimeTaker timer("generateBlockRaw()");
4976
4977         /*
4978                 Calculate some simple values
4979         */
4980
4981         v2s16 sectorpos0(blockpos0.X, blockpos0.Z);
4982         
4983         /*
4984                 Fill in some variables for the code that was copied from
4985                 generateChunkRaw
4986         */
4987         s16 y_blocks_min = blockpos0.Y-1;
4988         s16 y_blocks_max = blockpos0.Y+1;
4989         s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
4990         s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
4991         v2s16 sectorpos_bigbase = sectorpos0 - v2s16(1,1);
4992         s16 sectorpos_bigbase_size = 3;
4993         v2s16 sectorpos_base = sectorpos0;
4994         s16 sectorpos_base_size = 1;
4995         s16 max_spread_amount = MAP_BLOCKSIZE;
4996         s16 lighting_min_d = 0-max_spread_amount;
4997         s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
4998         
4999         /*
5000                 Create the whole area of this and the neighboring blocks
5001         */
5002         
5003         core::list<v3s16> blocks_created;
5004
5005         {
5006                 //TimeTaker timer("generateBlockRaw() create area");
5007                 
5008                 for(s16 x=-1; x<=1; x++)
5009                 for(s16 z=-1; z<=1; z++)
5010                 {
5011                         v2s16 sectorpos = sectorpos0 + v2s16(x,z);
5012                         ServerMapSector *sector = createSector(sectorpos);
5013                         assert(sector);
5014
5015                         for(s16 y=blockpos0.Y-1; y<=blockpos0.Y+1; y++)
5016                         {
5017                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
5018
5019                                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
5020                                 if(block && block->isDummy() == false)
5021                                         continue;
5022                                         
5023                                 block = createBlock(blockpos);
5024                                 block->setFullyGenerated(false);
5025
5026                                 blocks_created.push_back(blockpos);
5027
5028                                 // Lighting won't be calculated
5029                                 block->setLightingExpired(true);
5030                                 // Lighting will be calculated
5031                                 //block->setLightingExpired(false);
5032
5033                                 /*
5034                                         Block gets sunlight if this is true.
5035
5036                                         This should be set to true when the top side of a block
5037                                         is completely exposed to the sky.
5038
5039                                         This doesn't matter if the initial lighting is done
5040                                         here.
5041                                 */
5042                                 //block->setIsUnderground(y != y_blocks_max);
5043                                 block->setIsUnderground(false);
5044                         }
5045                 }
5046         }
5047         
5048         /*
5049                 Now we have a big empty area of (16x16x16)x27.
5050
5051                 Make a ManualMapVoxelManipulator that contains the whole area.
5052         */
5053
5054         ManualMapVoxelManipulator vmanip(this);
5055         // Add the area we just generated
5056         {
5057                 //TimeTaker timer("generateBlockRaw() initialEmerge");
5058                 vmanip.initialEmerge(blockpos0-v3s16(1,1,1), blockpos0+v3s16(1,1,1));
5059         }
5060
5061         // Clear all flags
5062         vmanip.clearFlag(0xff);
5063
5064         // Block type of blockpos0
5065         BlockType center_block_type = BT_SURFACE;
5066
5067         /*
5068                 Generate general ground level to newly created blocks.
5069                 Only stone is used and it is converted to other stuff later on.
5070         */
5071         {
5072         // 22ms @cs=8
5073         //dstream<<"Generating base ground..."<<std::endl;
5074         //TimeTaker timer1("ground level");
5075         
5076         // Loop through created blocks
5077         for(core::list<v3s16>::Iterator i = blocks_created.begin();
5078                         i != blocks_created.end(); i++)
5079         {
5080                 v3s16 blockpos = *i;
5081                 v2s16 sectorpos(blockpos.X, blockpos.Z);
5082
5083                 /*
5084                         Approximate whether this block is a surface block, an air
5085                         block or a ground block.
5086
5087                         This shall never mark a surface block as non-surface.
5088                 */
5089                 
5090                 BlockType block_type = BT_SURFACE;
5091                 v3s16 p_nodes = blockpos * MAP_BLOCKSIZE;
5092                 s32 lowest_ground_y = 32767;
5093                 s32 highest_ground_y = -32768;
5094                 u8 water_material = CONTENT_WATERSOURCE;
5095
5096                 {
5097                         /*
5098                                 Estimate surface at different positions of the block, to
5099                                 try to accomodate the effect of turbulence.
5100                         */
5101                         v3f checklist[] = {
5102                                 v3f(0,0,0),
5103                                 v3f(0,1,0),
5104                                 v3f(0,1,1),
5105                                 v3f(0,0,1),
5106                                 v3f(1,0,0),
5107                                 v3f(1,1,0),
5108                                 v3f(1,1,1),
5109                                 v3f(1,0,1),
5110                                 v3f(0.5,0.5,0.5),
5111                         };
5112                         v3f p_nodes_f = intToFloat(p_nodes, 1);
5113                         float surface_y_max = -1000000;
5114                         float surface_y_min = 1000000;
5115                         for(u32 i=0; i<sizeof(checklist)/sizeof(checklist[0]); i++)
5116                         {
5117                                 v3f p_map_f = p_nodes_f + checklist[i]*MAP_BLOCKSIZE;
5118
5119                                 double depth_guess;
5120                                 /*bool is_ground =*/ is_base_ground(m_seed, p_map_f, &depth_guess);
5121                                 
5122                                 // Estimate the surface height
5123                                 float surface_y_f = p_map_f.Y + depth_guess;
5124
5125                                 if(surface_y_f > surface_y_max)
5126                                         surface_y_max = surface_y_f;
5127                                 if(surface_y_f < surface_y_min)
5128                                         surface_y_min = surface_y_f;
5129                         }
5130
5131                         float block_low_y_f = p_nodes_f.Y;
5132                         float block_high_y_f = p_nodes_f.Y + MAP_BLOCKSIZE;
5133
5134                         /*dstream<<"surface_y_max="<<surface_y_max
5135                                         <<", surface_y_min="<<surface_y_min
5136                                         <<", block_low_y_f="<<block_low_y_f
5137                                         <<", block_high_y_f="<<block_high_y_f
5138                                         <<std::endl;*/
5139                         
5140                         // A fuzzyness value
5141                         // Must accomodate mud and turbulence holes
5142                         float d_down = 16;
5143                         // Must accomodate a bit less
5144                         float d_up = 5;
5145
5146                         if(block_high_y_f < surface_y_min - d_down)
5147                         {
5148                                 //dstream<<"BT_GROUND"<<std::endl;
5149                                 // A ground block
5150                                 block_type = BT_GROUND;
5151                         }
5152                         else if(block_low_y_f >= surface_y_max + d_up
5153                                         && block_low_y_f > WATER_LEVEL + d_up)
5154                         {
5155                                 //dstream<<"BT_SKY"<<std::endl;
5156                                 // A sky block
5157                                 block_type = BT_SKY;
5158                         }
5159                         else
5160                         {
5161                                 //dstream<<"BT_SURFACE"<<std::endl;
5162                                 // A surface block
5163                                 block_type = BT_SURFACE;
5164                         }
5165
5166                         if(/*block_type == BT_GROUND ||*/ block_type == BT_SKY)
5167                         {
5168                                 lowest_ground_y = surface_y_min;
5169                                 highest_ground_y = surface_y_max;
5170                         }
5171                 }
5172                 
5173                 if(blockpos == blockpos0)
5174                         center_block_type = block_type;
5175
5176                 if(block_type == BT_GROUND)
5177                 {
5178                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
5179                         if(block)
5180                                 block->setIsUnderground(true);
5181                 }
5182
5183                 /*
5184                         If the block has ground, generate ground precisely.
5185                 */
5186                 
5187                 if(block_type == BT_SURFACE || block_type == BT_GROUND)
5188                 {
5189                         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
5190                         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
5191                         {
5192                                 v2s16 real_p2d = v2s16(x0,z0) + sectorpos*MAP_BLOCKSIZE;
5193
5194                                 v2f real_p2d_f(real_p2d.X,real_p2d.Y);
5195
5196                                 double tfxz = get_turbulence_factor_2d(m_seed, real_p2d_f);
5197                                 bool turbulence_is_used = (tfxz > 0.001);
5198
5199                                 float surface_y_f = 0;
5200                                 s16 surface_y = 0;
5201                                 
5202                                 float noturb_surface_y_f = base_rock_level_2d(m_seed, real_p2d_f);
5203                                 s16 noturb_surface_y = noturb_surface_y_f;
5204                                         
5205                                 // Get some statistics of surface height
5206                                 if(noturb_surface_y < lowest_ground_y)
5207                                         lowest_ground_y = noturb_surface_y;
5208                                 if(noturb_surface_y > highest_ground_y)
5209                                         highest_ground_y = noturb_surface_y;
5210
5211                                 // Use fast index incrementing
5212                                 v3s16 em = vmanip.m_area.getExtent();
5213                                 u32 i = vmanip.m_area.index(v3s16(
5214                                                 real_p2d.X,
5215                                                 blockpos.Y*MAP_BLOCKSIZE,
5216                                                 real_p2d.Y));
5217                                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
5218                                 {
5219                                         s16 real_y = blockpos.Y * MAP_BLOCKSIZE + y0;
5220                                         v3s16 real_pos = v3s16(x0,y0,z0) + p_nodes;
5221                                         MapNode n;
5222
5223                                         /*
5224                                                 Calculate material
5225                                         */
5226                                         
5227                                         bool is_ground = false;
5228                                         v3f real_pos_f = intToFloat(real_pos, 1);
5229                                         
5230                                         bool turb_for_node = (turbulence_is_used
5231                                                         && real_y >= TURBULENCE_BOTTOM_CUTOFF_Y);
5232
5233                                         bool is_cavern = false;
5234                                         
5235                                         if(is_carved(m_seed, real_pos_f))
5236                                         {
5237                                                 is_ground = false;
5238                                                 if(real_y < noturb_surface_y)
5239                                                         is_cavern = true;
5240                                         }
5241                                         else
5242                                         {
5243                                                 if(turb_for_node)
5244                                                 {
5245                                                         double depth_guess;
5246                                                         is_ground = is_base_ground(m_seed,
5247                                                                         real_pos_f, &depth_guess);
5248                                                         
5249                                                         // Estimate the surface height
5250                                                         surface_y_f = (float)real_y + depth_guess;
5251                                                         surface_y = real_y + depth_guess;
5252                                                         
5253                                                         // Save some statistics of surface height
5254                                                         if(surface_y < lowest_ground_y)
5255                                                                 lowest_ground_y = surface_y;
5256                                                         if(surface_y > highest_ground_y)
5257                                                                 highest_ground_y = surface_y;
5258                                                 }
5259                                                 else
5260                                                 {
5261                                                         surface_y = noturb_surface_y;
5262                                                 }
5263                                                 
5264                                                 is_ground = (real_y <= surface_y);
5265                                         }
5266
5267                                         // If node is not ground, it's air or water
5268                                         if(is_ground == false)
5269                                         {
5270                                                 // If under water level, it's water
5271                                                 if(real_y < WATER_LEVEL && !is_cavern)
5272                                                 {
5273                                                         n.d = water_material;
5274                                                         u8 dist = 16;
5275                                                         if(real_y >= surface_y)
5276                                                                 dist = WATER_LEVEL-real_y+1;
5277                                                         n.setLight(LIGHTBANK_DAY,
5278                                                                         diminish_light(LIGHT_SUN, dist));
5279                                                         /*
5280                                                                 Add to transforming liquid queue (in case it'd
5281                                                                 start flowing)
5282                                                         */
5283                                                         m_transforming_liquid.push_back(real_pos);
5284                                                 }
5285                                                 // else air
5286                                                 else
5287                                                 {
5288                                                         n.d = CONTENT_AIR;
5289                                                         
5290                                                         /*
5291                                                                 Guess lighting
5292                                                         */
5293                                                         if(real_y > surface_y + 4)
5294                                                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
5295                                                 }
5296                                         }
5297                                         // Else it's ground
5298                                         else
5299                                         {
5300                                                 if(is_underground_mud(m_seed, real_pos_f))
5301                                                         n.d = CONTENT_MUD;
5302                                                 else
5303                                                         n.d = CONTENT_STONE;
5304                                         }
5305
5306                                         vmanip.m_data[i] = n;
5307                                         vmanip.m_area.add_y(em, i, 1);
5308                                 }
5309                         }
5310                 }// BT_SURFACE
5311                 else // BT_SKY or anything else
5312                 {
5313                         MapNode n_fill;
5314                         if(block_type == BT_GROUND)
5315                         {
5316                                 //n_fill.d = CONTENT_STONE;
5317                         }
5318                         else if(block_type == BT_SKY)
5319                         {
5320                                 n_fill.d = CONTENT_AIR;
5321                                 n_fill.setLight(LIGHTBANK_DAY, LIGHT_SUN);
5322                         }
5323                         else // fallback
5324                         {
5325                                 n_fill.d = CONTENT_MESE;
5326                         }
5327
5328                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
5329                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
5330                         {
5331                                 // Node position
5332                                 v2s16 p2d = sectorpos*MAP_BLOCKSIZE + v2s16(x,z);
5333
5334                                 {
5335                                         // Use fast index incrementing
5336                                         v3s16 em = vmanip.m_area.getExtent();
5337                                         s16 min = blockpos.Y*MAP_BLOCKSIZE;
5338                                         s16 max = min + MAP_BLOCKSIZE-1;
5339                                         u32 i = vmanip.m_area.index(v3s16(p2d.X, min, p2d.Y));
5340                                         for(s16 y=min; y<=max; y++)
5341                                         {
5342                                                 vmanip.m_data[i] = n_fill;
5343                                                 vmanip.m_area.add_y(em, i, 1);
5344                                         }
5345                                 }
5346                         }
5347                 }
5348         }
5349
5350         }//timer1
5351
5352         /*
5353                 Convert surface ground to mud
5354         */
5355         
5356         if(center_block_type == BT_SURFACE)
5357         {
5358 #if 1
5359                 for(s16 x=0; x<MAP_BLOCKSIZE; x++)
5360                 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
5361                 {
5362                         // Node position
5363                         v2s16 p2d = sectorpos0*MAP_BLOCKSIZE + v2s16(x,z);
5364                         v2f real_p2d_f(p2d.X,p2d.Y);
5365                         
5366                         {
5367                                 // Use fast index incrementing
5368                                 v3s16 em = vmanip.m_area.getExtent();
5369                                 s16 min = blockpos0.Y*MAP_BLOCKSIZE;
5370                                 // Start from one above the central block
5371                                 s16 max = min + MAP_BLOCKSIZE-1+1;
5372                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, max, p2d.Y));
5373                                 // If stone, there won't be mud
5374                                 if(vmanip.m_data[i].d == CONTENT_STONE)
5375                                         continue;
5376                                 // Find top of ground
5377                                 bool found = false;
5378                                 s16 y;
5379                                 for(y=max; y>=min; y--)
5380                                 {
5381                                         if(vmanip.m_data[i].d == CONTENT_STONE)
5382                                         {
5383                                                 found = true;
5384                                                 break;
5385                                         }
5386                                         vmanip.m_area.add_y(em, i, -1);
5387                                 }
5388                                 if(found == false)
5389                                         continue;
5390                                 // Set mud
5391                                 s16 mud_amount = get_mud_amount(m_seed, real_p2d_f);
5392                                 for(s16 j=0; j<mud_amount; j++)
5393                                 {
5394                                         if(vmanip.m_data[i].d != CONTENT_STONE)
5395                                         {
5396                                                 break;
5397                                         }
5398                                         if(j==0 && y >= WATER_LEVEL)
5399                                                 vmanip.m_data[i].d = CONTENT_GRASS;
5400                                         else
5401                                                 vmanip.m_data[i].d = CONTENT_MUD;
5402                                         vmanip.m_area.add_y(em, i, -1);
5403                                 }
5404                         }
5405                 }
5406 #endif
5407         }
5408
5409         /*
5410                 Convert mud to sand
5411         */
5412         if(center_block_type == BT_SURFACE)
5413         {
5414                 for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
5415                 for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)
5416                 {
5417                         // Node position in 2d
5418                         v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
5419                         
5420                         // Determine whether to have sand here
5421                         bool have_sand = get_have_sand_coast(m_seed, v2f(p2d.X,p2d.Y));
5422
5423                         if(have_sand == false)
5424                                 continue;
5425
5426                         // Find ground level
5427                         s16 surface_y = find_ground_level_clever(vmanip, p2d);
5428                         
5429                         if(surface_y >= WATER_LEVEL + 2)
5430                                 continue;
5431
5432                         {
5433                                 v3s16 em = vmanip.m_area.getExtent();
5434                                 s16 y_start = surface_y;
5435                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
5436                                 u32 not_sand_counter = 0;
5437                                 for(s16 y=y_start; y>=y_nodes_min; y--)
5438                                 {
5439                                         MapNode *n = &vmanip.m_data[i];
5440                                         if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
5441                                         {
5442                                                 n->d = CONTENT_SAND;
5443                                         }
5444                                         else
5445                                         {
5446                                                 not_sand_counter++;
5447                                                 if(not_sand_counter > 3)
5448                                                         break;
5449                                         }
5450
5451                                         vmanip.m_area.add_y(em, i, -1);
5452                                 }
5453                         }
5454                 }
5455         }
5456
5457         /*
5458                 Add some minerals
5459         */
5460
5461         if(center_block_type == BT_SURFACE || center_block_type == BT_GROUND)
5462         {
5463                 s16 underground_level = 1 - blockpos0.Y;
5464
5465                 /*
5466                         Add meseblocks
5467                 */
5468                 for(s16 i=0; i<underground_level/4 + 1; i++)
5469                 {
5470                         if(myrand()%25 == 0)
5471                         {
5472                                 v3s16 cp(
5473                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
5474                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
5475                                         (myrand()%(MAP_BLOCKSIZE-2))+1
5476                                 );
5477                                 cp += blockpos0*MAP_BLOCKSIZE;
5478
5479                                 MapNode n;
5480                                 n.d = CONTENT_MESE;
5481                                 
5482                                 for(u16 i=0; i<27; i++)
5483                                 {
5484                                         if(vmanip.getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
5485                                                 if(myrand()%8 == 0)
5486                                                         vmanip.setNode(cp+g_27dirs[i], n);
5487                                 }
5488                         }
5489                 }
5490
5491                 /*
5492                         Add coal
5493                 */
5494                 u16 coal_amount = 60;
5495                 u16 coal_rareness = 120 / coal_amount;
5496                 if(coal_rareness == 0)
5497                         coal_rareness = 1;
5498                 if(myrand()%coal_rareness == 0)
5499                 {
5500                         u16 a = myrand() % 16;
5501                         u16 amount = coal_amount * a*a*a / 1000;
5502                         for(s16 i=0; i<amount; i++)
5503                         {
5504                                 v3s16 cp(
5505                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
5506                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
5507                                         (myrand()%(MAP_BLOCKSIZE-2))+1
5508                                 );
5509                                 cp += blockpos0*MAP_BLOCKSIZE;
5510
5511                                 MapNode n;
5512                                 n.d = CONTENT_STONE;
5513                                 n.param = MINERAL_COAL;
5514
5515                                 for(u16 i=0; i<27; i++)
5516                                 {
5517                                         if(vmanip.getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
5518                                                 if(myrand()%8 == 0)
5519                                                         vmanip.setNode(cp+g_27dirs[i], n);
5520                                 }
5521                         }
5522                 }
5523
5524                 /*
5525                         Add iron
5526                 */
5527                 u16 iron_amount = 40;
5528                 u16 iron_rareness = 80 / iron_amount;
5529                 if(iron_rareness == 0)
5530                         iron_rareness = 1;
5531                 if(myrand()%iron_rareness == 0)
5532                 {
5533                         u16 a = myrand() % 16;
5534                         u16 amount = iron_amount * a*a*a / 1000;
5535                         for(s16 i=0; i<amount; i++)
5536                         {
5537                                 v3s16 cp(
5538                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
5539                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
5540                                         (myrand()%(MAP_BLOCKSIZE-2))+1
5541                                 );
5542                                 cp += blockpos0*MAP_BLOCKSIZE;
5543
5544                                 MapNode n;
5545                                 n.d = CONTENT_STONE;
5546                                 n.param = MINERAL_IRON;
5547
5548                                 for(u16 i=0; i<27; i++)
5549                                 {
5550                                         if(vmanip.getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
5551                                                 if(myrand()%8 == 0)
5552                                                         vmanip.setNode(cp+g_27dirs[i], n);
5553                                 }
5554                         }
5555                 }
5556         }
5557         
5558
5559         /*
5560                 Generate some trees
5561         */
5562         if(center_block_type == BT_SURFACE)
5563         {
5564                 // Divide area into this amount of parts
5565                 s16 div = 1;
5566                 s16 sidelen = sectorpos_base_size*MAP_BLOCKSIZE / div;
5567                 double area = sidelen * sidelen;
5568                 for(s16 x0=0; x0<div; x0++)
5569                 for(s16 z0=0; z0<div; z0++)
5570                 {
5571                         // Center position of part of division
5572                         v2s16 p2d_center(
5573                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
5574                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
5575                         );
5576                         // Minimum edge of part of division
5577                         v2s16 p2d_min(
5578                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
5579                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
5580                         );
5581                         // Maximum edge of part of division
5582                         v2s16 p2d_max(
5583                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
5584                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
5585                         );
5586                         // Amount of trees
5587                         u32 tree_count = area * tree_amount_2d(m_seed, p2d_center);
5588                         // Put trees in random places on part of division
5589                         for(u32 i=0; i<tree_count; i++)
5590                         {
5591                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
5592                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
5593                                 s16 y = find_ground_level(vmanip, v2s16(x,z));
5594                                 // Don't make a tree under water level
5595                                 if(y < WATER_LEVEL)
5596                                         continue;
5597                                 // Don't make a tree in other blocks
5598                                 if(y < blockpos0.Y*MAP_BLOCKSIZE
5599                                                 || y >= (blockpos0.Y+1)*MAP_BLOCKSIZE)
5600                                         continue;
5601                                 v3s16 p(x,y,z);
5602                                 /*
5603                                         Trees grow only on mud and grass
5604                                 */
5605                                 {
5606                                         u32 i = vmanip.m_area.index(v3s16(p));
5607                                         MapNode *n = &vmanip.m_data[i];
5608                                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
5609                                                 continue;
5610                                 }
5611                                 p.Y++;
5612                                 // Make a tree
5613                                 make_tree(vmanip, p);
5614                         }
5615                 }
5616         }
5617
5618 #if 0
5619         /*
5620                 Initial lighting (sunlight)
5621                 TODO: Do the lighting this way, with the VoxelManipulator
5622         */
5623
5624         core::map<v3s16, bool> light_sources;
5625
5626         {
5627         // 750ms @cs=8, can't optimize more
5628         TimeTaker timer1("initial lighting");
5629         
5630         /*
5631                 Go through the edges and apply sunlight to them, not caring
5632                 about neighbors
5633         */
5634         
5635         // Four edges
5636         for(s16 i=0; i<4; i++)
5637         // Edge length
5638         for(s16 j=lighting_min_d;
5639                         j<=lighting_max_d;
5640                         j++)
5641         {
5642                 s16 x;
5643                 s16 z;
5644                 // +-X
5645                 if(i == 0 || i == 1)
5646                 {
5647                         x = (i==0) ? lighting_min_d : lighting_max_d;
5648                         if(i == 0)
5649                                 z = lighting_min_d;
5650                         else
5651                                 z = lighting_max_d;
5652                 }
5653                 // +-Z
5654                 else
5655                 {
5656                         z = (i==0) ? lighting_min_d : lighting_max_d;
5657                         if(i == 0)
5658                                 x = lighting_min_d;
5659                         else
5660                                 x = lighting_max_d;
5661                 }
5662                 
5663                 // Node position in 2d
5664                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
5665                 
5666                 // Loop from top to down
5667                 {
5668                         u8 light = LIGHT_SUN;
5669                         v3s16 em = vmanip.m_area.getExtent();
5670                         s16 y_start = y_nodes_max;
5671                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
5672                         for(s16 y=y_start; y>=y_nodes_min; y--)
5673                         {
5674                                 MapNode *n = &vmanip.m_data[i];
5675                                 if(light_propagates_content(n->d) == false)
5676                                 {
5677                                         light = 0;
5678                                 }
5679                                 else if(light != LIGHT_SUN
5680                                         || sunlight_propagates_content(n->d) == false)
5681                                 {
5682                                         if(light > 0)
5683                                                 light--;
5684                                 }
5685                                 
5686                                 n->setLight(LIGHTBANK_DAY, light);
5687                                 n->setLight(LIGHTBANK_NIGHT, 0);
5688                                 
5689                                 if(light != 0)
5690                                 {
5691                                         // Insert light source
5692                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
5693                                 }
5694                                 
5695                                 // Increment index by y
5696                                 vmanip.m_area.add_y(em, i, -1);
5697                         }
5698                 }
5699         }
5700
5701         /*
5702                 This has to be 1 smaller than the actual area, because
5703                 neighboring nodes are checked.
5704         */
5705         for(s16 x=lighting_min_d+1;
5706                         x<=lighting_max_d-1;
5707                         x++)
5708         for(s16 z=lighting_min_d+1;
5709                         z<=lighting_max_d-1;
5710                         z++)
5711         {
5712                 // Node position in 2d
5713                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
5714                 
5715                 /*
5716                         Apply initial sunlight
5717                 */
5718                 {
5719                         u8 light = LIGHT_SUN;
5720                         bool add_to_sources = false;
5721                         v3s16 em = vmanip.m_area.getExtent();
5722                         s16 y_start = y_nodes_max;
5723                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
5724                         for(s16 y=y_start; y>=y_nodes_min; y--)
5725                         {
5726                                 MapNode *n = &vmanip.m_data[i];
5727
5728                                 if(light_propagates_content(n->d) == false)
5729                                 {
5730                                         light = 0;
5731                                 }
5732                                 else if(light != LIGHT_SUN
5733                                         || sunlight_propagates_content(n->d) == false)
5734                                 {
5735                                         if(light > 0)
5736                                                 light--;
5737                                 }
5738                                 
5739                                 // This doesn't take much time
5740                                 if(add_to_sources == false)
5741                                 {
5742                                         /*
5743                                                 Check sides. If side is not air or water, start
5744                                                 adding to light_sources.
5745                                         */
5746                                         v3s16 dirs4[4] = {
5747                                                 v3s16(0,0,1), // back
5748                                                 v3s16(1,0,0), // right
5749                                                 v3s16(0,0,-1), // front
5750                                                 v3s16(-1,0,0), // left
5751                                         };
5752                                         for(u32 di=0; di<4; di++)
5753                                         {
5754                                                 v3s16 dirp = dirs4[di];
5755                                                 u32 i2 = i;
5756                                                 vmanip.m_area.add_p(em, i2, dirp);
5757                                                 MapNode *n2 = &vmanip.m_data[i2];
5758                                                 if(
5759                                                         n2->d != CONTENT_AIR
5760                                                         && n2->d != CONTENT_WATERSOURCE
5761                                                         && n2->d != CONTENT_WATER
5762                                                 ){
5763                                                         add_to_sources = true;
5764                                                         break;
5765                                                 }
5766                                         }
5767                                 }
5768                                 
5769                                 n->setLight(LIGHTBANK_DAY, light);
5770                                 n->setLight(LIGHTBANK_NIGHT, 0);
5771                                 
5772                                 // This doesn't take much time
5773                                 if(light != 0 && add_to_sources)
5774                                 {
5775                                         // Insert light source
5776                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
5777                                 }
5778                                 
5779                                 // Increment index by y
5780                                 vmanip.m_area.add_y(em, i, -1);
5781                         }
5782                 }
5783         }
5784
5785         }//timer1
5786
5787         // Spread light around
5788         {
5789                 TimeTaker timer("generateBlockRaw() spreadLight");
5790                 vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
5791         }
5792 #endif
5793
5794         /*
5795                 Blit generated stuff to map
5796         */
5797         {
5798                 vmanip.blitBackAll(&changed_blocks);
5799         }
5800
5801 #if 0
5802         /*
5803                 Update day/night difference cache of the MapBlocks
5804         */
5805         {
5806                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
5807                                 i.atEnd() == false; i++)
5808                 {
5809                         MapBlock *block = i.getNode()->getValue();
5810                         block->updateDayNightDiff();
5811                 }
5812         }
5813 #endif
5814
5815         /*for(core::map<v3s16, MapBlock*>::Iterator
5816                         i = changed_blocks*/
5817         
5818         // Done!
5819         MapBlock *block = getBlockNoCreate(blockpos0);
5820         block->setFullyGenerated(true);
5821         
5822         /*
5823                 TODO: Calculate lighting with the VoxelManipulator, not this way
5824         */
5825         // emergeBlock reads this
5826         block->setLightingExpired(true);
5827         // Also set the above one, trees often will be there
5828         {
5829                 MapBlock *block = getBlockNoCreate(blockpos0+v3s16(0,1,0));
5830                 if(block)
5831                         block->setLightingExpired(true);
5832         }
5833
5834         return block;
5835 }
5836
5837
5838 /*MapBlock* ServerMap::generateBlock(v3s16 blockpos1,
5839                 core::map<v3s16, MapBlock*> &changed_blocks)*/
5840 MapBlock * ServerMap::generateBlock(
5841                 v3s16 blockpos1,
5842                 MapBlock *original_dummy,
5843                 ServerMapSector *sector,
5844                 core::map<v3s16, MapBlock*> &changed_blocks,
5845                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
5846 )
5847 {
5848         dstream<<"generateBlock(): Generating block "
5849                         <<"("<<blockpos1.X<<","<<blockpos1.Y<<","<<blockpos1.Z<<")"
5850                         <<std::endl;
5851         
5852         /*
5853                 The block at blockpos1 should be generated fully, so that it won't
5854                 change in the future anymore when more stuff is generated.
5855
5856                 Now, a block can be generated with generateBlockRaw().
5857                 generateBlockRaw() accesses the block and all its neighbors.
5858                 Here is what generateBlockRaw() does:
5859                 - If the asked block has been marked fully generated, do nothing.
5860                 - Create the asked block and its neighbors and generate the base
5861                   ground in them (if they don't exist)
5862                 - In places where the ground level is in the asked block, convert
5863                   top layer of ground to mud or sand. Conversion is extended to
5864                   the block below as needed.
5865                 - Add trees and other objects to the asked block. Parts of them
5866                   can be located in the neighboring blocks.
5867                 - Mark the asked block as fully generated.
5868                 
5869                 This means the block and all its neighbors have to be generated to
5870                 obtain a block that won't change in the future.
5871         */
5872         for(s16 x=-1; x<=1; x++)
5873         for(s16 y=-1; y<=1; y++)
5874         for(s16 z=-1; z<=1; z++)
5875         {
5876                 v3s16 blockpos0 = blockpos1 + v3s16(x,y,z);
5877                 MapBlock *block = getBlockNoCreateNoEx(blockpos0);
5878                 // Skip if already generated
5879                 if(block != NULL && block->isFullyGenerated())
5880                         continue;
5881                 generateBlockRaw(blockpos0, changed_blocks);
5882         }
5883         
5884         assert(blockNonVolatile(blockpos1));
5885
5886         MapBlock *block = getBlockNoCreate(blockpos1);
5887         
5888         return block;
5889 }
5890
5891 #if 0
5892 /*
5893         NOTE: This is not used for main map generation, only for blocks
5894         that are very high or low.
5895         NOTE: Now it is used mainly. Might change in the future.
5896 */
5897 MapBlock * ServerMap::generateBlock(
5898                 v3s16 p,
5899                 MapBlock *original_dummy,
5900                 ServerMapSector *sector,
5901                 core::map<v3s16, MapBlock*> &changed_blocks,
5902                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
5903 )
5904 {
5905         DSTACK("%s: p=(%d,%d,%d)",
5906                         __FUNCTION_NAME,
5907                         p.X, p.Y, p.Z);
5908         
5909         /*dstream<<"generateBlock(): "
5910                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5911                         <<std::endl;*/
5912         
5913         MapBlock *block = original_dummy;
5914                         
5915         v2s16 p2d(p.X, p.Z);
5916         s16 block_y = p.Y;
5917         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
5918         v3s16 p_nodes = p * MAP_BLOCKSIZE;
5919         
5920         /*
5921                 Do not generate over-limit
5922         */
5923         if(blockpos_over_limit(p))
5924         {
5925                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
5926                 throw InvalidPositionException("generateBlock(): pos. over limit");
5927         }
5928
5929         /*
5930                 If block doesn't exist, create one.
5931                 If it exists, it is a dummy. In that case unDummify() it.
5932
5933                 NOTE: This already sets the map as the parent of the block
5934         */
5935         if(block == NULL)
5936         {
5937                 block = sector->createBlankBlockNoInsert(block_y);
5938         }
5939         else
5940         {
5941                 // Remove the block so that nobody can get a half-generated one.
5942                 sector->removeBlock(block);
5943                 // Allocate the block to contain the generated data
5944                 block->unDummify();
5945         }
5946         
5947         u8 water_material = CONTENT_WATERSOURCE;
5948         
5949         s32 lowest_ground_y = 32767;
5950         s32 highest_ground_y = -32768;
5951
5952         enum{
5953                 BT_GROUND,
5954                 BT_SURFACE,
5955                 BT_SKY
5956         } block_type = BT_SURFACE;
5957
5958         {// ground_timer (0ms or ~100ms)
5959         TimeTaker ground_timer("Ground generation");
5960
5961         /*
5962                 Approximate whether this block is a surface block, an air
5963                 block or a ground block.
5964
5965                 This shall never mark a surface block as non-surface.
5966         */
5967
5968         {
5969                 /*
5970                         Estimate surface at different positions of the block, to
5971                         try to accomodate the effect of turbulence.
5972                 */
5973                 v3f checklist[] = {
5974                         v3f(0,0,0),
5975                         v3f(0,1,0),
5976                         v3f(0,1,1),
5977                         v3f(0,0,1),
5978                         v3f(1,0,0),
5979                         v3f(1,1,0),
5980                         v3f(1,1,1),
5981                         v3f(1,0,1),
5982                         v3f(0.5,0.5,0.5),
5983                 };
5984                 v3f p_nodes_f = intToFloat(p_nodes, 1);
5985                 float surface_y_max = -1000000;
5986                 float surface_y_min = 1000000;
5987                 for(u32 i=0; i<sizeof(checklist)/sizeof(checklist[0]); i++)
5988                 {
5989                         v3f p_map_f = p_nodes_f + checklist[i]*MAP_BLOCKSIZE;
5990
5991                         double depth_guess;
5992                         /*bool is_ground =*/ is_base_ground(m_seed, p_map_f, &depth_guess);
5993                         
5994                         // Estimate the surface height
5995                         float surface_y_f = p_map_f.Y + depth_guess;
5996
5997                         if(surface_y_f > surface_y_max)
5998                                 surface_y_max = surface_y_f;
5999                         if(surface_y_f < surface_y_min)
6000                                 surface_y_min = surface_y_f;
6001                 }
6002
6003                 float block_low_y_f = p_nodes_f.Y;
6004                 float block_high_y_f = p_nodes_f.Y + MAP_BLOCKSIZE;
6005
6006                 /*dstream<<"surface_y_max="<<surface_y_max
6007                                 <<", surface_y_min="<<surface_y_min
6008                                 <<", block_low_y_f="<<block_low_y_f
6009                                 <<", block_high_y_f="<<block_high_y_f
6010                                 <<std::endl;*/
6011                 
6012                 // A fuzzyness value
6013                 // Must accomodate mud and turbulence holes
6014                 float d_down = 16;
6015                 // Must accomodate a bit less
6016                 float d_up = 5;
6017
6018                 if(block_high_y_f < surface_y_min - d_down)
6019                 {
6020                         //dstream<<"BT_GROUND"<<std::endl;
6021                         // A ground block
6022                         block_type = BT_GROUND;
6023                 }
6024                 else if(block_low_y_f >= surface_y_max + d_up
6025                                 && block_low_y_f > WATER_LEVEL + d_up)
6026                 {
6027                         //dstream<<"BT_SKY"<<std::endl;
6028                         // A sky block
6029                         block_type = BT_SKY;
6030                 }
6031                 else
6032                 {
6033                         //dstream<<"BT_SURFACE"<<std::endl;
6034                         // A surface block
6035                         block_type = BT_SURFACE;
6036                 }
6037
6038                 if(/*block_type == BT_GROUND ||*/ block_type == BT_SKY)
6039                 {
6040                         lowest_ground_y = surface_y_min;
6041                         highest_ground_y = surface_y_max;
6042                 }
6043         }
6044         
6045         if(block_type == BT_SURFACE || block_type == BT_GROUND)
6046         {
6047                 /*
6048                         Generate ground precisely
6049                 */
6050                 
6051                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
6052                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
6053                 {
6054                         //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
6055
6056                         //s16 surface_y = 0;
6057
6058                         /*s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
6059                                         + AVERAGE_MUD_AMOUNT;
6060
6061                         if(surface_y < lowest_ground_y)
6062                                 lowest_ground_y = surface_y;
6063                         if(surface_y > highest_ground_y)
6064                                 highest_ground_y = surface_y;*/
6065
6066                         v2s16 real_p2d = v2s16(x0,z0) + p2d*MAP_BLOCKSIZE;
6067
6068                         v2f real_p2d_f(real_p2d.X,real_p2d.Y);
6069
6070                         s16 surface_depth = get_mud_amount(m_seed, real_p2d_f);
6071
6072                         double tfxz = get_turbulence_factor_2d(m_seed, real_p2d_f);
6073                         bool turbulence_is_used = (tfxz > 0.001);
6074
6075                         float surface_y_f = 0;
6076                         s16 surface_y = 0;
6077                         
6078                         float noturb_surface_y_f = base_rock_level_2d(m_seed, real_p2d_f);
6079                         s16 noturb_surface_y = noturb_surface_y_f;
6080                                 
6081                         // Get some statistics of surface height
6082                         if(noturb_surface_y < lowest_ground_y)
6083                                 lowest_ground_y = noturb_surface_y;
6084                         if(noturb_surface_y > highest_ground_y)
6085                                 highest_ground_y = noturb_surface_y;
6086
6087                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
6088                         {
6089         #if 1
6090                                 s16 real_y = block_y * MAP_BLOCKSIZE + y0;
6091                                 v3s16 real_pos = v3s16(x0,y0,z0) + p_nodes;
6092                                 MapNode n;
6093                                 /*
6094                                         Calculate lighting
6095                                         
6096                                         NOTE: If there are some man-made structures above the
6097                                         newly created block, they won't be taken into account.
6098                                 */
6099                                 /*if(real_y > surface_y)
6100                                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);*/
6101
6102                                 /*
6103                                         Calculate material
6104                                 */
6105                                 
6106                                 bool is_ground = false;
6107                                 v3f real_pos_f = intToFloat(real_pos, 1);
6108                                 
6109                                 bool turb_for_node = (turbulence_is_used
6110                                                 && real_y >= TURBULENCE_BOTTOM_CUTOFF_Y);
6111
6112                                 bool is_cavern = false;
6113                                 
6114                                 if(is_carved(m_seed, real_pos_f))
6115                                 {
6116                                         is_ground = false;
6117                                         if(real_y < noturb_surface_y)
6118                                                 is_cavern = true;
6119                                 }
6120                                 else
6121                                 {
6122                                         if(turb_for_node)
6123                                         {
6124                                                 double depth_guess;
6125                                                 is_ground = is_base_ground(m_seed,
6126                                                                 real_pos_f, &depth_guess);
6127                                                 
6128                                                 // Estimate the surface height
6129                                                 surface_y_f = (float)real_y + depth_guess;
6130                                                 surface_y = real_y + depth_guess;
6131                                                 
6132                                                 // Get some statistics of surface height
6133                                                 if(surface_y < lowest_ground_y)
6134                                                         lowest_ground_y = surface_y;
6135                                                 if(surface_y > highest_ground_y)
6136                                                         highest_ground_y = surface_y;
6137                                         }
6138                                         else
6139                                         {
6140                                                 surface_y = noturb_surface_y;
6141                                         }
6142                                         
6143                                         is_ground = (real_y <= surface_y);
6144                                 }
6145
6146                                 // If node is not ground, it's air or water
6147                                 if(is_ground == false)
6148                                 {
6149                                         // If under water level, it's water
6150                                         if(real_y < WATER_LEVEL && !is_cavern)
6151                                         {
6152                                                 n.d = water_material;
6153                                                 u8 dist = 16;
6154                                                 if(real_y >= surface_y)
6155                                                         dist = WATER_LEVEL-real_y+1;
6156                                                 n.setLight(LIGHTBANK_DAY,
6157                                                                 diminish_light(LIGHT_SUN, dist));
6158                                                 /*
6159                                                         Add to transforming liquid queue (in case it'd
6160                                                         start flowing)
6161                                                 */
6162                                                 m_transforming_liquid.push_back(real_pos);
6163                                         }
6164                                         // else air
6165                                         else
6166                                                 n.d = CONTENT_AIR;
6167                                 }
6168                                 // Else it's ground or dungeons (air)
6169                                 else
6170                                 {
6171                                         // If it's surface_depth under ground, it's stone
6172                                         if((float)real_y <= surface_y_f - surface_depth - 0.75)
6173                                         {
6174                                                 if(is_underground_mud(m_seed, real_pos_f))
6175                                                         n.d = CONTENT_MUD;
6176                                                 else
6177                                                         n.d = CONTENT_STONE;
6178                                         }
6179                                         else if(surface_y_f <= WATER_LEVEL + 2.1
6180                                                         && get_have_sand_coast(m_seed, real_p2d_f))
6181                                         {
6182                                                 n.d = CONTENT_SAND;
6183                                         }
6184                                         else
6185                                         {
6186                                                 /*// It is mud if it is under the first ground
6187                                                 // level or under water
6188                                                 if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
6189                                                 {
6190                                                         n.d = CONTENT_MUD;
6191                                                 }
6192                                                 else
6193                                                 {
6194                                                         n.d = CONTENT_GRASS;
6195                                                 }*/
6196                                                 
6197                                                 if(get_have_sand_ground(m_seed, real_p2d_f))
6198                                                         n.d = CONTENT_SAND;
6199                                                 else
6200                                                         n.d = CONTENT_MUD;
6201                                                 
6202                                                 /*// If under water level, it's mud
6203                                                 if(real_y < WATER_LEVEL)
6204                                                         n.d = CONTENT_MUD;
6205                                                 // Only the topmost node is grass
6206                                                 else if(real_y <= surface_y - 1)
6207                                                         n.d = CONTENT_MUD;
6208                                                 else
6209                                                         n.d = CONTENT_GRASS;*/
6210                                         }
6211                                 }
6212
6213                                 block->setNode(v3s16(x0,y0,z0), n);
6214         #endif
6215         #if 0
6216                                 s16 real_y = block_y * MAP_BLOCKSIZE + y0;
6217                                 MapNode n;
6218                                 /*
6219                                         Calculate lighting
6220                                         
6221                                         NOTE: If there are some man-made structures above the
6222                                         newly created block, they won't be taken into account.
6223                                 */
6224                                 if(real_y > surface_y)
6225                                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
6226
6227                                 /*
6228                                         Calculate material
6229                                 */
6230
6231                                 // If node is over heightmap y, it's air or water
6232                                 if(real_y > surface_y)
6233                                 {
6234                                         // If under water level, it's water
6235                                         if(real_y < WATER_LEVEL)
6236                                         {
6237                                                 n.d = water_material;
6238                                                 n.setLight(LIGHTBANK_DAY,
6239                                                                 diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
6240                                                 /*
6241                                                         Add to transforming liquid queue (in case it'd
6242                                                         start flowing)
6243                                                 */
6244                                                 v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
6245                                                 m_transforming_liquid.push_back(real_pos);
6246                                         }
6247                                         // else air
6248                                         else
6249                                                 n.d = CONTENT_AIR;
6250                                 }
6251                                 // Else it's ground or dungeons (air)
6252                                 else
6253                                 {
6254                                         // If it's surface_depth under ground, it's stone
6255                                         if(real_y <= surface_y - surface_depth)
6256                                         {
6257                                                 n.d = CONTENT_STONE;
6258                                         }
6259                                         else
6260                                         {
6261                                                 // It is mud if it is under the first ground
6262                                                 // level or under water
6263                                                 if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
6264                                                 {
6265                                                         n.d = CONTENT_MUD;
6266                                                 }
6267                                                 else
6268                                                 {
6269                                                         n.d = CONTENT_GRASS;
6270                                                 }
6271
6272                                                 //n.d = CONTENT_MUD;
6273                                                 
6274                                                 /*// If under water level, it's mud
6275                                                 if(real_y < WATER_LEVEL)
6276                                                         n.d = CONTENT_MUD;
6277                                                 // Only the topmost node is grass
6278                                                 else if(real_y <= surface_y - 1)
6279                                                         n.d = CONTENT_MUD;
6280                                                 else
6281                                                         n.d = CONTENT_GRASS;*/
6282                                         }
6283                                 }
6284
6285                                 block->setNode(v3s16(x0,y0,z0), n);
6286         #endif
6287                         }
6288                 }
6289         }// BT_SURFACE
6290         else // BT_GROUND, BT_SKY or anything else
6291         {
6292                 MapNode n_fill;
6293                 if(block_type == BT_GROUND)
6294                 {
6295                         //n_fill.d = CONTENT_STONE;
6296                 }
6297                 else if(block_type == BT_SKY)
6298                 {
6299                         n_fill.d = CONTENT_AIR;
6300                         n_fill.setLight(LIGHTBANK_DAY, LIGHT_SUN);
6301                 }
6302                 else // fallback
6303                 {
6304                         n_fill.d = CONTENT_MESE;
6305                 }
6306
6307
6308                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
6309                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
6310                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
6311                 {
6312                         //MapNode n = block->getNode(v3s16(x0,y0,z0));
6313                         block->setNode(v3s16(x0,y0,z0), n_fill);
6314                 }
6315         }
6316         
6317         }// ground_timer
6318         
6319         /*
6320                 Calculate some helper variables
6321         */
6322         
6323         // Completely underground if the highest part of block is under lowest
6324         // ground height.
6325         // This has to be very sure; it's probably one too strict now but
6326         // that's just better.
6327         bool completely_underground =
6328                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
6329
6330         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
6331
6332         bool mostly_underwater_surface = false;
6333         if(highest_ground_y < WATER_LEVEL
6334                         && some_part_underground && !completely_underground)
6335                 mostly_underwater_surface = true;
6336
6337         /*
6338                 Get local attributes
6339         */
6340
6341         //dstream<<"generateBlock(): Getting local attributes"<<std::endl;
6342
6343         //float caves_amount = 0.5;
6344
6345 #if 0
6346         {
6347                 /*
6348                         NOTE: BEWARE: Too big amount of attribute points slows verything
6349                         down by a lot.
6350                         1 interpolation from 5000 points takes 2-3ms.
6351                 */
6352                 //TimeTaker timer("generateBlock() local attribute retrieval");
6353                 v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
6354                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
6355                 caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
6356         }
6357 #endif
6358
6359         //dstream<<"generateBlock(): Done"<<std::endl;
6360
6361 #if 0
6362         // Set to true if has caves.
6363         // Set when some non-air is changed to air when making caves.
6364         bool has_dungeons = false;
6365
6366         /*
6367                 Generate dungeons
6368         */
6369
6370         // Initialize temporary table
6371         const s32 ued = MAP_BLOCKSIZE;
6372         bool underground_emptiness[ued*ued*ued];
6373         for(s32 i=0; i<ued*ued*ued; i++)
6374         {
6375                 underground_emptiness[i] = 0;
6376         }
6377         
6378         // Fill table
6379 #if 0
6380         {
6381                 /*
6382                         Initialize orp and ors. Try to find if some neighboring
6383                         MapBlock has a tunnel ended in its side
6384                 */
6385
6386                 v3f orp(
6387                         (float)(myrand()%ued)+0.5,
6388                         (float)(myrand()%ued)+0.5,
6389                         (float)(myrand()%ued)+0.5
6390                 );
6391                 
6392                 bool found_existing = false;
6393
6394                 // Check z-
6395                 try
6396                 {
6397                         s16 z = -1;
6398                         for(s16 y=0; y<ued; y++)
6399                         for(s16 x=0; x<ued; x++)
6400                         {
6401                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
6402                                 if(getNode(ap).d == CONTENT_AIR)
6403                                 {
6404                                         orp = v3f(x+1,y+1,0);
6405                                         found_existing = true;
6406                                         goto continue_generating;
6407                                 }
6408                         }
6409                 }
6410                 catch(InvalidPositionException &e){}
6411                 
6412                 // Check z+
6413                 try
6414                 {
6415                         s16 z = ued;
6416                         for(s16 y=0; y<ued; y++)
6417                         for(s16 x=0; x<ued; x++)
6418                         {
6419                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
6420                                 if(getNode(ap).d == CONTENT_AIR)
6421                                 {
6422                                         orp = v3f(x+1,y+1,ued-1);
6423                                         found_existing = true;
6424                                         goto continue_generating;
6425                                 }
6426                         }
6427                 }
6428                 catch(InvalidPositionException &e){}
6429                 
6430                 // Check x-
6431                 try
6432                 {
6433                         s16 x = -1;
6434                         for(s16 y=0; y<ued; y++)
6435                         for(s16 z=0; z<ued; z++)
6436                         {
6437                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
6438                                 if(getNode(ap).d == CONTENT_AIR)
6439                                 {
6440                                         orp = v3f(0,y+1,z+1);
6441                                         found_existing = true;
6442                                         goto continue_generating;
6443                                 }
6444                         }
6445                 }
6446                 catch(InvalidPositionException &e){}
6447                 
6448                 // Check x+
6449                 try
6450                 {
6451                         s16 x = ued;
6452                         for(s16 y=0; y<ued; y++)
6453                         for(s16 z=0; z<ued; z++)
6454                         {
6455                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
6456                                 if(getNode(ap).d == CONTENT_AIR)
6457                                 {
6458                                         orp = v3f(ued-1,y+1,z+1);
6459                                         found_existing = true;
6460                                         goto continue_generating;
6461                                 }
6462                         }
6463                 }
6464                 catch(InvalidPositionException &e){}
6465
6466                 // Check y-
6467                 try
6468                 {
6469                         s16 y = -1;
6470                         for(s16 x=0; x<ued; x++)
6471                         for(s16 z=0; z<ued; z++)
6472                         {
6473                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
6474                                 if(getNode(ap).d == CONTENT_AIR)
6475                                 {
6476                                         orp = v3f(x+1,0,z+1);
6477                                         found_existing = true;
6478                                         goto continue_generating;
6479                                 }
6480                         }
6481                 }
6482                 catch(InvalidPositionException &e){}
6483                 
6484                 // Check y+
6485                 try
6486                 {
6487                         s16 y = ued;
6488                         for(s16 x=0; x<ued; x++)
6489                         for(s16 z=0; z<ued; z++)
6490                         {
6491                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
6492                                 if(getNode(ap).d == CONTENT_AIR)
6493                                 {
6494                                         orp = v3f(x+1,ued-1,z+1);
6495                                         found_existing = true;
6496                                         goto continue_generating;
6497                                 }
6498                         }
6499                 }
6500                 catch(InvalidPositionException &e){}
6501
6502 continue_generating:
6503                 
6504                 /*
6505                         Choose whether to actually generate dungeon
6506                 */
6507                 bool do_generate_dungeons = true;
6508                 // Don't generate if no part is underground
6509                 if(!some_part_underground)
6510                 {
6511                         do_generate_dungeons = false;
6512                 }
6513                 // Don't generate if mostly underwater surface
6514                 /*else if(mostly_underwater_surface)
6515                 {
6516                         do_generate_dungeons = false;
6517                 }*/
6518                 // Partly underground = cave
6519                 else if(!completely_underground)
6520                 {
6521                         //do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
6522                         do_generate_dungeons = false;
6523                 }
6524                 // Found existing dungeon underground
6525                 else if(found_existing && completely_underground)
6526                 {
6527                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
6528                 }
6529                 // Underground and no dungeons found
6530                 else
6531                 {
6532                         do_generate_dungeons = (rand() % 300 <= (s32)(caves_amount*100));
6533                 }
6534
6535                 if(do_generate_dungeons)
6536                 {
6537                         /*
6538                                 Generate some tunnel starting from orp and ors
6539                         */
6540                         for(u16 i=0; i<3; i++)
6541                         {
6542                                 v3f rp(
6543                                         (float)(myrand()%ued)+0.5,
6544                                         (float)(myrand()%ued)+0.5,
6545                                         (float)(myrand()%ued)+0.5
6546                                 );
6547                                 s16 min_d = 0;
6548                                 s16 max_d = 4;
6549                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
6550                                 
6551                                 v3f vec = rp - orp;
6552
6553                                 for(float f=0; f<1.0; f+=0.04)
6554                                 {
6555                                         v3f fp = orp + vec * f;
6556                                         v3s16 cp(fp.X, fp.Y, fp.Z);
6557                                         s16 d0 = -rs/2;
6558                                         s16 d1 = d0 + rs - 1;
6559                                         for(s16 z0=d0; z0<=d1; z0++)
6560                                         {
6561                                                 s16 si = rs - abs(z0);
6562                                                 for(s16 x0=-si; x0<=si-1; x0++)
6563                                                 {
6564                                                         s16 si2 = rs - abs(x0);
6565                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
6566                                                         {
6567                                                                 s16 z = cp.Z + z0;
6568                                                                 s16 y = cp.Y + y0;
6569                                                                 s16 x = cp.X + x0;
6570                                                                 v3s16 p(x,y,z);
6571                                                                 if(isInArea(p, ued) == false)
6572                                                                         continue;
6573                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
6574                                                         }
6575                                                 }
6576                                         }
6577                                 }
6578
6579                                 orp = rp;
6580                         }
6581                 }
6582         }
6583 #endif
6584
6585         /*
6586                 Apply temporary cave data to block
6587         */
6588
6589         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
6590         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
6591         {
6592                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
6593                 {
6594                         MapNode n = block->getNode(v3s16(x0,y0,z0));
6595
6596                         // Create dungeons
6597                         if(underground_emptiness[
6598                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
6599                                         +ued*(y0*ued/MAP_BLOCKSIZE)
6600                                         +(x0*ued/MAP_BLOCKSIZE)])
6601                         {
6602                                 if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
6603                                 {
6604                                         // Has now caves
6605                                         has_dungeons = true;
6606                                         // Set air to node
6607                                         n.d = CONTENT_AIR;
6608                                 }
6609                         }
6610
6611                         block->setNode(v3s16(x0,y0,z0), n);
6612                 }
6613         }
6614 #endif
6615         
6616         /*
6617                 This is used for guessing whether or not the block should
6618                 receive sunlight from the top if the block above doesn't exist
6619         */
6620         block->setIsUnderground(completely_underground);
6621
6622         /*
6623                 Force lighting update if some part of block is partly
6624                 underground and has caves.
6625         */
6626         /*if(some_part_underground && !completely_underground && has_dungeons)
6627         {
6628                 //dstream<<"Half-ground caves"<<std::endl;
6629                 lighting_invalidated_blocks[block->getPos()] = block;
6630         }*/
6631         
6632         // DEBUG: Always update lighting
6633         //lighting_invalidated_blocks[block->getPos()] = block;
6634
6635         /*
6636                 Add some minerals
6637         */
6638
6639         if(some_part_underground)
6640         {
6641                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
6642
6643                 /*
6644                         Add meseblocks
6645                 */
6646                 for(s16 i=0; i<underground_level/4 + 1; i++)
6647                 {
6648                         if(myrand()%50 == 0)
6649                         {
6650                                 v3s16 cp(
6651                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
6652                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
6653                                         (myrand()%(MAP_BLOCKSIZE-2))+1
6654                                 );
6655
6656                                 MapNode n;
6657                                 n.d = CONTENT_MESE;
6658                                 
6659                                 for(u16 i=0; i<27; i++)
6660                                 {
6661                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
6662                                                 if(myrand()%8 == 0)
6663                                                         block->setNode(cp+g_27dirs[i], n);
6664                                 }
6665                         }
6666                 }
6667
6668                 /*
6669                         Add coal
6670                 */
6671                 u16 coal_amount = 60;
6672                 u16 coal_rareness = 120 / coal_amount;
6673                 if(coal_rareness == 0)
6674                         coal_rareness = 1;
6675                 if(myrand()%coal_rareness == 0)
6676                 {
6677                         u16 a = myrand() % 16;
6678                         u16 amount = coal_amount * a*a*a / 1000;
6679                         for(s16 i=0; i<amount; i++)
6680                         {
6681                                 v3s16 cp(
6682                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
6683                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
6684                                         (myrand()%(MAP_BLOCKSIZE-2))+1
6685                                 );
6686
6687                                 MapNode n;
6688                                 n.d = CONTENT_STONE;
6689                                 n.param = MINERAL_COAL;
6690
6691                                 for(u16 i=0; i<27; i++)
6692                                 {
6693                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
6694                                                 if(myrand()%8 == 0)
6695                                                         block->setNode(cp+g_27dirs[i], n);
6696                                 }
6697                         }
6698                 }
6699
6700                 /*
6701                         Add iron
6702                 */
6703                 u16 iron_amount = 40;
6704                 u16 iron_rareness = 80 / iron_amount;
6705                 if(iron_rareness == 0)
6706                         iron_rareness = 1;
6707                 if(myrand()%iron_rareness == 0)
6708                 {
6709                         u16 a = myrand() % 16;
6710                         u16 amount = iron_amount * a*a*a / 1000;
6711                         for(s16 i=0; i<amount; i++)
6712                         {
6713                                 v3s16 cp(
6714                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
6715                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
6716                                         (myrand()%(MAP_BLOCKSIZE-2))+1
6717                                 );
6718
6719                                 MapNode n;
6720                                 n.d = CONTENT_STONE;
6721                                 n.param = MINERAL_IRON;
6722
6723                                 for(u16 i=0; i<27; i++)
6724                                 {
6725                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
6726                                                 if(myrand()%8 == 0)
6727                                                         block->setNode(cp+g_27dirs[i], n);
6728                                 }
6729                         }
6730                 }
6731         }
6732         
6733         /*
6734                 Create a few rats in empty blocks underground
6735         */
6736         if(completely_underground)
6737         {
6738                 //for(u16 i=0; i<2; i++)
6739                 {
6740                         v3s16 cp(
6741                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
6742                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
6743                                 (myrand()%(MAP_BLOCKSIZE-2))+1
6744                         );
6745
6746                         // Check that the place is empty
6747                         //if(!is_ground_content(block->getNode(cp).d))
6748                         if(1)
6749                         {
6750                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp, BS));
6751                                 block->addObject(obj);
6752                         }
6753                 }
6754         }
6755         
6756         /*
6757                 Add block to sector
6758         */
6759         sector->insertBlock(block);
6760         
6761         // Lighting is invalid after generation for surface blocks
6762         if(block_type == BT_SURFACE)
6763         {
6764 #if 1
6765                 block->setLightingExpired(true);
6766                 lighting_invalidated_blocks.insert(p, block);
6767 #else
6768                 block->setLightingExpired(false);
6769 #endif
6770         }
6771         // Lighting is not invalid for other blocks
6772         else
6773         {
6774                 block->setLightingExpired(false);
6775         }
6776
6777         /*
6778                 Add trees
6779         */
6780 #if 1
6781         if(some_part_underground && !completely_underground)
6782         {
6783                 MapVoxelManipulator vm(this);
6784                 
6785                 double a = tree_amount_2d(m_seed, v2s16(p_nodes.X+8, p_nodes.Z+8));
6786                 u16 tree_count = (u16)(a*MAP_BLOCKSIZE*MAP_BLOCKSIZE);
6787                 for(u16 i=0; i<tree_count/2; i++)
6788                 {
6789                         v3s16 tree_p = p_nodes + v3s16(
6790                                 myrand_range(0,MAP_BLOCKSIZE-1),
6791                                 8,
6792                                 myrand_range(0,MAP_BLOCKSIZE-1)
6793                         );
6794                         double depth_guess;
6795                         /*bool is_ground =*/ is_base_ground(m_seed,
6796                                         intToFloat(tree_p, 1), &depth_guess);
6797                         tree_p.Y += (depth_guess - 0.5);
6798                         if(tree_p.Y <= WATER_LEVEL)
6799                                 continue;
6800                         make_tree(vm, tree_p);
6801                 }
6802
6803                 vm.blitBack(changed_blocks);
6804         }
6805 #endif
6806         
6807 #if 0
6808         /*
6809                 Debug information
6810         */
6811         dstream
6812         <<"lighting_invalidated_blocks.size()"
6813         <<", has_dungeons"
6814         <<", completely_ug"
6815         <<", some_part_ug"
6816         <<"  "<<lighting_invalidated_blocks.size()
6817         <<", "<<has_dungeons
6818         <<", "<<completely_underground
6819         <<", "<<some_part_underground
6820         <<std::endl;
6821 #endif
6822
6823         return block;
6824 }
6825 #endif
6826
6827 MapBlock * ServerMap::createBlock(v3s16 p)
6828 {
6829         DSTACK("%s: p=(%d,%d,%d)",
6830                         __FUNCTION_NAME, p.X, p.Y, p.Z);
6831         
6832         /*
6833                 Do not create over-limit
6834         */
6835         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6836         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6837         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6838         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6839         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6840         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
6841                 throw InvalidPositionException("createBlock(): pos. over limit");
6842         
6843         v2s16 p2d(p.X, p.Z);
6844         s16 block_y = p.Y;
6845         /*
6846                 This will create or load a sector if not found in memory.
6847                 If block exists on disk, it will be loaded.
6848
6849                 NOTE: On old save formats, this will be slow, as it generates
6850                       lighting on blocks for them.
6851         */
6852         ServerMapSector *sector;
6853         try{
6854                 sector = (ServerMapSector*)createSector(p2d);
6855                 assert(sector->getId() == MAPSECTOR_SERVER);
6856         }
6857         catch(InvalidPositionException &e)
6858         {
6859                 dstream<<"createBlock: createSector() failed"<<std::endl;
6860                 throw e;
6861         }
6862         /*
6863                 NOTE: This should not be done, or at least the exception
6864                 should not be passed on as std::exception, because it
6865                 won't be catched at all.
6866         */
6867         /*catch(std::exception &e)
6868         {
6869                 dstream<<"createBlock: createSector() failed: "
6870                                 <<e.what()<<std::endl;
6871                 throw e;
6872         }*/
6873
6874         /*
6875                 Try to get a block from the sector
6876         */
6877
6878         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
6879         if(block)
6880                 return block;
6881         // Create blank
6882         block = sector->createBlankBlock(block_y);
6883         return block;
6884 }
6885
6886 MapBlock * ServerMap::emergeBlock(
6887                 v3s16 p,
6888                 bool only_from_disk,
6889                 core::map<v3s16, MapBlock*> &changed_blocks,
6890                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
6891 )
6892 {
6893         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
6894                         __FUNCTION_NAME,
6895                         p.X, p.Y, p.Z, only_from_disk);
6896         
6897         /*
6898                 Do not generate over-limit
6899         */
6900         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6901         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6902         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6903         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6904         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
6905         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
6906                 throw InvalidPositionException("emergeBlock(): pos. over limit");
6907         
6908         v2s16 p2d(p.X, p.Z);
6909         s16 block_y = p.Y;
6910         /*
6911                 This will create or load a sector if not found in memory.
6912                 If block exists on disk, it will be loaded.
6913         */
6914         ServerMapSector *sector;
6915         try{
6916                 sector = (ServerMapSector*)emergeSector(p2d, changed_blocks);
6917                 assert(sector->getId() == MAPSECTOR_SERVER);
6918         }
6919         catch(InvalidPositionException &e)
6920         {
6921                 dstream<<"emergeBlock: emergeSector() failed: "
6922                                 <<e.what()<<std::endl;
6923                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
6924                                 <<std::endl
6925                                 <<"You could try to delete it."<<std::endl;
6926                 throw e;
6927         }
6928         catch(VersionMismatchException &e)
6929         {
6930                 dstream<<"emergeBlock: emergeSector() failed: "
6931                                 <<e.what()<<std::endl;
6932                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
6933                                 <<std::endl
6934                                 <<"You could try to delete it."<<std::endl;
6935                 throw e;
6936         }
6937         /*
6938                 NOTE: This should not be done, or at least the exception
6939                 should not be passed on as std::exception, because it
6940                 won't be catched at all.
6941         */
6942         /*catch(std::exception &e)
6943         {
6944                 dstream<<"emergeBlock: emergeSector() failed: "
6945                                 <<e.what()<<std::endl;
6946                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
6947                                 <<std::endl
6948                                 <<"You could try to delete it."<<std::endl;
6949                 throw e;
6950         }*/
6951
6952         /*
6953                 Try to get a block from the sector
6954         */
6955
6956         bool does_not_exist = false;
6957         bool lighting_expired = false;
6958         bool half_generated = false;
6959         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
6960
6961         if(block == NULL)
6962         {
6963                 does_not_exist = true;
6964         }
6965         else if(block->isDummy() == true)
6966         {
6967                 does_not_exist = true;
6968         }
6969         else if(block->getLightingExpired())
6970         {
6971                 lighting_expired = true;
6972         }
6973         else if(block->isFullyGenerated() == false)
6974         {
6975                 half_generated = true;
6976         }
6977         else
6978         {
6979                 // Valid block
6980                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
6981                 return block;
6982         }
6983         
6984         if(half_generated == false)
6985         {
6986                 /*
6987                         If block was not found on disk and not going to generate a
6988                         new one, make sure there is a dummy block in place.
6989                 */
6990                 if(only_from_disk && (does_not_exist || lighting_expired))
6991                 {
6992                         //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
6993
6994                         if(block == NULL)
6995                         {
6996                                 // Create dummy block
6997                                 block = new MapBlock(this, p, true);
6998
6999                                 // Add block to sector
7000                                 sector->insertBlock(block);
7001                         }
7002                         // Done.
7003                         return block;
7004                 }
7005         }
7006
7007         //dstream<<"Not found on disk, generating."<<std::endl;
7008         // 0ms
7009         //TimeTaker("emergeBlock() generate");
7010
7011         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
7012
7013         /*
7014                 If the block doesn't exist, generate the block.
7015         */
7016         if(does_not_exist || half_generated)
7017         {
7018                 block = generateBlock(p, block, sector, changed_blocks,
7019                                 lighting_invalidated_blocks);
7020
7021                 lighting_expired = block->getLightingExpired();
7022         }
7023
7024         if(lighting_expired)
7025         {
7026                 lighting_invalidated_blocks.insert(p, block);
7027         }
7028
7029         /*
7030                 Initially update sunlight
7031         */
7032         
7033         if(lighting_expired)
7034         {
7035                 core::map<v3s16, bool> light_sources;
7036                 bool black_air_left = false;
7037                 bool bottom_invalid =
7038                                 block->propagateSunlight(light_sources, true,
7039                                 &black_air_left, true);
7040
7041                 // If sunlight didn't reach everywhere and part of block is
7042                 // above ground, lighting has to be properly updated
7043                 //if(black_air_left && some_part_underground)
7044                 if(black_air_left)
7045                 {
7046                         lighting_invalidated_blocks[block->getPos()] = block;
7047                 }
7048
7049                 if(bottom_invalid)
7050                 {
7051                         lighting_invalidated_blocks[block->getPos()] = block;
7052                 }
7053         }
7054         
7055         return block;
7056 }
7057
7058 s16 ServerMap::findGroundLevel(v2s16 p2d)
7059 {
7060         /*
7061                 Uh, just do something random...
7062         */
7063         // Find existing map from top to down
7064         s16 max=63;
7065         s16 min=-64;
7066         v3s16 p(p2d.X, max, p2d.Y);
7067         for(; p.Y>min; p.Y--)
7068         {
7069                 MapNode n = getNodeNoEx(p);
7070                 if(n.d != CONTENT_IGNORE)
7071                         break;
7072         }
7073         if(p.Y == min)
7074                 goto plan_b;
7075         // If this node is not air, go to plan b
7076         if(getNodeNoEx(p).d != CONTENT_AIR)
7077                 goto plan_b;
7078         // Search existing walkable and return it
7079         for(; p.Y>min; p.Y--)
7080         {
7081                 MapNode n = getNodeNoEx(p);
7082                 if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
7083                         return p.Y;
7084         }
7085         // Move to plan b
7086 plan_b:
7087         /*
7088                 Plan B: Get from map generator perlin noise function
7089         */
7090         double level = base_rock_level_2d(m_seed, p2d);
7091         return (s16)level;
7092 }
7093
7094 void ServerMap::createDir(std::string path)
7095 {
7096         if(fs::CreateDir(path) == false)
7097         {
7098                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
7099                                 <<"\""<<path<<"\""<<std::endl;
7100                 throw BaseException("ServerMap failed to create directory");
7101         }
7102 }
7103
7104 std::string ServerMap::getSectorSubDir(v2s16 pos)
7105 {
7106         char cc[9];
7107         snprintf(cc, 9, "%.4x%.4x",
7108                         (unsigned int)pos.X&0xffff,
7109                         (unsigned int)pos.Y&0xffff);
7110
7111         return std::string(cc);
7112 }
7113
7114 std::string ServerMap::getSectorDir(v2s16 pos)
7115 {
7116         return m_savedir + "/sectors/" + getSectorSubDir(pos);
7117 }
7118
7119 v2s16 ServerMap::getSectorPos(std::string dirname)
7120 {
7121         if(dirname.size() != 8)
7122                 throw InvalidFilenameException("Invalid sector directory name");
7123         unsigned int x, y;
7124         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
7125         if(r != 2)
7126                 throw InvalidFilenameException("Invalid sector directory name");
7127         v2s16 pos((s16)x, (s16)y);
7128         return pos;
7129 }
7130
7131 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
7132 {
7133         v2s16 p2d = getSectorPos(sectordir);
7134
7135         if(blockfile.size() != 4){
7136                 throw InvalidFilenameException("Invalid block filename");
7137         }
7138         unsigned int y;
7139         int r = sscanf(blockfile.c_str(), "%4x", &y);
7140         if(r != 1)
7141                 throw InvalidFilenameException("Invalid block filename");
7142         return v3s16(p2d.X, y, p2d.Y);
7143 }
7144
7145 void ServerMap::save(bool only_changed)
7146 {
7147         DSTACK(__FUNCTION_NAME);
7148         if(m_map_saving_enabled == false)
7149         {
7150                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
7151                 return;
7152         }
7153         
7154         if(only_changed == false)
7155                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
7156                                 <<std::endl;
7157         
7158         saveMapMeta();
7159         //saveChunkMeta();
7160         
7161         u32 sector_meta_count = 0;
7162         u32 block_count = 0;
7163         
7164         { //sectorlock
7165         JMutexAutoLock lock(m_sector_mutex);
7166         
7167         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
7168         for(; i.atEnd() == false; i++)
7169         {
7170                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
7171                 assert(sector->getId() == MAPSECTOR_SERVER);
7172         
7173                 if(sector->differs_from_disk || only_changed == false)
7174                 {
7175                         saveSectorMeta(sector);
7176                         sector_meta_count++;
7177                 }
7178                 core::list<MapBlock*> blocks;
7179                 sector->getBlocks(blocks);
7180                 core::list<MapBlock*>::Iterator j;
7181                 for(j=blocks.begin(); j!=blocks.end(); j++)
7182                 {
7183                         MapBlock *block = *j;
7184                         if(block->getChangedFlag() || only_changed == false)
7185                         {
7186                                 saveBlock(block);
7187                                 block_count++;
7188
7189                                 /*dstream<<"ServerMap: Written block ("
7190                                                 <<block->getPos().X<<","
7191                                                 <<block->getPos().Y<<","
7192                                                 <<block->getPos().Z<<")"
7193                                                 <<std::endl;*/
7194                         }
7195                 }
7196         }
7197
7198         }//sectorlock
7199         
7200         /*
7201                 Only print if something happened or saved whole map
7202         */
7203         if(only_changed == false || sector_meta_count != 0
7204                         || block_count != 0)
7205         {
7206                 dstream<<DTIME<<"ServerMap: Written: "
7207                                 <<sector_meta_count<<" sector metadata files, "
7208                                 <<block_count<<" block files"
7209                                 <<std::endl;
7210         }
7211 }
7212
7213 void ServerMap::loadAll()
7214 {
7215         DSTACK(__FUNCTION_NAME);
7216         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
7217         
7218         loadMapMeta();
7219         //loadChunkMeta();
7220
7221         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
7222
7223         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
7224         
7225         JMutexAutoLock lock(m_sector_mutex);
7226         
7227         s32 counter = 0;
7228         s32 printed_counter = -100000;
7229         s32 count = list.size();
7230
7231         std::vector<fs::DirListNode>::iterator i;
7232         for(i=list.begin(); i!=list.end(); i++)
7233         {
7234                 if(counter > printed_counter + 10)
7235                 {
7236                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
7237                         printed_counter = counter;
7238                 }
7239                 counter++;
7240
7241                 MapSector *sector = NULL;
7242
7243                 // We want directories
7244                 if(i->dir == false)
7245                         continue;
7246                 try{
7247                         sector = loadSectorMeta(i->name);
7248                 }
7249                 catch(InvalidFilenameException &e)
7250                 {
7251                         // This catches unknown crap in directory
7252                 }
7253                 
7254                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
7255                                 (m_savedir+"/sectors/"+i->name);
7256                 std::vector<fs::DirListNode>::iterator i2;
7257                 for(i2=list2.begin(); i2!=list2.end(); i2++)
7258                 {
7259                         // We want files
7260                         if(i2->dir)
7261                                 continue;
7262                         try{
7263                                 loadBlock(i->name, i2->name, sector);
7264                         }
7265                         catch(InvalidFilenameException &e)
7266                         {
7267                                 // This catches unknown crap in directory
7268                         }
7269                 }
7270         }
7271         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
7272 }
7273
7274 #if 0
7275 void ServerMap::saveMasterHeightmap()
7276 {
7277         DSTACK(__FUNCTION_NAME);
7278         
7279         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
7280
7281         createDir(m_savedir);
7282         
7283         /*std::string fullpath = m_savedir + "/master_heightmap";
7284         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
7285         if(o.good() == false)
7286                 throw FileNotGoodException("Cannot open master heightmap");*/
7287         
7288         // Format used for writing
7289         //u8 version = SER_FMT_VER_HIGHEST;
7290 }
7291
7292 void ServerMap::loadMasterHeightmap()
7293 {
7294         DSTACK(__FUNCTION_NAME);
7295         
7296         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
7297
7298         /*std::string fullpath = m_savedir + "/master_heightmap";
7299         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
7300         if(is.good() == false)
7301                 throw FileNotGoodException("Cannot open master heightmap");*/
7302 }
7303 #endif
7304
7305 void ServerMap::saveMapMeta()
7306 {
7307         DSTACK(__FUNCTION_NAME);
7308         
7309         dstream<<"INFO: ServerMap::saveMapMeta(): "
7310                         <<"seed="<<m_seed
7311                         /*<<", chunksize="<<m_chunksize*/
7312                         <<std::endl;
7313
7314         createDir(m_savedir);
7315         
7316         std::string fullpath = m_savedir + "/map_meta.txt";
7317         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
7318         if(os.good() == false)
7319         {
7320                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
7321                                 <<"could not open"<<fullpath<<std::endl;
7322                 throw FileNotGoodException("Cannot open chunk metadata");
7323         }
7324         
7325         Settings params;
7326         params.setU64("seed", m_seed);
7327         //params.setS32("chunksize", m_chunksize);
7328
7329         params.writeLines(os);
7330
7331         os<<"[end_of_params]\n";
7332         
7333 }
7334
7335 void ServerMap::loadMapMeta()
7336 {
7337         DSTACK(__FUNCTION_NAME);
7338         
7339         dstream<<"INFO: ServerMap::loadMapMeta(): Loading chunk metadata"
7340                         <<std::endl;
7341
7342         std::string fullpath = m_savedir + "/map_meta.txt";
7343         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
7344         if(is.good() == false)
7345         {
7346                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
7347                                 <<"could not open"<<fullpath<<std::endl;
7348                 throw FileNotGoodException("Cannot open chunk metadata");
7349         }
7350
7351         Settings params;
7352
7353         for(;;)
7354         {
7355                 if(is.eof())
7356                         throw SerializationError
7357                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
7358                 std::string line;
7359                 std::getline(is, line);
7360                 std::string trimmedline = trim(line);
7361                 if(trimmedline == "[end_of_params]")
7362                         break;
7363                 params.parseConfigLine(line);
7364         }
7365
7366         m_seed = params.getU64("seed");
7367         //m_chunksize = params.getS32("chunksize");
7368
7369         dstream<<"INFO: ServerMap::loadMapMeta(): "
7370                         <<"seed="<<m_seed
7371                         /*<<", chunksize="<<m_chunksize*/
7372                         <<std::endl;
7373 }
7374
7375 #if 0
7376 void ServerMap::saveChunkMeta()
7377 {
7378         DSTACK(__FUNCTION_NAME);
7379         
7380         u32 count = m_chunks.size();
7381
7382         dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
7383                         <<count<<" chunks"<<std::endl;
7384
7385         createDir(m_savedir);
7386         
7387         std::string fullpath = m_savedir + "/chunk_meta";
7388         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
7389         if(os.good() == false)
7390         {
7391                 dstream<<"ERROR: ServerMap::saveChunkMeta(): "
7392                                 <<"could not open"<<fullpath<<std::endl;
7393                 throw FileNotGoodException("Cannot open chunk metadata");
7394         }
7395         
7396         u8 version = 0;
7397         
7398         // Write version
7399         os.write((char*)&version, 1);
7400
7401         u8 buf[4];
7402         
7403         // Write count
7404         writeU32(buf, count);
7405         os.write((char*)buf, 4);
7406         
7407         for(core::map<v2s16, MapChunk*>::Iterator
7408                         i = m_chunks.getIterator();
7409                         i.atEnd()==false; i++)
7410         {
7411                 v2s16 p = i.getNode()->getKey();
7412                 MapChunk *chunk = i.getNode()->getValue();
7413                 // Write position
7414                 writeV2S16(buf, p);
7415                 os.write((char*)buf, 4);
7416                 // Write chunk data
7417                 chunk->serialize(os, version);
7418         }
7419 }
7420
7421 void ServerMap::loadChunkMeta()
7422 {
7423         DSTACK(__FUNCTION_NAME);
7424         
7425         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading chunk metadata"
7426                         <<std::endl;
7427
7428         std::string fullpath = m_savedir + "/chunk_meta";
7429         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
7430         if(is.good() == false)
7431         {
7432                 dstream<<"ERROR: ServerMap::loadChunkMeta(): "
7433                                 <<"could not open"<<fullpath<<std::endl;
7434                 throw FileNotGoodException("Cannot open chunk metadata");
7435         }
7436
7437         u8 version = 0;
7438         
7439         // Read version
7440         is.read((char*)&version, 1);
7441
7442         u8 buf[4];
7443         
7444         // Read count
7445         is.read((char*)buf, 4);
7446         u32 count = readU32(buf);
7447
7448         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading metadata of "
7449                         <<count<<" chunks"<<std::endl;
7450         
7451         for(u32 i=0; i<count; i++)
7452         {
7453                 v2s16 p;
7454                 MapChunk *chunk = new MapChunk();
7455                 // Read position
7456                 is.read((char*)buf, 4);
7457                 p = readV2S16(buf);
7458                 // Read chunk data
7459                 chunk->deSerialize(is, version);
7460                 m_chunks.insert(p, chunk);
7461         }
7462 }
7463 #endif
7464
7465 void ServerMap::saveSectorMeta(ServerMapSector *sector)
7466 {
7467         DSTACK(__FUNCTION_NAME);
7468         // Format used for writing
7469         u8 version = SER_FMT_VER_HIGHEST;
7470         // Get destination
7471         v2s16 pos = sector->getPos();
7472         createDir(m_savedir);
7473         createDir(m_savedir+"/sectors");
7474         std::string dir = getSectorDir(pos);
7475         createDir(dir);
7476         
7477         std::string fullpath = dir + "/meta";
7478         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
7479         if(o.good() == false)
7480                 throw FileNotGoodException("Cannot open sector metafile");
7481
7482         sector->serialize(o, version);
7483         
7484         sector->differs_from_disk = false;
7485 }
7486
7487 MapSector* ServerMap::loadSectorMeta(std::string dirname)
7488 {
7489         DSTACK(__FUNCTION_NAME);
7490         // Get destination
7491         v2s16 p2d = getSectorPos(dirname);
7492         std::string dir = m_savedir + "/sectors/" + dirname;
7493         
7494         std::string fullpath = dir + "/meta";
7495         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
7496         if(is.good() == false)
7497                 throw FileNotGoodException("Cannot open sector metafile");
7498
7499         ServerMapSector *sector = ServerMapSector::deSerialize
7500                         (is, this, p2d, m_sectors);
7501         
7502         sector->differs_from_disk = false;
7503
7504         return sector;
7505 }
7506
7507 bool ServerMap::loadSectorFull(v2s16 p2d)
7508 {
7509         DSTACK(__FUNCTION_NAME);
7510         std::string sectorsubdir = getSectorSubDir(p2d);
7511
7512         MapSector *sector = NULL;
7513
7514         JMutexAutoLock lock(m_sector_mutex);
7515
7516         try{
7517                 sector = loadSectorMeta(sectorsubdir);
7518         }
7519         catch(InvalidFilenameException &e)
7520         {
7521                 return false;
7522         }
7523         catch(FileNotGoodException &e)
7524         {
7525                 return false;
7526         }
7527         catch(std::exception &e)
7528         {
7529                 return false;
7530         }
7531         
7532         /*
7533                 Load blocks
7534         */
7535         std::vector<fs::DirListNode> list2 = fs::GetDirListing
7536                         (m_savedir+"/sectors/"+sectorsubdir);
7537         std::vector<fs::DirListNode>::iterator i2;
7538         for(i2=list2.begin(); i2!=list2.end(); i2++)
7539         {
7540                 // We want files
7541                 if(i2->dir)
7542                         continue;
7543                 try{
7544                         loadBlock(sectorsubdir, i2->name, sector);
7545                 }
7546                 catch(InvalidFilenameException &e)
7547                 {
7548                         // This catches unknown crap in directory
7549                 }
7550         }
7551         return true;
7552 }
7553
7554 void ServerMap::saveBlock(MapBlock *block)
7555 {
7556         DSTACK(__FUNCTION_NAME);
7557         /*
7558                 Dummy blocks are not written
7559         */
7560         if(block->isDummy())
7561         {
7562                 /*v3s16 p = block->getPos();
7563                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
7564                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
7565                 return;
7566         }
7567
7568         // Format used for writing
7569         u8 version = SER_FMT_VER_HIGHEST;
7570         // Get destination
7571         v3s16 p3d = block->getPos();
7572         v2s16 p2d(p3d.X, p3d.Z);
7573         createDir(m_savedir);
7574         createDir(m_savedir+"/sectors");
7575         std::string dir = getSectorDir(p2d);
7576         createDir(dir);
7577         
7578         // Block file is map/sectors/xxxxxxxx/xxxx
7579         char cc[5];
7580         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
7581         std::string fullpath = dir + "/" + cc;
7582         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
7583         if(o.good() == false)
7584                 throw FileNotGoodException("Cannot open block data");
7585
7586         /*
7587                 [0] u8 serialization version
7588                 [1] data
7589         */
7590         o.write((char*)&version, 1);
7591         
7592         block->serialize(o, version);
7593
7594         /*
7595                 Versions up from 9 have block objects.
7596         */
7597         if(version >= 9)
7598         {
7599                 block->serializeObjects(o, version);
7600         }
7601         
7602         // We just wrote it to the disk
7603         block->resetChangedFlag();
7604 }
7605
7606 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
7607 {
7608         DSTACK(__FUNCTION_NAME);
7609
7610         try{
7611
7612                 // Block file is map/sectors/xxxxxxxx/xxxx
7613                 std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
7614                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
7615                 if(is.good() == false)
7616                         throw FileNotGoodException("Cannot open block file");
7617
7618                 v3s16 p3d = getBlockPos(sectordir, blockfile);
7619                 v2s16 p2d(p3d.X, p3d.Z);
7620                 
7621                 assert(sector->getPos() == p2d);
7622                 
7623                 u8 version = SER_FMT_VER_INVALID;
7624                 is.read((char*)&version, 1);
7625
7626                 if(is.fail())
7627                         throw SerializationError("ServerMap::loadBlock(): Failed"
7628                                         " to read MapBlock version");
7629
7630                 /*u32 block_size = MapBlock::serializedLength(version);
7631                 SharedBuffer<u8> data(block_size);
7632                 is.read((char*)*data, block_size);*/
7633
7634                 // This will always return a sector because we're the server
7635                 //MapSector *sector = emergeSector(p2d);
7636
7637                 MapBlock *block = NULL;
7638                 bool created_new = false;
7639                 try{
7640                         block = sector->getBlockNoCreate(p3d.Y);
7641                 }
7642                 catch(InvalidPositionException &e)
7643                 {
7644                         block = sector->createBlankBlockNoInsert(p3d.Y);
7645                         created_new = true;
7646                 }
7647                 
7648                 // deserialize block data
7649                 block->deSerialize(is, version);
7650                 
7651                 /*
7652                         Versions up from 9 have block objects.
7653                 */
7654                 if(version >= 9)
7655                 {
7656                         block->updateObjects(is, version, NULL, 0);
7657                 }
7658
7659                 if(created_new)
7660                         sector->insertBlock(block);
7661                 
7662                 /*
7663                         Convert old formats to new and save
7664                 */
7665
7666                 // Save old format blocks in new format
7667                 if(version < SER_FMT_VER_HIGHEST)
7668                 {
7669                         saveBlock(block);
7670                 }
7671                 
7672                 // We just loaded it from the disk, so it's up-to-date.
7673                 block->resetChangedFlag();
7674
7675         }
7676         catch(SerializationError &e)
7677         {
7678                 dstream<<"WARNING: Invalid block data on disk "
7679                                 "(SerializationError). Ignoring. "
7680                                 "A new one will be generated."
7681                                 <<std::endl;
7682         }
7683 }
7684
7685 void ServerMap::PrintInfo(std::ostream &out)
7686 {
7687         out<<"ServerMap: ";
7688 }
7689
7690 #ifndef SERVER
7691
7692 /*
7693         ClientMap
7694 */
7695
7696 ClientMap::ClientMap(
7697                 Client *client,
7698                 MapDrawControl &control,
7699                 scene::ISceneNode* parent,
7700                 scene::ISceneManager* mgr,
7701                 s32 id
7702 ):
7703         Map(dout_client),
7704         scene::ISceneNode(parent, mgr, id),
7705         m_client(client),
7706         m_control(control),
7707         m_camera_position(0,0,0),
7708         m_camera_direction(0,0,1)
7709 {
7710         m_camera_mutex.Init();
7711         assert(m_camera_mutex.IsInitialized());
7712         
7713         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
7714                         BS*1000000,BS*1000000,BS*1000000);
7715 }
7716
7717 ClientMap::~ClientMap()
7718 {
7719         /*JMutexAutoLock lock(mesh_mutex);
7720         
7721         if(mesh != NULL)
7722         {
7723                 mesh->drop();
7724                 mesh = NULL;
7725         }*/
7726 }
7727
7728 MapSector * ClientMap::emergeSector(v2s16 p2d)
7729 {
7730         DSTACK(__FUNCTION_NAME);
7731         // Check that it doesn't exist already
7732         try{
7733                 return getSectorNoGenerate(p2d);
7734         }
7735         catch(InvalidPositionException &e)
7736         {
7737         }
7738         
7739         // Create a sector
7740         ClientMapSector *sector = new ClientMapSector(this, p2d);
7741         
7742         {
7743                 JMutexAutoLock lock(m_sector_mutex);
7744                 m_sectors.insert(p2d, sector);
7745         }
7746         
7747         return sector;
7748 }
7749
7750 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
7751 {
7752         DSTACK(__FUNCTION_NAME);
7753         ClientMapSector *sector = NULL;
7754
7755         JMutexAutoLock lock(m_sector_mutex);
7756         
7757         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
7758
7759         if(n != NULL)
7760         {
7761                 sector = (ClientMapSector*)n->getValue();
7762                 assert(sector->getId() == MAPSECTOR_CLIENT);
7763         }
7764         else
7765         {
7766                 sector = new ClientMapSector(this, p2d);
7767                 {
7768                         JMutexAutoLock lock(m_sector_mutex);
7769                         m_sectors.insert(p2d, sector);
7770                 }
7771         }
7772
7773         sector->deSerialize(is);
7774 }
7775
7776 void ClientMap::OnRegisterSceneNode()
7777 {
7778         if(IsVisible)
7779         {
7780                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
7781                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
7782         }
7783
7784         ISceneNode::OnRegisterSceneNode();
7785 }
7786
7787 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
7788 {
7789         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
7790         DSTACK(__FUNCTION_NAME);
7791
7792         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
7793
7794         /*
7795                 Get time for measuring timeout.
7796                 
7797                 Measuring time is very useful for long delays when the
7798                 machine is swapping a lot.
7799         */
7800         int time1 = time(0);
7801
7802         u32 daynight_ratio = m_client->getDayNightRatio();
7803
7804         m_camera_mutex.Lock();
7805         v3f camera_position = m_camera_position;
7806         v3f camera_direction = m_camera_direction;
7807         m_camera_mutex.Unlock();
7808
7809         /*
7810                 Get all blocks and draw all visible ones
7811         */
7812
7813         v3s16 cam_pos_nodes(
7814                         camera_position.X / BS,
7815                         camera_position.Y / BS,
7816                         camera_position.Z / BS);
7817
7818         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
7819
7820         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
7821         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
7822
7823         // Take a fair amount as we will be dropping more out later
7824         v3s16 p_blocks_min(
7825                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
7826                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
7827                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
7828         v3s16 p_blocks_max(
7829                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
7830                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
7831                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
7832         
7833         u32 vertex_count = 0;
7834         
7835         // For limiting number of mesh updates per frame
7836         u32 mesh_update_count = 0;
7837         
7838         u32 blocks_would_have_drawn = 0;
7839         u32 blocks_drawn = 0;
7840
7841         //NOTE: The sectors map should be locked but we're not doing it
7842         // because it'd cause too much delays
7843
7844         int timecheck_counter = 0;
7845         core::map<v2s16, MapSector*>::Iterator si;
7846         si = m_sectors.getIterator();
7847         for(; si.atEnd() == false; si++)
7848         {
7849                 {
7850                         timecheck_counter++;
7851                         if(timecheck_counter > 50)
7852                         {
7853                                 timecheck_counter = 0;
7854                                 int time2 = time(0);
7855                                 if(time2 > time1 + 4)
7856                                 {
7857                                         dstream<<"ClientMap::renderMap(): "
7858                                                 "Rendering takes ages, returning."
7859                                                 <<std::endl;
7860                                         return;
7861                                 }
7862                         }
7863                 }
7864
7865                 MapSector *sector = si.getNode()->getValue();
7866                 v2s16 sp = sector->getPos();
7867                 
7868                 if(m_control.range_all == false)
7869                 {
7870                         if(sp.X < p_blocks_min.X
7871                         || sp.X > p_blocks_max.X
7872                         || sp.Y < p_blocks_min.Z
7873                         || sp.Y > p_blocks_max.Z)
7874                                 continue;
7875                 }
7876
7877                 core::list< MapBlock * > sectorblocks;
7878                 sector->getBlocks(sectorblocks);
7879                 
7880                 /*
7881                         Draw blocks
7882                 */
7883
7884                 core::list< MapBlock * >::Iterator i;
7885                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
7886                 {
7887                         MapBlock *block = *i;
7888
7889                         /*
7890                                 Compare block position to camera position, skip
7891                                 if not seen on display
7892                         */
7893                         
7894                         float range = 100000 * BS;
7895                         if(m_control.range_all == false)
7896                                 range = m_control.wanted_range * BS;
7897                         
7898                         float d = 0.0;
7899                         if(isBlockInSight(block->getPos(), camera_position,
7900                                         camera_direction, range, &d) == false)
7901                         {
7902                                 continue;
7903                         }
7904                         
7905                         // This is ugly
7906                         /*if(m_control.range_all == false &&
7907                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
7908                                 continue;*/
7909
7910 #if 1
7911                         /*
7912                                 Update expired mesh (used for day/night change)
7913                         */
7914
7915                         bool mesh_expired = false;
7916                         
7917                         {
7918                                 JMutexAutoLock lock(block->mesh_mutex);
7919
7920                                 mesh_expired = block->getMeshExpired();
7921
7922                                 // Mesh has not been expired and there is no mesh:
7923                                 // block has no content
7924                                 if(block->mesh == NULL && mesh_expired == false)
7925                                         continue;
7926                         }
7927
7928                         f32 faraway = BS*50;
7929                         //f32 faraway = m_control.wanted_range * BS;
7930                         
7931                         /*
7932                                 This has to be done with the mesh_mutex unlocked
7933                         */
7934                         // Pretty random but this should work somewhat nicely
7935                         if(mesh_expired && (
7936                                         (mesh_update_count < 3
7937                                                 && (d < faraway || mesh_update_count < 2)
7938                                         )
7939                                         || 
7940                                         (m_control.range_all && mesh_update_count < 20)
7941                                 )
7942                         )
7943                         /*if(mesh_expired && mesh_update_count < 6
7944                                         && (d < faraway || mesh_update_count < 3))*/
7945                         {
7946                                 mesh_update_count++;
7947
7948                                 // Mesh has been expired: generate new mesh
7949                                 //block->updateMeshes(daynight_i);
7950                                 block->updateMesh(daynight_ratio);
7951
7952                                 mesh_expired = false;
7953                         }
7954                         
7955                         /*
7956                                 Don't draw an expired mesh that is far away
7957                         */
7958                         /*if(mesh_expired && d >= faraway)
7959                         //if(mesh_expired)
7960                         {
7961                                 // Instead, delete it
7962                                 JMutexAutoLock lock(block->mesh_mutex);
7963                                 if(block->mesh)
7964                                 {
7965                                         block->mesh->drop();
7966                                         block->mesh = NULL;
7967                                 }
7968                                 // And continue to next block
7969                                 continue;
7970                         }*/
7971 #endif
7972                         /*
7973                                 Draw the faces of the block
7974                         */
7975                         {
7976                                 JMutexAutoLock lock(block->mesh_mutex);
7977
7978                                 scene::SMesh *mesh = block->mesh;
7979
7980                                 if(mesh == NULL)
7981                                         continue;
7982                                 
7983                                 blocks_would_have_drawn++;
7984                                 if(blocks_drawn >= m_control.wanted_max_blocks
7985                                                 && m_control.range_all == false
7986                                                 && d > m_control.wanted_min_range * BS)
7987                                         continue;
7988                                 blocks_drawn++;
7989
7990                                 u32 c = mesh->getMeshBufferCount();
7991
7992                                 for(u32 i=0; i<c; i++)
7993                                 {
7994                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
7995                                         const video::SMaterial& material = buf->getMaterial();
7996                                         video::IMaterialRenderer* rnd =
7997                                                         driver->getMaterialRenderer(material.MaterialType);
7998                                         bool transparent = (rnd && rnd->isTransparent());
7999                                         // Render transparent on transparent pass and likewise.
8000                                         if(transparent == is_transparent_pass)
8001                                         {
8002                                                 /*
8003                                                         This *shouldn't* hurt too much because Irrlicht
8004                                                         doesn't change opengl textures if the old
8005                                                         material is set again.
8006                                                 */
8007                                                 driver->setMaterial(buf->getMaterial());
8008                                                 driver->drawMeshBuffer(buf);
8009                                                 vertex_count += buf->getVertexCount();
8010                                         }
8011                                 }
8012                         }
8013                 } // foreach sectorblocks
8014         }
8015         
8016         m_control.blocks_drawn = blocks_drawn;
8017         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
8018
8019         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
8020                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
8021 }
8022
8023 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
8024                 core::map<v3s16, MapBlock*> *affected_blocks)
8025 {
8026         bool changed = false;
8027         /*
8028                 Add it to all blocks touching it
8029         */
8030         v3s16 dirs[7] = {
8031                 v3s16(0,0,0), // this
8032                 v3s16(0,0,1), // back
8033                 v3s16(0,1,0), // top
8034                 v3s16(1,0,0), // right
8035                 v3s16(0,0,-1), // front
8036                 v3s16(0,-1,0), // bottom
8037                 v3s16(-1,0,0), // left
8038         };
8039         for(u16 i=0; i<7; i++)
8040         {
8041                 v3s16 p2 = p + dirs[i];
8042                 // Block position of neighbor (or requested) node
8043                 v3s16 blockpos = getNodeBlockPos(p2);
8044                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
8045                 if(blockref == NULL)
8046                         continue;
8047                 // Relative position of requested node
8048                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
8049                 if(blockref->setTempMod(relpos, mod))
8050                 {
8051                         changed = true;
8052                 }
8053         }
8054         if(changed && affected_blocks!=NULL)
8055         {
8056                 for(u16 i=0; i<7; i++)
8057                 {
8058                         v3s16 p2 = p + dirs[i];
8059                         // Block position of neighbor (or requested) node
8060                         v3s16 blockpos = getNodeBlockPos(p2);
8061                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
8062                         if(blockref == NULL)
8063                                 continue;
8064                         affected_blocks->insert(blockpos, blockref);
8065                 }
8066         }
8067         return changed;
8068 }
8069
8070 bool ClientMap::clearTempMod(v3s16 p,
8071                 core::map<v3s16, MapBlock*> *affected_blocks)
8072 {
8073         bool changed = false;
8074         v3s16 dirs[7] = {
8075                 v3s16(0,0,0), // this
8076                 v3s16(0,0,1), // back
8077                 v3s16(0,1,0), // top
8078                 v3s16(1,0,0), // right
8079                 v3s16(0,0,-1), // front
8080                 v3s16(0,-1,0), // bottom
8081                 v3s16(-1,0,0), // left
8082         };
8083         for(u16 i=0; i<7; i++)
8084         {
8085                 v3s16 p2 = p + dirs[i];
8086                 // Block position of neighbor (or requested) node
8087                 v3s16 blockpos = getNodeBlockPos(p2);
8088                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
8089                 if(blockref == NULL)
8090                         continue;
8091                 // Relative position of requested node
8092                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
8093                 if(blockref->clearTempMod(relpos))
8094                 {
8095                         changed = true;
8096                 }
8097         }
8098         if(changed && affected_blocks!=NULL)
8099         {
8100                 for(u16 i=0; i<7; i++)
8101                 {
8102                         v3s16 p2 = p + dirs[i];
8103                         // Block position of neighbor (or requested) node
8104                         v3s16 blockpos = getNodeBlockPos(p2);
8105                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
8106                         if(blockref == NULL)
8107                                 continue;
8108                         affected_blocks->insert(blockpos, blockref);
8109                 }
8110         }
8111         return changed;
8112 }
8113
8114 void ClientMap::expireMeshes(bool only_daynight_diffed)
8115 {
8116         TimeTaker timer("expireMeshes()");
8117
8118         core::map<v2s16, MapSector*>::Iterator si;
8119         si = m_sectors.getIterator();
8120         for(; si.atEnd() == false; si++)
8121         {
8122                 MapSector *sector = si.getNode()->getValue();
8123
8124                 core::list< MapBlock * > sectorblocks;
8125                 sector->getBlocks(sectorblocks);
8126                 
8127                 core::list< MapBlock * >::Iterator i;
8128                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
8129                 {
8130                         MapBlock *block = *i;
8131
8132                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
8133                         {
8134                                 continue;
8135                         }
8136                         
8137                         {
8138                                 JMutexAutoLock lock(block->mesh_mutex);
8139                                 if(block->mesh != NULL)
8140                                 {
8141                                         /*block->mesh->drop();
8142                                         block->mesh = NULL;*/
8143                                         block->setMeshExpired(true);
8144                                 }
8145                         }
8146                 }
8147         }
8148 }
8149
8150 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
8151 {
8152         try{
8153                 v3s16 p = blockpos + v3s16(0,0,0);
8154                 MapBlock *b = getBlockNoCreate(p);
8155                 b->updateMesh(daynight_ratio);
8156         }
8157         catch(InvalidPositionException &e){}
8158         // Leading edge
8159         try{
8160                 v3s16 p = blockpos + v3s16(-1,0,0);
8161                 MapBlock *b = getBlockNoCreate(p);
8162                 b->updateMesh(daynight_ratio);
8163         }
8164         catch(InvalidPositionException &e){}
8165         try{
8166                 v3s16 p = blockpos + v3s16(0,-1,0);
8167                 MapBlock *b = getBlockNoCreate(p);
8168                 b->updateMesh(daynight_ratio);
8169         }
8170         catch(InvalidPositionException &e){}
8171         try{
8172                 v3s16 p = blockpos + v3s16(0,0,-1);
8173                 MapBlock *b = getBlockNoCreate(p);
8174                 b->updateMesh(daynight_ratio);
8175         }
8176         catch(InvalidPositionException &e){}
8177 }
8178
8179 /*
8180         Update mesh of block in which the node is, and if the node is at the
8181         leading edge, update the appropriate leading blocks too.
8182 */
8183 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
8184 {
8185         v3s16 dirs[4] = {
8186                 v3s16(0,0,0),
8187                 v3s16(-1,0,0),
8188                 v3s16(0,-1,0),
8189                 v3s16(0,0,-1),
8190         };
8191         v3s16 blockposes[4];
8192         for(u32 i=0; i<4; i++)
8193         {
8194                 v3s16 np = nodepos + dirs[i];
8195                 blockposes[i] = getNodeBlockPos(np);
8196                 // Don't update mesh of block if it has been done already
8197                 bool already_updated = false;
8198                 for(u32 j=0; j<i; j++)
8199                 {
8200                         if(blockposes[j] == blockposes[i])
8201                         {
8202                                 already_updated = true;
8203                                 break;
8204                         }
8205                 }
8206                 if(already_updated)
8207                         continue;
8208                 // Update mesh
8209                 MapBlock *b = getBlockNoCreate(blockposes[i]);
8210                 b->updateMesh(daynight_ratio);
8211         }
8212 }
8213
8214 void ClientMap::PrintInfo(std::ostream &out)
8215 {
8216         out<<"ClientMap: ";
8217 }
8218
8219 #endif // !SERVER
8220
8221 /*
8222         MapVoxelManipulator
8223 */
8224
8225 MapVoxelManipulator::MapVoxelManipulator(Map *map)
8226 {
8227         m_map = map;
8228 }
8229
8230 MapVoxelManipulator::~MapVoxelManipulator()
8231 {
8232         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
8233                         <<std::endl;*/
8234 }
8235
8236 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
8237 {
8238         TimeTaker timer1("emerge", &emerge_time);
8239
8240         // Units of these are MapBlocks
8241         v3s16 p_min = getNodeBlockPos(a.MinEdge);
8242         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
8243
8244         VoxelArea block_area_nodes
8245                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
8246
8247         addArea(block_area_nodes);
8248
8249         for(s32 z=p_min.Z; z<=p_max.Z; z++)
8250         for(s32 y=p_min.Y; y<=p_max.Y; y++)
8251         for(s32 x=p_min.X; x<=p_max.X; x++)
8252         {
8253                 v3s16 p(x,y,z);
8254                 core::map<v3s16, bool>::Node *n;
8255                 n = m_loaded_blocks.find(p);
8256                 if(n != NULL)
8257                         continue;
8258                 
8259                 bool block_data_inexistent = false;
8260                 try
8261                 {
8262                         TimeTaker timer1("emerge load", &emerge_load_time);
8263
8264                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
8265                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
8266                                         <<" wanted area: ";
8267                         a.print(dstream);
8268                         dstream<<std::endl;*/
8269                         
8270                         MapBlock *block = m_map->getBlockNoCreate(p);
8271                         if(block->isDummy())
8272                                 block_data_inexistent = true;
8273                         else
8274                                 block->copyTo(*this);
8275                 }
8276                 catch(InvalidPositionException &e)
8277                 {
8278                         block_data_inexistent = true;
8279                 }
8280
8281                 if(block_data_inexistent)
8282                 {
8283                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
8284                         // Fill with VOXELFLAG_INEXISTENT
8285                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
8286                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
8287                         {
8288                                 s32 i = m_area.index(a.MinEdge.X,y,z);
8289                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
8290                         }
8291                 }
8292
8293                 m_loaded_blocks.insert(p, !block_data_inexistent);
8294         }
8295
8296         //dstream<<"emerge done"<<std::endl;
8297 }
8298
8299 /*
8300         SUGG: Add an option to only update eg. water and air nodes.
8301               This will make it interfere less with important stuff if
8302                   run on background.
8303 */
8304 void MapVoxelManipulator::blitBack
8305                 (core::map<v3s16, MapBlock*> & modified_blocks)
8306 {
8307         if(m_area.getExtent() == v3s16(0,0,0))
8308                 return;
8309         
8310         //TimeTaker timer1("blitBack");
8311
8312         /*dstream<<"blitBack(): m_loaded_blocks.size()="
8313                         <<m_loaded_blocks.size()<<std::endl;*/
8314         
8315         /*
8316                 Initialize block cache
8317         */
8318         v3s16 blockpos_last;
8319         MapBlock *block = NULL;
8320         bool block_checked_in_modified = false;
8321
8322         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
8323         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
8324         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
8325         {
8326                 v3s16 p(x,y,z);
8327
8328                 u8 f = m_flags[m_area.index(p)];
8329                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
8330                         continue;
8331
8332                 MapNode &n = m_data[m_area.index(p)];
8333                         
8334                 v3s16 blockpos = getNodeBlockPos(p);
8335                 
8336                 try
8337                 {
8338                         // Get block
8339                         if(block == NULL || blockpos != blockpos_last){
8340                                 block = m_map->getBlockNoCreate(blockpos);
8341                                 blockpos_last = blockpos;
8342                                 block_checked_in_modified = false;
8343                         }
8344                         
8345                         // Calculate relative position in block
8346                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
8347
8348                         // Don't continue if nothing has changed here
8349                         if(block->getNode(relpos) == n)
8350                                 continue;
8351
8352                         //m_map->setNode(m_area.MinEdge + p, n);
8353                         block->setNode(relpos, n);
8354                         
8355                         /*
8356                                 Make sure block is in modified_blocks
8357                         */
8358                         if(block_checked_in_modified == false)
8359                         {
8360                                 modified_blocks[blockpos] = block;
8361                                 block_checked_in_modified = true;
8362                         }
8363                 }
8364                 catch(InvalidPositionException &e)
8365                 {
8366                 }
8367         }
8368 }
8369
8370 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
8371                 MapVoxelManipulator(map)
8372 {
8373 }
8374
8375 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
8376 {
8377 }
8378
8379 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
8380 {
8381         // Just create the area so that it can be pointed to
8382         VoxelManipulator::emerge(a, caller_id);
8383 }
8384
8385 void ManualMapVoxelManipulator::initialEmerge(
8386                 v3s16 blockpos_min, v3s16 blockpos_max)
8387 {
8388         TimeTaker timer1("initialEmerge", &emerge_time);
8389
8390         // Units of these are MapBlocks
8391         v3s16 p_min = blockpos_min;
8392         v3s16 p_max = blockpos_max;
8393
8394         VoxelArea block_area_nodes
8395                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
8396         
8397         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
8398         if(size_MB >= 1)
8399         {
8400                 dstream<<"initialEmerge: area: ";
8401                 block_area_nodes.print(dstream);
8402                 dstream<<" ("<<size_MB<<"MB)";
8403                 dstream<<std::endl;
8404         }
8405
8406         addArea(block_area_nodes);
8407
8408         for(s32 z=p_min.Z; z<=p_max.Z; z++)
8409         for(s32 y=p_min.Y; y<=p_max.Y; y++)
8410         for(s32 x=p_min.X; x<=p_max.X; x++)
8411         {
8412                 v3s16 p(x,y,z);
8413                 core::map<v3s16, bool>::Node *n;
8414                 n = m_loaded_blocks.find(p);
8415                 if(n != NULL)
8416                         continue;
8417                 
8418                 bool block_data_inexistent = false;
8419                 try
8420                 {
8421                         TimeTaker timer1("emerge load", &emerge_load_time);
8422
8423                         MapBlock *block = m_map->getBlockNoCreate(p);
8424                         if(block->isDummy())
8425                                 block_data_inexistent = true;
8426                         else
8427                                 block->copyTo(*this);
8428                 }
8429                 catch(InvalidPositionException &e)
8430                 {
8431                         block_data_inexistent = true;
8432                 }
8433
8434                 if(block_data_inexistent)
8435                 {
8436                         /*
8437                                 Mark area inexistent
8438                         */
8439                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
8440                         // Fill with VOXELFLAG_INEXISTENT
8441                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
8442                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
8443                         {
8444                                 s32 i = m_area.index(a.MinEdge.X,y,z);
8445                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
8446                         }
8447                 }
8448
8449                 m_loaded_blocks.insert(p, !block_data_inexistent);
8450         }
8451 }
8452
8453 void ManualMapVoxelManipulator::blitBackAll(
8454                 core::map<v3s16, MapBlock*> * modified_blocks)
8455 {
8456         if(m_area.getExtent() == v3s16(0,0,0))
8457                 return;
8458         
8459         /*
8460                 Copy data of all blocks
8461         */
8462         for(core::map<v3s16, bool>::Iterator
8463                         i = m_loaded_blocks.getIterator();
8464                         i.atEnd() == false; i++)
8465         {
8466                 bool existed = i.getNode()->getValue();
8467                 if(existed == false)
8468                         continue;
8469                 v3s16 p = i.getNode()->getKey();
8470                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
8471                 if(block == NULL)
8472                 {
8473                         dstream<<"WARNING: "<<__FUNCTION_NAME
8474                                         <<": got NULL block "
8475                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
8476                                         <<std::endl;
8477                         continue;
8478                 }
8479
8480                 block->copyFrom(*this);
8481
8482                 if(modified_blocks)
8483                         modified_blocks->insert(p, block);
8484         }
8485 }
8486
8487 //END