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