Map generator tweaking. Still doesn't resume from save properly.
[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
30 /*
31         Map
32 */
33
34 Map::Map(std::ostream &dout):
35         m_dout(dout),
36         m_camera_position(0,0,0),
37         m_camera_direction(0,0,1),
38         m_sector_cache(NULL),
39         m_hwrapper(this)
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         //dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;
1459
1460         while(m_transforming_liquid.size() != 0)
1461         {
1462                 /*
1463                         Get a queued transforming liquid node
1464                 */
1465                 v3s16 p0 = m_transforming_liquid.pop_front();
1466
1467                 MapNode n0 = getNode(p0);
1468                 
1469                 // Don't deal with non-liquids
1470                 if(content_liquid(n0.d) == false)
1471                         continue;
1472
1473                 bool is_source = !content_flowing_liquid(n0.d);
1474                 
1475                 u8 liquid_level = 8;
1476                 if(is_source == false)
1477                         liquid_level = n0.param2 & 0x0f;
1478                 
1479                 // Turn possible source into non-source
1480                 u8 nonsource_c = make_liquid_flowing(n0.d);
1481
1482                 /*
1483                         If not source, check that some node flows into this one
1484                         and what is the level of liquid in this one
1485                 */
1486                 if(is_source == false)
1487                 {
1488                         s8 new_liquid_level_max = -1;
1489
1490                         v3s16 dirs_from[5] = {
1491                                 v3s16(0,1,0), // top
1492                                 v3s16(0,0,1), // back
1493                                 v3s16(1,0,0), // right
1494                                 v3s16(0,0,-1), // front
1495                                 v3s16(-1,0,0), // left
1496                         };
1497                         for(u16 i=0; i<5; i++)
1498                         {
1499                                 try
1500                                 {
1501
1502                                 bool from_top = (i==0);
1503
1504                                 v3s16 p2 = p0 + dirs_from[i];
1505                                 MapNode n2 = getNode(p2);
1506
1507                                 if(content_liquid(n2.d))
1508                                 {
1509                                         u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1510                                         // Check that the liquids are the same type
1511                                         if(n2_nonsource_c != nonsource_c)
1512                                         {
1513                                                 dstream<<"WARNING: Not handling: different liquids"
1514                                                                 " collide"<<std::endl;
1515                                                 continue;
1516                                         }
1517                                         bool n2_is_source = !content_flowing_liquid(n2.d);
1518                                         s8 n2_liquid_level = 8;
1519                                         if(n2_is_source == false)
1520                                                 n2_liquid_level = n2.param2 & 0x07;
1521                                         
1522                                         s8 new_liquid_level = -1;
1523                                         if(from_top)
1524                                         {
1525                                                 //new_liquid_level = 7;
1526                                                 if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
1527                                                         new_liquid_level = 7;
1528                                                 else
1529                                                         new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
1530                                         }
1531                                         else if(n2_liquid_level > 0)
1532                                         {
1533                                                 new_liquid_level = n2_liquid_level - 1;
1534                                         }
1535
1536                                         if(new_liquid_level > new_liquid_level_max)
1537                                                 new_liquid_level_max = new_liquid_level;
1538                                 }
1539
1540                                 }catch(InvalidPositionException &e)
1541                                 {
1542                                 }
1543                         } //for
1544                         
1545                         /*
1546                                 If liquid level should be something else, update it and
1547                                 add all the neighboring water nodes to the transform queue.
1548                         */
1549                         if(new_liquid_level_max != liquid_level)
1550                         {
1551                                 if(new_liquid_level_max == -1)
1552                                 {
1553                                         // Remove water alltoghether
1554                                         n0.d = CONTENT_AIR;
1555                                         n0.param2 = 0;
1556                                         setNode(p0, n0);
1557                                 }
1558                                 else
1559                                 {
1560                                         n0.param2 = new_liquid_level_max;
1561                                         setNode(p0, n0);
1562                                 }
1563                                 
1564                                 // Block has been modified
1565                                 {
1566                                         v3s16 blockpos = getNodeBlockPos(p0);
1567                                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1568                                         if(block != NULL)
1569                                                 modified_blocks.insert(blockpos, block);
1570                                 }
1571                                 
1572                                 /*
1573                                         Add neighboring non-source liquid nodes to transform queue.
1574                                 */
1575                                 v3s16 dirs[6] = {
1576                                         v3s16(0,0,1), // back
1577                                         v3s16(0,1,0), // top
1578                                         v3s16(1,0,0), // right
1579                                         v3s16(0,0,-1), // front
1580                                         v3s16(0,-1,0), // bottom
1581                                         v3s16(-1,0,0), // left
1582                                 };
1583                                 for(u16 i=0; i<6; i++)
1584                                 {
1585                                         try
1586                                         {
1587
1588                                         v3s16 p2 = p0 + dirs[i];
1589                                         
1590                                         MapNode n2 = getNode(p2);
1591                                         if(content_flowing_liquid(n2.d))
1592                                         {
1593                                                 m_transforming_liquid.push_back(p2);
1594                                         }
1595                                         
1596                                         }catch(InvalidPositionException &e)
1597                                         {
1598                                         }
1599                                 }
1600                         }
1601                 }
1602                 
1603                 // Get a new one from queue if the node has turned into non-water
1604                 if(content_liquid(n0.d) == false)
1605                         continue;
1606
1607                 /*
1608                         Flow water from this node
1609                 */
1610                 v3s16 dirs_to[5] = {
1611                         v3s16(0,-1,0), // bottom
1612                         v3s16(0,0,1), // back
1613                         v3s16(1,0,0), // right
1614                         v3s16(0,0,-1), // front
1615                         v3s16(-1,0,0), // left
1616                 };
1617                 for(u16 i=0; i<5; i++)
1618                 {
1619                         try
1620                         {
1621
1622                         bool to_bottom = (i == 0);
1623
1624                         // If liquid is at lowest possible height, it's not going
1625                         // anywhere except down
1626                         if(liquid_level == 0 && to_bottom == false)
1627                                 continue;
1628                         
1629                         u8 liquid_next_level = 0;
1630                         // If going to bottom
1631                         if(to_bottom)
1632                         {
1633                                 //liquid_next_level = 7;
1634                                 if(liquid_level >= 7 - WATER_DROP_BOOST)
1635                                         liquid_next_level = 7;
1636                                 else
1637                                         liquid_next_level = liquid_level + WATER_DROP_BOOST;
1638                         }
1639                         else
1640                                 liquid_next_level = liquid_level - 1;
1641
1642                         bool n2_changed = false;
1643                         bool flowed = false;
1644                         
1645                         v3s16 p2 = p0 + dirs_to[i];
1646
1647                         MapNode n2 = getNode(p2);
1648                         //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
1649
1650                         if(content_liquid(n2.d))
1651                         {
1652                                 u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1653                                 // Check that the liquids are the same type
1654                                 if(n2_nonsource_c != nonsource_c)
1655                                 {
1656                                         dstream<<"WARNING: Not handling: different liquids"
1657                                                         " collide"<<std::endl;
1658                                         continue;
1659                                 }
1660                                 bool n2_is_source = !content_flowing_liquid(n2.d);
1661                                 u8 n2_liquid_level = 8;
1662                                 if(n2_is_source == false)
1663                                         n2_liquid_level = n2.param2 & 0x07;
1664                                 
1665                                 if(to_bottom)
1666                                 {
1667                                         flowed = true;
1668                                 }
1669
1670                                 if(n2_is_source)
1671                                 {
1672                                         // Just flow into the source, nothing changes.
1673                                         // n2_changed is not set because destination didn't change
1674                                         flowed = true;
1675                                 }
1676                                 else
1677                                 {
1678                                         if(liquid_next_level > liquid_level)
1679                                         {
1680                                                 n2.param2 = liquid_next_level;
1681                                                 setNode(p2, n2);
1682
1683                                                 n2_changed = true;
1684                                                 flowed = true;
1685                                         }
1686                                 }
1687                         }
1688                         else if(n2.d == CONTENT_AIR)
1689                         {
1690                                 n2.d = nonsource_c;
1691                                 n2.param2 = liquid_next_level;
1692                                 setNode(p2, n2);
1693                                 
1694                                 n2_changed = true;
1695                                 flowed = true;
1696                         }
1697                         
1698                         //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl;
1699
1700                         if(n2_changed)
1701                         {
1702                                 m_transforming_liquid.push_back(p2);
1703                                 
1704                                 v3s16 blockpos = getNodeBlockPos(p2);
1705                                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1706                                 if(block != NULL)
1707                                         modified_blocks.insert(blockpos, block);
1708                         }
1709                         
1710                         // If n2_changed to bottom, don't flow anywhere else
1711                         if(to_bottom && flowed && !is_source)
1712                                 break;
1713                                 
1714                         }catch(InvalidPositionException &e)
1715                         {
1716                         }
1717                 }
1718
1719                 loopcount++;
1720                 //if(loopcount >= 100000)
1721                 if(loopcount >= initial_size * 1)
1722                         break;
1723         }
1724         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1725 }
1726
1727 /*
1728         ServerMap
1729 */
1730
1731 ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
1732         Map(dout_server),
1733         m_heightmap(NULL)
1734 {
1735         
1736         //m_chunksize = 64;
1737         //m_chunksize = 16;
1738         m_chunksize = 8;
1739         //m_chunksize = 4;
1740         //m_chunksize = 2;
1741
1742         /*
1743                 Experimental and debug stuff
1744         */
1745         
1746         {
1747                 dstream<<"Generating map point attribute lists"<<std::endl;
1748                 
1749                 PointAttributeList *list_baseheight = m_padb.getList("hm_baseheight");
1750                 PointAttributeList *list_randmax = m_padb.getList("hm_randmax");
1751                 PointAttributeList *list_randfactor = m_padb.getList("hm_randfactor");
1752                 //PointAttributeList *list_plants_amount = m_padb.getList("plants_amount");
1753                 //PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
1754
1755 #if 0
1756                 /*
1757                         NOTE: BEWARE: Too big amount of these will make map generation
1758                         slow. Especially those that are read by every block emerge.
1759                         
1760                         Fetch times:
1761                         1000 points: 2-3ms
1762                         5000 points: 15ms
1763                         15000 points: 40ms
1764                 */
1765                 
1766                 for(u32 i=0; i<500; i++)
1767                 {
1768                         /*u32 lim = MAP_GENERATION_LIMIT;
1769                         if(i < 400)
1770                                 lim = 2000;*/
1771
1772                         u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500;
1773
1774                         v3s16 p(
1775                                 -lim + myrand()%(lim*2),
1776                                 0,
1777                                 -lim + myrand()%(lim*2)
1778                         );
1779                         /*float plants_amount = (float)(myrand()%1050) / 1000.0;
1780                         plants_amount = pow(plants_amount, 5);
1781                         list_plants_amount->addPoint(p, Attribute(plants_amount));*/
1782                         
1783                         float plants_amount = 0;
1784                         if(myrand()%4 == 0)
1785                         {
1786                                 plants_amount = 1.5;
1787                         }
1788                         else if(myrand()%4 == 0)
1789                         {
1790                                 plants_amount = 0.5;
1791                         }
1792                         else if(myrand()%2 == 0)
1793                         {
1794                                 plants_amount = 0.03;
1795                         }
1796                         else
1797                         {
1798                                 plants_amount = 0.0;
1799                         }
1800
1801
1802                         list_plants_amount->addPoint(p, Attribute(plants_amount));
1803                 }
1804
1805                 for(u32 i=0; i<500; i++)
1806                 {
1807                         /*u32 lim = MAP_GENERATION_LIMIT;
1808                         if(i < 400)
1809                                 lim = 2000;*/
1810
1811                         u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500;
1812
1813                         v3s16 p(
1814                                 -lim + myrand()%(lim*2),
1815                                 0,
1816                                 -lim + myrand()%(lim*2)
1817                         );
1818
1819                         float caves_amount = 0;
1820                         if(myrand()%5 == 0)
1821                         {
1822                                 caves_amount = 1.0;
1823                         }
1824                         else if(myrand()%3 == 0)
1825                         {
1826                                 caves_amount = 0.3;
1827                         }
1828                         else
1829                         {
1830                                 caves_amount = 0.05;
1831                         }
1832
1833                         list_caves_amount->addPoint(p, Attribute(caves_amount));
1834                 }
1835                 
1836                 for(u32 i=0; i<500; i++)
1837                 {
1838                         /*u32 lim = MAP_GENERATION_LIMIT;
1839                         if(i < 400)
1840                                 lim = 2000;*/
1841
1842                         u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500;
1843
1844                         v3s16 p(
1845                                 -lim + (myrand()%(lim*2)),
1846                                 0,
1847                                 -lim + (myrand()%(lim*2))
1848                         );
1849                         
1850                         /*s32 bh_i = (myrand()%200) - 50;
1851                         float baseheight = (float)bh_i;
1852                         
1853                         float m = 100.;
1854                         float e = 3.;
1855                         float randmax = (float)(myrand()%(int)(10.*pow(m, 1./e)))/10.;
1856                         randmax = pow(randmax, e);
1857
1858                         //float randmax = (float)(myrand()%60);
1859                         float randfactor = (float)(myrand()%450) / 1000.0 + 0.4;*/
1860
1861                         float baseheight = 0;
1862                         float randmax = 0;
1863                         float randfactor = 0;
1864
1865                         /*if(myrand()%5 == 0)
1866                         {
1867                                 baseheight = 100;
1868                                 randmax = 50;
1869                                 randfactor = 0.63;
1870                         }
1871                         else if(myrand()%6 == 0)
1872                         {
1873                                 baseheight = 200;
1874                                 randmax = 100;
1875                                 randfactor = 0.66;
1876                         }
1877                         else if(myrand()%4 == 0)
1878                         {
1879                                 baseheight = -3;
1880                                 randmax = 30;
1881                                 randfactor = 0.7;
1882                         }
1883                         else if(myrand()%3 == 0)
1884                         {
1885                                 baseheight = 0;
1886                                 randmax = 30;
1887                                 randfactor = 0.63;
1888                         }
1889                         else
1890                         {
1891                                 baseheight = -3;
1892                                 randmax = 20;
1893                                 randfactor = 0.5;
1894                         }*/
1895                         
1896                         if(myrand()%3 < 2)
1897                         {
1898                                 baseheight = 10;
1899                                 randmax = 30;
1900                                 randfactor = 0.7;
1901                         }
1902                         else
1903                         {
1904                                 baseheight = 0;
1905                                 randmax = 15;
1906                                 randfactor = 0.63;
1907                         }
1908
1909                         list_baseheight->addPoint(p, Attribute(baseheight));
1910                         list_randmax->addPoint(p, Attribute(randmax));
1911                         list_randfactor->addPoint(p, Attribute(randfactor));
1912                 }
1913 #endif
1914                 
1915                 // Add only one entry
1916                 list_baseheight->addPoint(v3s16(0,0,0), Attribute(-4));
1917                 list_randmax->addPoint(v3s16(0,0,0), Attribute(22));
1918                 //list_randmax->addPoint(v3s16(0,0,0), Attribute(0));
1919                 list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.45));
1920
1921                 // Easy spawn point
1922                 /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(0));
1923                 list_randmax->addPoint(v3s16(0,0,0), Attribute(10));
1924                 list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.65));*/
1925         }
1926         
1927         /*
1928                 Try to load map; if not found, create a new one.
1929         */
1930
1931         m_savedir = savedir;
1932         m_map_saving_enabled = false;
1933         
1934         try
1935         {
1936                 // If directory exists, check contents and load if possible
1937                 if(fs::PathExists(m_savedir))
1938                 {
1939                         // If directory is empty, it is safe to save into it.
1940                         if(fs::GetDirListing(m_savedir).size() == 0)
1941                         {
1942                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1943                                                 <<std::endl;
1944                                 m_map_saving_enabled = true;
1945                         }
1946                         else
1947                         {
1948                                 // Load master heightmap
1949                                 loadMasterHeightmap();
1950                                 
1951                                 // Load sector (0,0) and throw and exception on fail
1952                                 if(loadSectorFull(v2s16(0,0)) == false)
1953                                         throw LoadError("Failed to load sector (0,0)");
1954
1955                                 dstream<<DTIME<<"Server: Successfully loaded master "
1956                                                 "heightmap and sector (0,0) from "<<savedir<<
1957                                                 ", assuming valid save directory."
1958                                                 <<std::endl;
1959
1960                                 m_map_saving_enabled = true;
1961                                 // Map loaded, not creating new one
1962                                 return;
1963                         }
1964                 }
1965                 // If directory doesn't exist, it is safe to save to it
1966                 else{
1967                         m_map_saving_enabled = true;
1968                 }
1969         }
1970         catch(std::exception &e)
1971         {
1972                 dstream<<DTIME<<"Server: Failed to load map from "<<savedir
1973                                 <<", exception: "<<e.what()<<std::endl;
1974                 dstream<<DTIME<<"Please remove the map or fix it."<<std::endl;
1975                 dstream<<DTIME<<"WARNING: Map saving will be disabled."<<std::endl;
1976         }
1977
1978         dstream<<DTIME<<"Initializing new map."<<std::endl;
1979         
1980         // Create master heightmap
1981         m_heightmap = new UnlimitedHeightmap
1982                         (32, &m_padb);
1983         
1984         // Set map parameters
1985         m_params = mp;
1986         
1987         // Create zero sector
1988         emergeSector(v2s16(0,0));
1989
1990         // Initially write whole map
1991         save(false);
1992 }
1993
1994 ServerMap::~ServerMap()
1995 {
1996         try
1997         {
1998                 if(m_map_saving_enabled)
1999                 {
2000                         //save(false);
2001                         // Save only changed parts
2002                         save(true);
2003                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
2004                 }
2005                 else
2006                 {
2007                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
2008                 }
2009         }
2010         catch(std::exception &e)
2011         {
2012                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
2013                                 <<", exception: "<<e.what()<<std::endl;
2014         }
2015         
2016         if(m_heightmap != NULL)
2017                 delete m_heightmap;
2018         
2019         /*
2020                 Free all MapChunks
2021         */
2022         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2023         for(; i.atEnd() == false; i++)
2024         {
2025                 MapChunk *chunk = i.getNode()->getValue();
2026                 delete chunk;
2027         }
2028 }
2029
2030 /*
2031         Some helper functions
2032 */
2033
2034 s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
2035 {
2036         v3s16 em = vmanip.m_area.getExtent();
2037         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
2038         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
2039         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2040         s16 y;
2041         for(y=y_nodes_max; y>=y_nodes_min; y--)
2042         {
2043                 MapNode &n = vmanip.m_data[i];
2044                 if(content_walkable(n.d))
2045                         break;
2046                         
2047                 vmanip.m_area.add_y(em, i, -1);
2048         }
2049         if(y >= y_nodes_min)
2050                 return y;
2051         else
2052                 return y_nodes_min;
2053 }
2054
2055 void make_tree(VoxelManipulator &vmanip, v3s16 p0)
2056 {
2057         MapNode treenode(CONTENT_TREE);
2058         MapNode leavesnode(CONTENT_LEAVES);
2059
2060         s16 trunk_h = myrand_range(2, 6);
2061         v3s16 p1 = p0;
2062         for(s16 ii=0; ii<trunk_h; ii++)
2063         {
2064                 if(vmanip.m_area.contains(p1))
2065                         vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
2066                 p1.Y++;
2067         }
2068         
2069         // p1 is now the last piece of the trunk
2070         p1.Y -= 1;
2071
2072         VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
2073         SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
2074         for(s32 i=0; i<leaves_a.getVolume(); i++)
2075                 leaves_d[i] = 0;
2076         
2077         // Force leaves at near the end of the trunk
2078         {
2079                 s16 d = 1;
2080                 for(s16 z=-d; z<=d; z++)
2081                 for(s16 y=-d; y<=d; y++)
2082                 for(s16 x=-d; x<=d; x++)
2083                 {
2084                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
2085                 }
2086         }
2087         
2088         // Add leaves randomly
2089         for(u32 iii=0; iii<7; iii++)
2090         {
2091                 s16 d = 1;
2092
2093                 v3s16 p(
2094                         myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
2095                         myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
2096                         myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
2097                 );
2098                 
2099                 for(s16 z=0; z<=d; z++)
2100                 for(s16 y=0; y<=d; y++)
2101                 for(s16 x=0; x<=d; x++)
2102                 {
2103                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
2104                 }
2105         }
2106         
2107         // Blit leaves to vmanip
2108         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
2109         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
2110         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
2111         {
2112                 v3s16 p(x,y,z);
2113                 p += p1;
2114                 if(vmanip.m_area.contains(p) == false)
2115                         continue;
2116                 u32 vi = vmanip.m_area.index(p);
2117                 if(vmanip.m_data[vi].d != CONTENT_AIR)
2118                         continue;
2119                 u32 i = leaves_a.index(x,y,z);
2120                 if(leaves_d[i] == 1)
2121                         vmanip.m_data[vi] = leavesnode;
2122         }
2123 }
2124
2125 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
2126                 core::map<v3s16, MapBlock*> &changed_blocks)
2127 {
2128         /*
2129                 Don't generate if already fully generated
2130         */
2131         {
2132                 MapChunk *chunk = getChunk(chunkpos);
2133                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
2134                 {
2135                         dstream<<"generateChunkRaw(): Chunk "
2136                                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2137                                         <<" already generated"<<std::endl;
2138                         return chunk;
2139                 }
2140         }
2141
2142         dstream<<"generateChunkRaw(): Generating chunk "
2143                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2144                         <<std::endl;
2145         
2146         TimeTaker timer("generateChunkRaw()");
2147         
2148         // The distance how far into the neighbors the generator is allowed to go
2149         s16 max_spread_amount_sectors = 2;
2150         assert(max_spread_amount_sectors <= m_chunksize);
2151         s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
2152         // Minimum amount of space left on sides for mud to fall in
2153         s16 min_mud_fall_space = 2;
2154         // Maximum diameter of stone obstacles in X and Z
2155         s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
2156         assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);
2157         
2158         s16 y_blocks_min = -4;
2159         s16 y_blocks_max = 3;
2160         s16 h_blocks = y_blocks_max - y_blocks_min + 1;
2161         s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
2162         s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
2163
2164         v2s16 sectorpos_base = chunk_to_sector(chunkpos);
2165         s16 sectorpos_base_size = m_chunksize;
2166
2167         /*v2s16 sectorpos_bigbase = chunk_to_sector(chunkpos - v2s16(1,1));
2168         s16 sectorpos_bigbase_size = m_chunksize * 3;*/
2169         v2s16 sectorpos_bigbase =
2170                         sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
2171         s16 sectorpos_bigbase_size =
2172                         sectorpos_base_size + 2 * max_spread_amount_sectors;
2173
2174         v3s16 bigarea_blocks_min(
2175                 sectorpos_bigbase.X,
2176                 y_blocks_min,
2177                 sectorpos_bigbase.Y
2178         );
2179
2180         v3s16 bigarea_blocks_max(
2181                 sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
2182                 y_blocks_max,
2183                 sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
2184         );
2185         
2186         // Relative values to control amount of stuff in one chunk
2187         u32 relative_area = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2188                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE;
2189         u32 relative_volume = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2190                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE
2191                         *(u32)h_blocks*MAP_BLOCKSIZE;
2192                 
2193         /*
2194                 Create the whole area of this and the neighboring chunks
2195         */
2196         {
2197                 TimeTaker timer("generateChunkRaw() create area");
2198                 
2199                 for(s16 x=0; x<sectorpos_bigbase_size; x++)
2200                 for(s16 z=0; z<sectorpos_bigbase_size; z++)
2201                 {
2202                         v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
2203                         ServerMapSector *sector = createSector(sectorpos);
2204                         assert(sector);
2205
2206                         for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
2207                         {
2208                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
2209                                 MapBlock *block = createBlock(blockpos);
2210
2211                                 // Lighting won't be calculated
2212                                 //block->setLightingExpired(true);
2213                                 // Lighting will be calculated
2214                                 block->setLightingExpired(false);
2215
2216                                 /*
2217                                         Block gets sunlight if this is true.
2218
2219                                         This should be set to true when the top side of a block
2220                                         is completely exposed to the sky.
2221
2222                                         Actually this doesn't matter now because the
2223                                         initial lighting is done here.
2224                                 */
2225                                 block->setIsUnderground(y != y_blocks_max);
2226                         }
2227                 }
2228         }
2229
2230         /*
2231                 Now we have a big empty area.
2232
2233                 Make a ManualMapVoxelManipulator that contains this and the
2234                 neighboring chunks
2235         */
2236
2237         ManualMapVoxelManipulator vmanip(this);
2238         // Add the area we just generated
2239         {
2240                 TimeTaker timer("generateChunkRaw() initialEmerge");
2241                 vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2242         }
2243
2244         TimeTaker timer_generate("generateChunkRaw() generate");
2245
2246         /*
2247                 Generate general ground level to full area
2248         */
2249         
2250         {
2251         // 22ms @cs=8
2252         //TimeTaker timer1("ground level");
2253
2254         for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
2255         for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
2256         {
2257                 // Node position
2258                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2259                 
2260                 /*
2261                         Skip of already generated
2262                 */
2263                 {
2264                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2265                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
2266                                 continue;
2267                 }
2268
2269                 // Ground height at this point
2270                 float surface_y_f = 0.0;
2271                 /*
2272                         A hack to get the ground height from the sector.
2273                         Do this better.
2274                 */
2275                 {
2276                         v2s16 sectorpos = getContainerPos(p2d, MAP_BLOCKSIZE);
2277                         v2s16 sector_relpos = p2d - sectorpos*MAP_BLOCKSIZE;
2278                         MapSector *sector = getSectorNoGenerate(sectorpos);
2279                         assert(sector);
2280                         float h = sector->getGroundHeight(sector_relpos);
2281                         if(h > GROUNDHEIGHT_VALID_MINVALUE)
2282                                 surface_y_f = h;
2283                         else
2284                                 dstream<<"WARNING: "<<__FUNCTION_NAME
2285                                 <<": sector->getGroundHeight returned bad height"<<std::endl;
2286                 }
2287                 // Convert to integer
2288                 s16 surface_y = (s16)surface_y_f;
2289
2290                 /*
2291                         Fill ground with stone
2292                 */
2293                 {
2294                         // Use fast index incrementing
2295                         v3s16 em = vmanip.m_area.getExtent();
2296                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
2297                         for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++)
2298                         {
2299                                 vmanip.m_data[i].d = CONTENT_STONE;
2300
2301                                 vmanip.m_area.add_y(em, i, 1);
2302                         }
2303                 }
2304         }
2305         
2306         }//timer1
2307
2308         /*
2309                 Randomize some parameters
2310         */
2311
2312         // 0-100
2313         // Usually little, sometimes huge
2314         //u32 stone_obstacle_amount = myrand_range(0, myrand_range(0, 100));
2315         u32 stone_obstacle_amount = myrand_range(0, myrand_range(20, 100));
2316
2317         /*
2318                 Loop this part, it will make stuff look older and newer nicely
2319         */
2320
2321         for(u32 i_age=0; i_age<2; i_age++)
2322         { // Aging loop
2323
2324         // This is set during the next operation.
2325         // Maximum height of the stone surface and obstacles.
2326         // This is used to disable dungeon generation from going too high.
2327         s16 stone_surface_max_y = 0;
2328
2329         {
2330         // 8ms @cs=8
2331         //TimeTaker timer1("stone obstacles");
2332
2333         /*
2334                 Add some random stone obstacles
2335         */
2336         
2337         for(u32 ri=0; ri<stone_obstacle_amount/3; ri++)
2338         //for(u32 ri=0; ri<7; ri++)
2339         //if(0)
2340         {
2341                 // Randomize max height so usually stuff will be quite low
2342                 //s16 maxheight_randomized = myrand_range(0, 25);
2343                 s16 maxheight_randomized = myrand_range(0, stone_obstacle_amount/3);
2344
2345                 // The size of these could actually be m_chunksize*MAP_BLOCKSIZE*2
2346                 v3s16 ob_size(
2347                         myrand_range(5, stone_obstacle_max_size),
2348                         myrand_range(0, maxheight_randomized),
2349                         myrand_range(5, stone_obstacle_max_size)
2350                 );
2351                 v2s16 ob_place(
2352                         myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1),
2353                         myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1)
2354                 );
2355                 
2356                 // Minimum space left on top of the obstacle
2357                 s16 min_head_space = 10;
2358                 
2359                 for(s16 x=-ob_size.X/2; x<ob_size.X/2; x++)
2360                 for(s16 z=-ob_size.Z/2; z<ob_size.Z/2; z++)
2361                 {
2362                         // Node position in 2d
2363                         v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + ob_place + v2s16(x,z);
2364                         
2365                         // Find stone ground level
2366                         // (ignore everything else than mud in already generated chunks)
2367                         // and mud amount over the stone level
2368                         s16 surface_y = 0;
2369                         s16 mud_amount = 0;
2370                         {
2371                                 v3s16 em = vmanip.m_area.getExtent();
2372                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2373                                 s16 y;
2374                                 // Go to ground level
2375                                 for(y=y_nodes_max; y>=y_nodes_min; y--)
2376                                 {
2377                                         MapNode *n = &vmanip.m_data[i];
2378                                         /*if(content_walkable(n.d)
2379                                                         && n.d != CONTENT_MUD
2380                                                         && n.d != CONTENT_GRASS)
2381                                                 break;*/
2382                                         if(n->d == CONTENT_STONE)
2383                                                 break;
2384                                         
2385                                         if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
2386                                         {
2387                                                 mud_amount++;
2388                                                 /*
2389                                                         Change to mud because otherwise we might
2390                                                         be throwing mud on grass at the next
2391                                                         step
2392                                                 */
2393                                                 n->d = CONTENT_MUD;
2394                                         }
2395                                                 
2396                                         vmanip.m_area.add_y(em, i, -1);
2397                                 }
2398                                 if(y >= y_nodes_min)
2399                                         surface_y = y;
2400                                 else
2401                                         surface_y = y_nodes_min;
2402                         }
2403
2404
2405                         /*
2406                                 Add stone on ground
2407                         */
2408                         {
2409                                 v3s16 em = vmanip.m_area.getExtent();
2410                                 s16 y_start = surface_y+1;
2411                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2412                                 s16 y;
2413                                 // Add stone
2414                                 s16 count = 0;
2415                                 for(y=y_start; y<=y_nodes_max - min_head_space; y++)
2416                                 {
2417                                         MapNode &n = vmanip.m_data[i];
2418                                         n.d = CONTENT_STONE;
2419
2420                                         if(y > stone_surface_max_y)
2421                                                 stone_surface_max_y = y;
2422
2423                                         count++;
2424                                         if(count >= ob_size.Y)
2425                                                 break;
2426                                                 
2427                                         vmanip.m_area.add_y(em, i, 1);
2428                                 }
2429                                 // Add mud
2430                                 count = 0;
2431                                 for(; y<=y_nodes_max; y++)
2432                                 {
2433                                         MapNode &n = vmanip.m_data[i];
2434                                         n.d = CONTENT_MUD;
2435                                         count++;
2436                                         if(count >= mud_amount)
2437                                                 break;
2438                                                 
2439                                         vmanip.m_area.add_y(em, i, 1);
2440                                 }
2441                         }
2442
2443                 }
2444         }
2445
2446         }//timer1
2447         {
2448         // 24ms @cs=8
2449         //TimeTaker timer1("dungeons");
2450
2451         /*
2452                 Make dungeons
2453         */
2454         u32 dungeons_count = relative_volume / 200000;
2455         u32 bruises_count = relative_volume * stone_surface_max_y / 15000000;
2456         for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
2457         {
2458                 s16 min_tunnel_diameter = 1;
2459                 s16 max_tunnel_diameter = 5;
2460                 u16 tunnel_routepoints = 10;
2461                 
2462                 bool bruise_surface = (jj < bruises_count);
2463
2464                 if(bruise_surface)
2465                 {
2466                         min_tunnel_diameter = 5;
2467                         max_tunnel_diameter = myrand_range(8, 20);
2468                         tunnel_routepoints = 7;
2469                 }
2470
2471                 // Allowed route area size in nodes
2472                 v3s16 ar(
2473                         sectorpos_base_size*MAP_BLOCKSIZE,
2474                         h_blocks*MAP_BLOCKSIZE,
2475                         sectorpos_base_size*MAP_BLOCKSIZE
2476                 );
2477
2478                 // Area starting point in nodes
2479                 v3s16 of(
2480                         sectorpos_base.X*MAP_BLOCKSIZE,
2481                         y_blocks_min*MAP_BLOCKSIZE,
2482                         sectorpos_base.Y*MAP_BLOCKSIZE
2483                 );
2484
2485                 // Allow a bit more
2486                 //(this should be more than the maximum radius of the tunnel)
2487                 //s16 insure = 5; // Didn't work with max_d = 20
2488                 s16 insure = 10;
2489                 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
2490                 ar += v3s16(1,0,1) * more * 2;
2491                 of -= v3s16(1,0,1) * more;
2492                 
2493                 s16 route_y_min = 0;
2494                 //s16 route_y_max = ar.Y-1;
2495                 s16 route_y_max = stone_surface_max_y - of.Y;
2496
2497                 if(bruise_surface)
2498                 {
2499                         /*// Minimum is at y=0
2500                         route_y_min = -of.Y - 0;*/
2501                         // Minimum is at y=max_tunnel_diameter/4
2502                         route_y_min = -of.Y + max_tunnel_diameter/4;
2503                         route_y_min = rangelim(route_y_min, 0, route_y_max);
2504                 }
2505
2506                 /*dstream<<"route_y_min = "<<route_y_min
2507                                 <<", route_y_max = "<<route_y_max<<std::endl;*/
2508
2509                 // Randomize starting position
2510                 v3f orp(
2511                         (float)(myrand()%ar.X)+0.5,
2512                         (float)(myrand_range(route_y_min, route_y_max))+0.5,
2513                         (float)(myrand()%ar.Z)+0.5
2514                 );
2515
2516                 MapNode airnode(CONTENT_AIR);
2517                 
2518                 /*
2519                         Generate some tunnel starting from orp
2520                 */
2521                 
2522                 for(u16 j=0; j<tunnel_routepoints; j++)
2523                 {
2524                         v3s16 maxlen(20, 10, 20);
2525
2526                         if(bruise_surface)
2527                         {
2528                                 maxlen = v3s16(60,60,60);
2529                         }
2530
2531                         v3f vec(
2532                                 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2533                                 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
2534                                 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2535                         );
2536                         v3f rp = orp + vec;
2537                         if(rp.X < 0)
2538                                 rp.X = 0;
2539                         else if(rp.X >= ar.X)
2540                                 rp.X = ar.X-1;
2541                         if(rp.Y < route_y_min)
2542                                 rp.Y = route_y_min;
2543                         else if(rp.Y >= route_y_max)
2544                                 rp.Y = route_y_max-1;
2545                         if(rp.Z < 0)
2546                                 rp.Z = 0;
2547                         else if(rp.Z >= ar.Z)
2548                                 rp.Z = ar.Z-1;
2549                         vec = rp - orp;
2550
2551                         // Randomize size
2552                         s16 min_d = min_tunnel_diameter;
2553                         s16 max_d = max_tunnel_diameter;
2554                         s16 rs = myrand_range(min_d, max_d);
2555                         
2556                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
2557                         {
2558                                 v3f fp = orp + vec * f;
2559                                 v3s16 cp(fp.X, fp.Y, fp.Z);
2560
2561                                 s16 d0 = -rs/2;
2562                                 s16 d1 = d0 + rs - 1;
2563                                 for(s16 z0=d0; z0<=d1; z0++)
2564                                 {
2565                                         s16 si = rs - abs(z0);
2566                                         for(s16 x0=-si; x0<=si-1; x0++)
2567                                         {
2568                                                 s16 maxabsxz = abs(x0)>abs(z0)?abs(x0):abs(z0);
2569                                                 s16 si2 = rs - maxabsxz;
2570                                                 //s16 si2 = rs - abs(x0);
2571                                                 for(s16 y0=-si2+1; y0<=si2-1; y0++)
2572                                                 {
2573                                                         s16 z = cp.Z + z0;
2574                                                         s16 y = cp.Y + y0;
2575                                                         s16 x = cp.X + x0;
2576                                                         v3s16 p(x,y,z);
2577                                                         /*if(isInArea(p, ar) == false)
2578                                                                 continue;*/
2579                                                         // Check only height
2580                                                         if(y < 0 || y >= ar.Y)
2581                                                                 continue;
2582                                                         p += of;
2583                                                         
2584                                                         //assert(vmanip.m_area.contains(p));
2585                                                         if(vmanip.m_area.contains(p) == false)
2586                                                         {
2587                                                                 dstream<<"WARNING: "<<__FUNCTION_NAME
2588                                                                                 <<":"<<__LINE__<<": "
2589                                                                                 <<"point not in area"
2590                                                                                 <<std::endl;
2591                                                                 continue;
2592                                                         }
2593                                                         
2594                                                         // Just set it to air, it will be changed to
2595                                                         // water afterwards
2596                                                         u32 i = vmanip.m_area.index(p);
2597                                                         vmanip.m_data[i] = airnode;
2598                                                 }
2599                                         }
2600                                 }
2601                         }
2602
2603                         orp = rp;
2604                 }
2605         
2606         }
2607
2608         }//timer1
2609         {
2610         // 46ms @cs=8
2611         //TimeTaker timer1("ore veins");
2612
2613         /*
2614                 Make ore veins
2615         */
2616         for(u32 jj=0; jj<relative_volume/524; jj++)
2617         {
2618                 s16 max_vein_diameter = 3;
2619
2620                 // Allowed route area size in nodes
2621                 v3s16 ar(
2622                         sectorpos_base_size*MAP_BLOCKSIZE,
2623                         h_blocks*MAP_BLOCKSIZE,
2624                         sectorpos_base_size*MAP_BLOCKSIZE
2625                 );
2626
2627                 // Area starting point in nodes
2628                 v3s16 of(
2629                         sectorpos_base.X*MAP_BLOCKSIZE,
2630                         y_blocks_min*MAP_BLOCKSIZE,
2631                         sectorpos_base.Y*MAP_BLOCKSIZE
2632                 );
2633
2634                 // Allow a bit more
2635                 //(this should be more than the maximum radius of the tunnel)
2636                 s16 insure = 3;
2637                 s16 more = max_spread_amount - max_vein_diameter/2 - insure;
2638                 ar += v3s16(1,0,1) * more * 2;
2639                 of -= v3s16(1,0,1) * more;
2640                 
2641                 // Randomize starting position
2642                 v3f orp(
2643                         (float)(myrand()%ar.X)+0.5,
2644                         (float)(myrand()%ar.Y)+0.5,
2645                         (float)(myrand()%ar.Z)+0.5
2646                 );
2647
2648                 // Randomize mineral
2649                 u8 mineral = myrand_range(1, MINERAL_COUNT-1);
2650
2651                 /*
2652                         Generate some vein starting from orp
2653                 */
2654
2655                 for(u16 j=0; j<2; j++)
2656                 {
2657                         /*v3f rp(
2658                                 (float)(myrand()%ar.X)+0.5,
2659                                 (float)(myrand()%ar.Y)+0.5,
2660                                 (float)(myrand()%ar.Z)+0.5
2661                         );
2662                         v3f vec = rp - orp;*/
2663                         
2664                         v3s16 maxlen(10, 10, 10);
2665                         v3f vec(
2666                                 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2667                                 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
2668                                 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2669                         );
2670                         v3f rp = orp + vec;
2671                         if(rp.X < 0)
2672                                 rp.X = 0;
2673                         else if(rp.X >= ar.X)
2674                                 rp.X = ar.X;
2675                         if(rp.Y < 0)
2676                                 rp.Y = 0;
2677                         else if(rp.Y >= ar.Y)
2678                                 rp.Y = ar.Y;
2679                         if(rp.Z < 0)
2680                                 rp.Z = 0;
2681                         else if(rp.Z >= ar.Z)
2682                                 rp.Z = ar.Z;
2683                         vec = rp - orp;
2684
2685                         // Randomize size
2686                         s16 min_d = 0;
2687                         s16 max_d = max_vein_diameter;
2688                         s16 rs = myrand_range(min_d, max_d);
2689                         
2690                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
2691                         {
2692                                 v3f fp = orp + vec * f;
2693                                 v3s16 cp(fp.X, fp.Y, fp.Z);
2694                                 s16 d0 = -rs/2;
2695                                 s16 d1 = d0 + rs - 1;
2696                                 for(s16 z0=d0; z0<=d1; z0++)
2697                                 {
2698                                         s16 si = rs - abs(z0);
2699                                         for(s16 x0=-si; x0<=si-1; x0++)
2700                                         {
2701                                                 s16 si2 = rs - abs(x0);
2702                                                 for(s16 y0=-si2+1; y0<=si2-1; y0++)
2703                                                 {
2704                                                         // Don't put mineral to every place
2705                                                         if(myrand()%5 != 0)
2706                                                                 continue;
2707
2708                                                         s16 z = cp.Z + z0;
2709                                                         s16 y = cp.Y + y0;
2710                                                         s16 x = cp.X + x0;
2711                                                         v3s16 p(x,y,z);
2712                                                         /*if(isInArea(p, ar) == false)
2713                                                                 continue;*/
2714                                                         // Check only height
2715                                                         if(y < 0 || y >= ar.Y)
2716                                                                 continue;
2717                                                         p += of;
2718                                                         
2719                                                         assert(vmanip.m_area.contains(p));
2720                                                         
2721                                                         // Just set it to air, it will be changed to
2722                                                         // water afterwards
2723                                                         u32 i = vmanip.m_area.index(p);
2724                                                         MapNode *n = &vmanip.m_data[i];
2725                                                         if(n->d == CONTENT_STONE)
2726                                                                 n->param = mineral;
2727                                                 }
2728                                         }
2729                                 }
2730                         }
2731
2732                         orp = rp;
2733                 }
2734         
2735         }
2736
2737         }//timer1
2738         {
2739         // 15ms @cs=8
2740         //TimeTaker timer1("add mud");
2741
2742         /*
2743                 Add mud to the central chunk
2744         */
2745         
2746         for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
2747         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)
2748         {
2749                 // Node position in 2d
2750                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2751                 
2752                 // Find ground level
2753                 s16 surface_y = find_ground_level(vmanip, p2d);
2754
2755                 /*
2756                         If topmost node is grass, change it to mud.
2757                         It might be if it was flown to there from a neighboring
2758                         chunk and then converted.
2759                 */
2760                 {
2761                         u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
2762                         MapNode *n = &vmanip.m_data[i];
2763                         if(n->d == CONTENT_GRASS)
2764                                 n->d = CONTENT_MUD;
2765                 }
2766
2767                 /*
2768                         Add mud on ground
2769                 */
2770                 {
2771                         s16 mudcount = 0;
2772                         v3s16 em = vmanip.m_area.getExtent();
2773                         s16 y_start = surface_y+1;
2774                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2775                         for(s16 y=y_start; y<=y_nodes_max; y++)
2776                         {
2777                                 MapNode &n = vmanip.m_data[i];
2778                                 n.d = CONTENT_MUD;
2779                                 mudcount++;
2780                                 if(mudcount >= 3)
2781                                         break;
2782                                         
2783                                 vmanip.m_area.add_y(em, i, 1);
2784                         }
2785                 }
2786
2787         }
2788
2789         }//timer1
2790         {
2791         // 179ms @cs=8
2792         //TimeTaker timer1("flow mud");
2793
2794         /*
2795                 Flow mud away from steep edges
2796         */
2797
2798         // Iterate a few times
2799         for(s16 k=0; k<4; k++)
2800         {
2801
2802         for(s16 x=0-max_spread_amount+1;
2803                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
2804                         x++)
2805         for(s16 z=0-max_spread_amount+1;
2806                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
2807                         z++)
2808         {
2809                 // Node position in 2d
2810                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2811                 
2812                 v3s16 em = vmanip.m_area.getExtent();
2813                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2814                 s16 y;
2815                 // Go to ground level
2816                 for(y=y_nodes_max; y>=y_nodes_min; y--)
2817                 {
2818                         MapNode &n = vmanip.m_data[i];
2819                         //if(n.d != CONTENT_AIR)
2820                         if(content_walkable(n.d))
2821                                 break;
2822                                 
2823                         vmanip.m_area.add_y(em, i, -1);
2824                 }
2825
2826                 // If not mud, do nothing to it
2827                 MapNode *n = &vmanip.m_data[i];
2828                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2829                         continue;
2830
2831                 // Make it exactly mud
2832                 n->d = CONTENT_MUD;
2833
2834                 v3s16 dirs4[4] = {
2835                         v3s16(0,0,1), // back
2836                         v3s16(1,0,0), // right
2837                         v3s16(0,0,-1), // front
2838                         v3s16(-1,0,0), // left
2839                 };
2840
2841                 // Drop mud on side
2842                 
2843                 for(u32 di=0; di<4; di++)
2844                 {
2845                         v3s16 dirp = dirs4[di];
2846                         u32 i2 = i;
2847                         // Check that side is air
2848                         vmanip.m_area.add_p(em, i2, dirp);
2849                         MapNode *n2 = &vmanip.m_data[i2];
2850                         if(content_walkable(n2->d))
2851                                 continue;
2852                         // Check that under side is air
2853                         vmanip.m_area.add_y(em, i2, -1);
2854                         n2 = &vmanip.m_data[i2];
2855                         if(content_walkable(n2->d))
2856                                 continue;
2857                         // Loop further down until not air
2858                         do{
2859                                 vmanip.m_area.add_y(em, i2, -1);
2860                                 n2 = &vmanip.m_data[i2];
2861                         }while(content_walkable(n2->d) == false);
2862                         // Loop one up so that we're in air
2863                         vmanip.m_area.add_y(em, i2, 1);
2864                         n2 = &vmanip.m_data[i2];
2865
2866                         // Move mud to new place
2867                         *n2 = *n;
2868                         // Set old place to be air
2869                         *n = MapNode(CONTENT_AIR);
2870
2871                         #if 0
2872                         // Switch mud and other and change mud source to air
2873                         //MapNode tempnode = *n2;
2874                         *n2 = *n;
2875                         //*n = tempnode;
2876                         // Force old mud position to be air
2877                         n->d = CONTENT_AIR;
2878                         #endif
2879
2880                         // Done
2881                         break;
2882                 }
2883         }
2884         
2885         }
2886
2887         }//timer1
2888         {
2889         // 50ms @cs=8
2890         //TimeTaker timer1("add water");
2891
2892         /*
2893                 Add water to the central chunk (and a bit more)
2894         */
2895         
2896         for(s16 x=0-max_spread_amount;
2897                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
2898                         x++)
2899         for(s16 z=0-max_spread_amount;
2900                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
2901                         z++)
2902         {
2903                 // Node position in 2d
2904                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2905                 
2906                 // Find ground level
2907                 //s16 surface_y = find_ground_level(vmanip, p2d);
2908
2909                 /*
2910                         If ground level is over water level, skip.
2911                         NOTE: This leaves caves near water without water,
2912                         which looks especially crappy when the nearby water
2913                         won't start flowing either for some reason
2914                 */
2915                 /*if(surface_y > WATER_LEVEL)
2916                         continue;*/
2917
2918                 /*
2919                         Add water on ground
2920                 */
2921                 {
2922                         v3s16 em = vmanip.m_area.getExtent();
2923                         s16 y_start = WATER_LEVEL;
2924                         u8 light = LIGHT_MAX;
2925                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2926                         MapNode *n = &vmanip.m_data[i];
2927                         /*
2928                                 Add first one to transforming liquid queue
2929                         */
2930                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
2931                         {
2932                                 v3s16 p = v3s16(p2d.X, y_start, p2d.Y);
2933                                 m_transforming_liquid.push_back(p);
2934                         }
2935                         for(s16 y=y_start; y>=y_nodes_min; y--)
2936                         {
2937                                 n = &vmanip.m_data[i];
2938                                 
2939                                 // Stop when there is no water and no air
2940                                 if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
2941                                                 && n->d != CONTENT_WATER)
2942                                 {
2943                                         /*
2944                                                 Add bottom one to transforming liquid queue
2945                                         */
2946                                         vmanip.m_area.add_y(em, i, 1);
2947                                         n = &vmanip.m_data[i];
2948                                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
2949                                         {
2950                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2951                                                 m_transforming_liquid.push_back(p);
2952                                         }
2953
2954                                         break;
2955                                 }
2956                                 
2957                                 n->d = CONTENT_WATERSOURCE;
2958                                 n->setLight(LIGHTBANK_DAY, light);
2959
2960                                 /*// Add to transforming liquid queue (in case it'd
2961                                 // start flowing)
2962                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2963                                 m_transforming_liquid.push_back(p);*/
2964                                 
2965                                 // Next one
2966                                 vmanip.m_area.add_y(em, i, -1);
2967                                 if(light > 0)
2968                                         light--;
2969                         }
2970                 }
2971
2972         }
2973
2974         }//timer1
2975         
2976         } // Aging loop
2977
2978         {
2979         // 1ms @cs=8
2980         //TimeTaker timer1("plant trees");
2981
2982         /*
2983                 Plant some trees
2984         */
2985         {
2986                 u32 tree_max = relative_area / 60;
2987                 
2988                 u32 count = myrand_range(0, tree_max);
2989                 for(u32 i=0; i<count; i++)
2990                 {
2991                         s16 x = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
2992                         s16 z = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
2993                         x += sectorpos_base.X*MAP_BLOCKSIZE;
2994                         z += sectorpos_base.Y*MAP_BLOCKSIZE;
2995                         s16 y = find_ground_level(vmanip, v2s16(x,z));
2996                         // Don't make a tree under water level
2997                         if(y < WATER_LEVEL)
2998                                 continue;
2999                         v3s16 p(x,y+1,z);
3000                         // Make a tree
3001                         make_tree(vmanip, p);
3002                 }
3003         }
3004
3005         }//timer1
3006
3007         {
3008         // 19ms @cs=8
3009         //TimeTaker timer1("grow grass");
3010
3011         /*
3012                 Grow grass
3013         */
3014
3015         /*for(s16 x=0-4; x<sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
3016         for(s16 z=0-4; z<sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
3017         for(s16 x=0-max_spread_amount;
3018                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3019                         x++)
3020         for(s16 z=0-max_spread_amount;
3021                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3022                         z++)
3023         {
3024                 // Node position in 2d
3025                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3026                 
3027                 /*
3028                         Find the lowest surface to which enough light ends up
3029                         to make grass grow.
3030
3031                         Basically just wait until not air and not leaves.
3032                 */
3033                 s16 surface_y = 0;
3034                 {
3035                         v3s16 em = vmanip.m_area.getExtent();
3036                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3037                         s16 y;
3038                         // Go to ground level
3039                         for(y=y_nodes_max; y>=y_nodes_min; y--)
3040                         {
3041                                 MapNode &n = vmanip.m_data[i];
3042                                 if(n.d != CONTENT_AIR
3043                                                 && n.d != CONTENT_LEAVES)
3044                                         break;
3045                                 vmanip.m_area.add_y(em, i, -1);
3046                         }
3047                         if(y >= y_nodes_min)
3048                                 surface_y = y;
3049                         else
3050                                 surface_y = y_nodes_min;
3051                 }
3052                 
3053                 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
3054                 MapNode *n = &vmanip.m_data[i];
3055                 if(n->d == CONTENT_MUD)
3056                         n->d = CONTENT_GRASS;
3057         }
3058
3059         }//timer1
3060
3061         /*
3062                 Handle lighting
3063         */
3064
3065         core::map<v3s16, bool> light_sources;
3066
3067         {
3068         // 750ms @cs=8, can't optimize more
3069         //TimeTaker timer1("initial lighting");
3070
3071         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3072         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3073         for(s16 x=0-max_spread_amount+1;
3074                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3075                         x++)
3076         for(s16 z=0-max_spread_amount+1;
3077                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3078                         z++)
3079         {
3080                 // Node position in 2d
3081                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3082                 
3083                 /*
3084                         Apply initial sunlight
3085                 */
3086                 {
3087                         u8 light = LIGHT_SUN;
3088                         bool add_to_sources = false;
3089                         v3s16 em = vmanip.m_area.getExtent();
3090                         s16 y_start = y_nodes_max;
3091                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3092                         for(s16 y=y_start; y>=y_nodes_min; y--)
3093                         {
3094                                 MapNode *n = &vmanip.m_data[i];
3095
3096                                 if(light_propagates_content(n->d) == false)
3097                                 {
3098                                         light = 0;
3099                                 }
3100                                 else if(light != LIGHT_SUN
3101                                         || sunlight_propagates_content(n->d) == false)
3102                                 {
3103                                         if(light > 0)
3104                                                 light--;
3105                                 }
3106                                 
3107                                 // This doesn't take much time
3108                                 if(add_to_sources == false)
3109                                 {
3110                                         /*
3111                                                 Check sides. If side is not air or water, start
3112                                                 adding to light_sources.
3113                                         */
3114                                         v3s16 dirs4[4] = {
3115                                                 v3s16(0,0,1), // back
3116                                                 v3s16(1,0,0), // right
3117                                                 v3s16(0,0,-1), // front
3118                                                 v3s16(-1,0,0), // left
3119                                         };
3120                                         for(u32 di=0; di<4; di++)
3121                                         {
3122                                                 v3s16 dirp = dirs4[di];
3123                                                 u32 i2 = i;
3124                                                 vmanip.m_area.add_p(em, i2, dirp);
3125                                                 MapNode *n2 = &vmanip.m_data[i2];
3126                                                 if(
3127                                                         n2->d != CONTENT_AIR
3128                                                         && n2->d != CONTENT_WATERSOURCE
3129                                                         && n2->d != CONTENT_WATER
3130                                                 ){
3131                                                         add_to_sources = true;
3132                                                         break;
3133                                                 }
3134                                         }
3135                                 }
3136
3137                                 n->setLight(LIGHTBANK_DAY, light);
3138                                 n->setLight(LIGHTBANK_NIGHT, 0);
3139                                 
3140                                 // This doesn't take much time
3141                                 if(light != 0 && add_to_sources)
3142                                 {
3143                                         // Insert light source
3144                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3145                                 }
3146                                 
3147                                 // Increment index by y
3148                                 vmanip.m_area.add_y(em, i, -1);
3149                         }
3150                 }
3151         }
3152
3153         }//timer1
3154
3155         // Spread light around
3156         {
3157                 TimeTaker timer("generateChunkRaw() spreadLight");
3158                 vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
3159         }
3160         
3161         /*
3162                 Generation ended
3163         */
3164
3165         timer_generate.stop();
3166
3167         /*
3168                 Blit generated stuff to map
3169         */
3170         {
3171                 // 70ms @cs=8
3172                 //TimeTaker timer("generateChunkRaw() blitBackAll");
3173                 vmanip.blitBackAll(&changed_blocks);
3174         }
3175         /*
3176                 Update day/night difference cache of the MapBlocks
3177         */
3178         {
3179                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
3180                                 i.atEnd() == false; i++)
3181                 {
3182                         MapBlock *block = i.getNode()->getValue();
3183                         block->updateDayNightDiff();
3184                 }
3185         }
3186
3187         
3188         /*
3189                 Create chunk metadata
3190         */
3191
3192         for(s16 x=-1; x<=1; x++)
3193         for(s16 y=-1; y<=1; y++)
3194         {
3195                 v2s16 chunkpos0 = chunkpos + v2s16(x,y);
3196                 // Add chunk meta information
3197                 MapChunk *chunk = getChunk(chunkpos0);
3198                 if(chunk == NULL)
3199                 {
3200                         chunk = new MapChunk();
3201                         m_chunks.insert(chunkpos0, chunk);
3202                 }
3203                 //chunk->setIsVolatile(true);
3204                 if(chunk->getGenLevel() > GENERATED_PARTLY)
3205                         chunk->setGenLevel(GENERATED_PARTLY);
3206         }
3207
3208         /*
3209                 Set central chunk non-volatile and return it
3210         */
3211         MapChunk *chunk = getChunk(chunkpos);
3212         assert(chunk);
3213         // Set non-volatile
3214         //chunk->setIsVolatile(false);
3215         chunk->setGenLevel(GENERATED_FULLY);
3216         // Return it
3217         return chunk;
3218 }
3219
3220 MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
3221                 core::map<v3s16, MapBlock*> &changed_blocks)
3222 {
3223         dstream<<"generateChunk(): Generating chunk "
3224                         <<"("<<chunkpos1.X<<","<<chunkpos1.Y<<")"
3225                         <<std::endl;
3226         
3227         /*for(s16 x=-1; x<=1; x++)
3228         for(s16 y=-1; y<=1; y++)*/
3229         for(s16 x=-0; x<=0; x++)
3230         for(s16 y=-0; y<=0; y++)
3231         {
3232                 v2s16 chunkpos0 = chunkpos1 + v2s16(x,y);
3233                 MapChunk *chunk = getChunk(chunkpos0);
3234                 // Skip if already generated
3235                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
3236                         continue;
3237                 generateChunkRaw(chunkpos0, changed_blocks);
3238         }
3239         
3240         assert(chunkNonVolatile(chunkpos1));
3241
3242         MapChunk *chunk = getChunk(chunkpos1);
3243         return chunk;
3244 }
3245
3246 ServerMapSector * ServerMap::createSector(v2s16 p2d)
3247 {
3248         DSTACK("%s: p2d=(%d,%d)",
3249                         __FUNCTION_NAME,
3250                         p2d.X, p2d.Y);
3251         
3252         /*
3253                 Check if it exists already in memory
3254         */
3255         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3256         if(sector != NULL)
3257                 return sector;
3258         
3259         /*
3260                 Try to load it from disk (with blocks)
3261         */
3262         if(loadSectorFull(p2d) == true)
3263         {
3264                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3265                 if(sector == NULL)
3266                 {
3267                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
3268                         throw InvalidPositionException("");
3269                 }
3270                 return sector;
3271         }
3272
3273         /*
3274                 If there is no master heightmap, throw.
3275         */
3276         if(m_heightmap == NULL)
3277         {
3278                 throw InvalidPositionException("createSector(): no heightmap");
3279         }
3280
3281         /*
3282                 Do not create over-limit
3283         */
3284         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3285         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3286         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3287         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
3288                 throw InvalidPositionException("createSector(): pos. over limit");
3289
3290         /*
3291                 Generate blank sector
3292         */
3293         
3294         // Number of heightmaps in sector in each direction
3295         u16 hm_split = SECTOR_HEIGHTMAP_SPLIT;
3296
3297         // Heightmap side width
3298         s16 hm_d = MAP_BLOCKSIZE / hm_split;
3299
3300         sector = new ServerMapSector(this, p2d, hm_split);
3301         
3302         // Sector position on map in nodes
3303         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
3304
3305         /*dstream<<"Generating sector ("<<p2d.X<<","<<p2d.Y<<")"
3306                         " heightmaps and objects"<<std::endl;*/
3307         
3308         /*
3309                 Generate sector heightmap
3310         */
3311
3312         v2s16 mhm_p = p2d * hm_split;
3313         /*f32 corners[4] = {
3314                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split),
3315                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split),
3316                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split),
3317                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split),
3318         };*/
3319         
3320         // Loop through sub-heightmaps
3321         for(s16 y=0; y<hm_split; y++)
3322         for(s16 x=0; x<hm_split; x++)
3323         {
3324                 v2s16 p_in_sector = v2s16(x,y);
3325                 v2s16 mhm_p = p2d * hm_split + p_in_sector;
3326                 f32 corners[4] = {
3327                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)),
3328                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)),
3329                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)),
3330                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)),
3331                 };
3332
3333                 /*dstream<<"p_in_sector=("<<p_in_sector.X<<","<<p_in_sector.Y<<")"
3334                                 <<" mhm_p=("<<mhm_p.X<<","<<mhm_p.Y<<")"
3335                                 <<std::endl;*/
3336
3337                 FixedHeightmap *hm = new FixedHeightmap(&m_hwrapper,
3338                                 mhm_p, hm_d);
3339                 sector->setHeightmap(p_in_sector, hm);
3340
3341                 //hm->generateContinued(1.0, 0.5, corners);
3342                 hm->generateContinued(0.5, 0.5, corners);
3343
3344                 //hm->print();
3345         }
3346         
3347         // Add dummy objects
3348         core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
3349         sector->setObjects(objects);
3350         
3351         /*
3352                 Insert to container
3353         */
3354         m_sectors.insert(p2d, sector);
3355         
3356         return sector;
3357 }
3358
3359 MapSector * ServerMap::emergeSector(v2s16 p2d,
3360                 core::map<v3s16, MapBlock*> &changed_blocks)
3361 {
3362         DSTACK("%s: p2d=(%d,%d)",
3363                         __FUNCTION_NAME,
3364                         p2d.X, p2d.Y);
3365         
3366         /*
3367                 Check chunk status
3368         */
3369         v2s16 chunkpos = sector_to_chunk(p2d);
3370         /*bool chunk_nonvolatile = false;
3371         MapChunk *chunk = getChunk(chunkpos);
3372         if(chunk && chunk->getIsVolatile() == false)
3373                 chunk_nonvolatile = true;*/
3374         bool chunk_nonvolatile = chunkNonVolatile(chunkpos);
3375
3376         /*
3377                 If chunk is not fully generated, generate chunk
3378         */
3379         if(chunk_nonvolatile == false)
3380         {
3381                 // Generate chunk and neighbors
3382                 generateChunk(chunkpos, changed_blocks);
3383         }
3384         
3385         /*
3386                 Return sector if it exists now
3387         */
3388         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3389         if(sector != NULL)
3390                 return sector;
3391         
3392         /*
3393                 Try to load it from disk
3394         */
3395         if(loadSectorFull(p2d) == true)
3396         {
3397                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
3398                 if(sector == NULL)
3399                 {
3400                         dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<<std::endl;
3401                         throw InvalidPositionException("");
3402                 }
3403                 return sector;
3404         }
3405
3406         /*
3407                 generateChunk should have generated the sector
3408         */
3409         assert(0);
3410
3411         /*
3412                 Generate directly
3413         */
3414         //return generateSector();
3415 }
3416
3417 /*
3418         NOTE: This is not used for main map generation, only for blocks
3419         that are very high or low
3420 */
3421 MapBlock * ServerMap::generateBlock(
3422                 v3s16 p,
3423                 MapBlock *original_dummy,
3424                 ServerMapSector *sector,
3425                 core::map<v3s16, MapBlock*> &changed_blocks,
3426                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
3427 )
3428 {
3429         DSTACK("%s: p=(%d,%d,%d)",
3430                         __FUNCTION_NAME,
3431                         p.X, p.Y, p.Z);
3432         
3433         /*dstream<<"generateBlock(): "
3434                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3435                         <<std::endl;*/
3436         
3437         MapBlock *block = original_dummy;
3438                         
3439         v2s16 p2d(p.X, p.Z);
3440         s16 block_y = p.Y;
3441         
3442         /*
3443                 Do not generate over-limit
3444         */
3445         if(blockpos_over_limit(p))
3446         {
3447                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
3448                 throw InvalidPositionException("generateBlock(): pos. over limit");
3449         }
3450
3451         /*
3452                 If block doesn't exist, create one.
3453                 If it exists, it is a dummy. In that case unDummify() it.
3454
3455                 NOTE: This already sets the map as the parent of the block
3456         */
3457         if(block == NULL)
3458         {
3459                 block = sector->createBlankBlockNoInsert(block_y);
3460         }
3461         else
3462         {
3463                 // Remove the block so that nobody can get a half-generated one.
3464                 sector->removeBlock(block);
3465                 // Allocate the block to contain the generated data
3466                 block->unDummify();
3467         }
3468         
3469         /*u8 water_material = CONTENT_WATER;
3470         if(g_settings.getBool("endless_water"))
3471                 water_material = CONTENT_WATERSOURCE;*/
3472         u8 water_material = CONTENT_WATERSOURCE;
3473         
3474         s32 lowest_ground_y = 32767;
3475         s32 highest_ground_y = -32768;
3476         
3477         // DEBUG
3478         //sector->printHeightmaps();
3479
3480         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3481         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3482         {
3483                 //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
3484
3485                 float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
3486                 //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
3487                 if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE)
3488                 {
3489                         dstream<<"WARNING: Surface height not found in sector "
3490                                         "for block that is being emerged"<<std::endl;
3491                         surface_y_f = 0.0;
3492                 }
3493
3494                 s16 surface_y = surface_y_f;
3495                 //avg_ground_y += surface_y;
3496                 if(surface_y < lowest_ground_y)
3497                         lowest_ground_y = surface_y;
3498                 if(surface_y > highest_ground_y)
3499                         highest_ground_y = surface_y;
3500
3501                 s32 surface_depth = 0;
3502                 
3503                 float slope = sector->getSlope(v2s16(x0,z0)).getLength();
3504                 
3505                 //float min_slope = 0.45;
3506                 //float max_slope = 0.85;
3507                 float min_slope = 0.60;
3508                 float max_slope = 1.20;
3509                 float min_slope_depth = 5.0;
3510                 float max_slope_depth = 0;
3511
3512                 if(slope < min_slope)
3513                         surface_depth = min_slope_depth;
3514                 else if(slope > max_slope)
3515                         surface_depth = max_slope_depth;
3516                 else
3517                         surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
3518
3519                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3520                 {
3521                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
3522                         MapNode n;
3523                         /*
3524                                 Calculate lighting
3525                                 
3526                                 NOTE: If there are some man-made structures above the
3527                                 newly created block, they won't be taken into account.
3528                         */
3529                         if(real_y > surface_y)
3530                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
3531
3532                         /*
3533                                 Calculate material
3534                         */
3535
3536                         // If node is over heightmap y, it's air or water
3537                         if(real_y > surface_y)
3538                         {
3539                                 // If under water level, it's water
3540                                 if(real_y < WATER_LEVEL)
3541                                 {
3542                                         n.d = water_material;
3543                                         n.setLight(LIGHTBANK_DAY,
3544                                                         diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
3545                                         /*
3546                                                 Add to transforming liquid queue (in case it'd
3547                                                 start flowing)
3548                                         */
3549                                         v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
3550                                         m_transforming_liquid.push_back(real_pos);
3551                                 }
3552                                 // else air
3553                                 else
3554                                         n.d = CONTENT_AIR;
3555                         }
3556                         // Else it's ground or dungeons (air)
3557                         else
3558                         {
3559                                 // If it's surface_depth under ground, it's stone
3560                                 if(real_y <= surface_y - surface_depth)
3561                                 {
3562                                         n.d = CONTENT_STONE;
3563                                 }
3564                                 else
3565                                 {
3566                                         // It is mud if it is under the first ground
3567                                         // level or under water
3568                                         if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
3569                                         {
3570                                                 n.d = CONTENT_MUD;
3571                                         }
3572                                         else
3573                                         {
3574                                                 n.d = CONTENT_GRASS;
3575                                         }
3576
3577                                         //n.d = CONTENT_MUD;
3578                                         
3579                                         /*// If under water level, it's mud
3580                                         if(real_y < WATER_LEVEL)
3581                                                 n.d = CONTENT_MUD;
3582                                         // Only the topmost node is grass
3583                                         else if(real_y <= surface_y - 1)
3584                                                 n.d = CONTENT_MUD;
3585                                         else
3586                                                 n.d = CONTENT_GRASS;*/
3587                                 }
3588                         }
3589
3590                         block->setNode(v3s16(x0,y0,z0), n);
3591                 }
3592         }
3593         
3594         /*
3595                 Calculate some helper variables
3596         */
3597         
3598         // Completely underground if the highest part of block is under lowest
3599         // ground height.
3600         // This has to be very sure; it's probably one too strict now but
3601         // that's just better.
3602         bool completely_underground =
3603                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
3604
3605         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
3606
3607         bool mostly_underwater_surface = false;
3608         if(highest_ground_y < WATER_LEVEL
3609                         && some_part_underground && !completely_underground)
3610                 mostly_underwater_surface = true;
3611
3612         /*
3613                 Get local attributes
3614         */
3615
3616         //dstream<<"generateBlock(): Getting local attributes"<<std::endl;
3617
3618         float caves_amount = 0.5;
3619
3620 #if 0
3621         {
3622                 /*
3623                         NOTE: BEWARE: Too big amount of attribute points slows verything
3624                         down by a lot.
3625                         1 interpolation from 5000 points takes 2-3ms.
3626                 */
3627                 //TimeTaker timer("generateBlock() local attribute retrieval");
3628                 v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
3629                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
3630                 caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
3631         }
3632 #endif
3633
3634         //dstream<<"generateBlock(): Done"<<std::endl;
3635
3636         /*
3637                 Generate dungeons
3638         */
3639
3640         // Initialize temporary table
3641         const s32 ued = MAP_BLOCKSIZE;
3642         bool underground_emptiness[ued*ued*ued];
3643         for(s32 i=0; i<ued*ued*ued; i++)
3644         {
3645                 underground_emptiness[i] = 0;
3646         }
3647         
3648         // Fill table
3649 #if 1
3650         {
3651                 /*
3652                         Initialize orp and ors. Try to find if some neighboring
3653                         MapBlock has a tunnel ended in its side
3654                 */
3655
3656                 v3f orp(
3657                         (float)(myrand()%ued)+0.5,
3658                         (float)(myrand()%ued)+0.5,
3659                         (float)(myrand()%ued)+0.5
3660                 );
3661                 
3662                 bool found_existing = false;
3663
3664                 // Check z-
3665                 try
3666                 {
3667                         s16 z = -1;
3668                         for(s16 y=0; y<ued; y++)
3669                         for(s16 x=0; x<ued; x++)
3670                         {
3671                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
3672                                 if(getNode(ap).d == CONTENT_AIR)
3673                                 {
3674                                         orp = v3f(x+1,y+1,0);
3675                                         found_existing = true;
3676                                         goto continue_generating;
3677                                 }
3678                         }
3679                 }
3680                 catch(InvalidPositionException &e){}
3681                 
3682                 // Check z+
3683                 try
3684                 {
3685                         s16 z = ued;
3686                         for(s16 y=0; y<ued; y++)
3687                         for(s16 x=0; x<ued; x++)
3688                         {
3689                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
3690                                 if(getNode(ap).d == CONTENT_AIR)
3691                                 {
3692                                         orp = v3f(x+1,y+1,ued-1);
3693                                         found_existing = true;
3694                                         goto continue_generating;
3695                                 }
3696                         }
3697                 }
3698                 catch(InvalidPositionException &e){}
3699                 
3700                 // Check x-
3701                 try
3702                 {
3703                         s16 x = -1;
3704                         for(s16 y=0; y<ued; y++)
3705                         for(s16 z=0; z<ued; z++)
3706                         {
3707                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
3708                                 if(getNode(ap).d == CONTENT_AIR)
3709                                 {
3710                                         orp = v3f(0,y+1,z+1);
3711                                         found_existing = true;
3712                                         goto continue_generating;
3713                                 }
3714                         }
3715                 }
3716                 catch(InvalidPositionException &e){}
3717                 
3718                 // Check x+
3719                 try
3720                 {
3721                         s16 x = ued;
3722                         for(s16 y=0; y<ued; y++)
3723                         for(s16 z=0; z<ued; z++)
3724                         {
3725                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
3726                                 if(getNode(ap).d == CONTENT_AIR)
3727                                 {
3728                                         orp = v3f(ued-1,y+1,z+1);
3729                                         found_existing = true;
3730                                         goto continue_generating;
3731                                 }
3732                         }
3733                 }
3734                 catch(InvalidPositionException &e){}
3735
3736                 // Check y-
3737                 try
3738                 {
3739                         s16 y = -1;
3740                         for(s16 x=0; x<ued; x++)
3741                         for(s16 z=0; z<ued; z++)
3742                         {
3743                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
3744                                 if(getNode(ap).d == CONTENT_AIR)
3745                                 {
3746                                         orp = v3f(x+1,0,z+1);
3747                                         found_existing = true;
3748                                         goto continue_generating;
3749                                 }
3750                         }
3751                 }
3752                 catch(InvalidPositionException &e){}
3753                 
3754                 // Check y+
3755                 try
3756                 {
3757                         s16 y = ued;
3758                         for(s16 x=0; x<ued; x++)
3759                         for(s16 z=0; z<ued; z++)
3760                         {
3761                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
3762                                 if(getNode(ap).d == CONTENT_AIR)
3763                                 {
3764                                         orp = v3f(x+1,ued-1,z+1);
3765                                         found_existing = true;
3766                                         goto continue_generating;
3767                                 }
3768                         }
3769                 }
3770                 catch(InvalidPositionException &e){}
3771
3772 continue_generating:
3773                 
3774                 /*
3775                         Choose whether to actually generate dungeon
3776                 */
3777                 bool do_generate_dungeons = true;
3778                 // Don't generate if no part is underground
3779                 if(!some_part_underground)
3780                 {
3781                         do_generate_dungeons = false;
3782                 }
3783                 // Don't generate if mostly underwater surface
3784                 /*else if(mostly_underwater_surface)
3785                 {
3786                         do_generate_dungeons = false;
3787                 }*/
3788                 // Partly underground = cave
3789                 else if(!completely_underground)
3790                 {
3791                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
3792                 }
3793                 // Found existing dungeon underground
3794                 else if(found_existing && completely_underground)
3795                 {
3796                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
3797                 }
3798                 // Underground and no dungeons found
3799                 else
3800                 {
3801                         do_generate_dungeons = (rand() % 300 <= (s32)(caves_amount*100));
3802                 }
3803
3804                 if(do_generate_dungeons)
3805                 {
3806                         /*
3807                                 Generate some tunnel starting from orp and ors
3808                         */
3809                         for(u16 i=0; i<3; i++)
3810                         {
3811                                 v3f rp(
3812                                         (float)(myrand()%ued)+0.5,
3813                                         (float)(myrand()%ued)+0.5,
3814                                         (float)(myrand()%ued)+0.5
3815                                 );
3816                                 s16 min_d = 0;
3817                                 s16 max_d = 4;
3818                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
3819                                 
3820                                 v3f vec = rp - orp;
3821
3822                                 for(float f=0; f<1.0; f+=0.04)
3823                                 {
3824                                         v3f fp = orp + vec * f;
3825                                         v3s16 cp(fp.X, fp.Y, fp.Z);
3826                                         s16 d0 = -rs/2;
3827                                         s16 d1 = d0 + rs - 1;
3828                                         for(s16 z0=d0; z0<=d1; z0++)
3829                                         {
3830                                                 s16 si = rs - abs(z0);
3831                                                 for(s16 x0=-si; x0<=si-1; x0++)
3832                                                 {
3833                                                         s16 si2 = rs - abs(x0);
3834                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
3835                                                         {
3836                                                                 s16 z = cp.Z + z0;
3837                                                                 s16 y = cp.Y + y0;
3838                                                                 s16 x = cp.X + x0;
3839                                                                 v3s16 p(x,y,z);
3840                                                                 if(isInArea(p, ued) == false)
3841                                                                         continue;
3842                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
3843                                                         }
3844                                                 }
3845                                         }
3846                                 }
3847
3848                                 orp = rp;
3849                         }
3850                 }
3851         }
3852 #endif
3853
3854         // Set to true if has caves.
3855         // Set when some non-air is changed to air when making caves.
3856         bool has_dungeons = false;
3857
3858         /*
3859                 Apply temporary cave data to block
3860         */
3861
3862         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3863         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3864         {
3865                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3866                 {
3867                         MapNode n = block->getNode(v3s16(x0,y0,z0));
3868
3869                         // Create dungeons
3870                         if(underground_emptiness[
3871                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
3872                                         +ued*(y0*ued/MAP_BLOCKSIZE)
3873                                         +(x0*ued/MAP_BLOCKSIZE)])
3874                         {
3875                                 if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
3876                                 {
3877                                         // Has now caves
3878                                         has_dungeons = true;
3879                                         // Set air to node
3880                                         n.d = CONTENT_AIR;
3881                                 }
3882                         }
3883
3884                         block->setNode(v3s16(x0,y0,z0), n);
3885                 }
3886         }
3887         
3888         /*
3889                 This is used for guessing whether or not the block should
3890                 receive sunlight from the top if the block above doesn't exist
3891         */
3892         block->setIsUnderground(completely_underground);
3893
3894         /*
3895                 Force lighting update if some part of block is partly
3896                 underground and has caves.
3897         */
3898         /*if(some_part_underground && !completely_underground && has_dungeons)
3899         {
3900                 //dstream<<"Half-ground caves"<<std::endl;
3901                 lighting_invalidated_blocks[block->getPos()] = block;
3902         }*/
3903         
3904         // DEBUG: Always update lighting
3905         //lighting_invalidated_blocks[block->getPos()] = block;
3906
3907         /*
3908                 Add some minerals
3909         */
3910
3911         if(some_part_underground)
3912         {
3913                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
3914
3915                 /*
3916                         Add meseblocks
3917                 */
3918                 for(s16 i=0; i<underground_level/4 + 1; i++)
3919                 {
3920                         if(myrand()%50 == 0)
3921                         {
3922                                 v3s16 cp(
3923                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
3924                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
3925                                         (myrand()%(MAP_BLOCKSIZE-2))+1
3926                                 );
3927
3928                                 MapNode n;
3929                                 n.d = CONTENT_MESE;
3930                                 
3931                                 for(u16 i=0; i<27; i++)
3932                                 {
3933                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
3934                                                 if(myrand()%8 == 0)
3935                                                         block->setNode(cp+g_27dirs[i], n);
3936                                 }
3937                         }
3938                 }
3939
3940                 /*
3941                         Add coal
3942                 */
3943                 u16 coal_amount = 30.0 * g_settings.getFloat("coal_amount");
3944                 u16 coal_rareness = 60 / coal_amount;
3945                 if(coal_rareness == 0)
3946                         coal_rareness = 1;
3947                 if(myrand()%coal_rareness == 0)
3948                 {
3949                         u16 a = myrand() % 16;
3950                         u16 amount = coal_amount * a*a*a / 1000;
3951                         for(s16 i=0; i<amount; i++)
3952                         {
3953                                 v3s16 cp(
3954                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
3955                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
3956                                         (myrand()%(MAP_BLOCKSIZE-2))+1
3957                                 );
3958
3959                                 MapNode n;
3960                                 n.d = CONTENT_STONE;
3961                                 n.param = MINERAL_COAL;
3962
3963                                 for(u16 i=0; i<27; i++)
3964                                 {
3965                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
3966                                                 if(myrand()%8 == 0)
3967                                                         block->setNode(cp+g_27dirs[i], n);
3968                                 }
3969                         }
3970                 }
3971
3972                 /*
3973                         Add iron
3974                 */
3975                 //TODO: change to iron_amount or whatever
3976                 u16 iron_amount = 30.0 * g_settings.getFloat("coal_amount");
3977                 u16 iron_rareness = 60 / iron_amount;
3978                 if(iron_rareness == 0)
3979                         iron_rareness = 1;
3980                 if(myrand()%iron_rareness == 0)
3981                 {
3982                         u16 a = myrand() % 16;
3983                         u16 amount = iron_amount * a*a*a / 1000;
3984                         for(s16 i=0; i<amount; i++)
3985                         {
3986                                 v3s16 cp(
3987                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
3988                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
3989                                         (myrand()%(MAP_BLOCKSIZE-2))+1
3990                                 );
3991
3992                                 MapNode n;
3993                                 n.d = CONTENT_STONE;
3994                                 n.param = MINERAL_IRON;
3995
3996                                 for(u16 i=0; i<27; i++)
3997                                 {
3998                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
3999                                                 if(myrand()%8 == 0)
4000                                                         block->setNode(cp+g_27dirs[i], n);
4001                                 }
4002                         }
4003                 }
4004         }
4005         
4006         /*
4007                 Create a few rats in empty blocks underground
4008         */
4009         if(completely_underground)
4010         {
4011                 //for(u16 i=0; i<2; i++)
4012                 {
4013                         v3s16 cp(
4014                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4015                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4016                                 (myrand()%(MAP_BLOCKSIZE-2))+1
4017                         );
4018
4019                         // Check that the place is empty
4020                         //if(!is_ground_content(block->getNode(cp).d))
4021                         if(1)
4022                         {
4023                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
4024                                 block->addObject(obj);
4025                         }
4026                 }
4027         }
4028         
4029         /*
4030                 Add block to sector.
4031         */
4032         sector->insertBlock(block);
4033         
4034         /*
4035                 Sector object stuff
4036         */
4037                 
4038         // An y-wise container of changed blocks
4039         core::map<s16, MapBlock*> changed_blocks_sector;
4040
4041         /*
4042                 Check if any sector's objects can be placed now.
4043                 If so, place them.
4044         */
4045         core::map<v3s16, u8> *objects = sector->getObjects();
4046         core::list<v3s16> objects_to_remove;
4047         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
4048                         i.atEnd() == false; i++)
4049         {
4050                 v3s16 p = i.getNode()->getKey();
4051                 v2s16 p2d(p.X,p.Z);
4052                 u8 d = i.getNode()->getValue();
4053
4054                 // Ground level point (user for stuff that is on ground)
4055                 v3s16 gp = p;
4056                 bool ground_found = true;
4057                 
4058                 // Search real ground level
4059                 try{
4060                         for(;;)
4061                         {
4062                                 MapNode n = sector->getNode(gp);
4063
4064                                 // If not air, go one up and continue to placing the tree
4065                                 if(n.d != CONTENT_AIR)
4066                                 {
4067                                         gp += v3s16(0,1,0);
4068                                         break;
4069                                 }
4070
4071                                 // If air, go one down
4072                                 gp += v3s16(0,-1,0);
4073                         }
4074                 }catch(InvalidPositionException &e)
4075                 {
4076                         // Ground not found.
4077                         ground_found = false;
4078                         // This is most close to ground
4079                         gp += v3s16(0,1,0);
4080                 }
4081
4082                 try
4083                 {
4084
4085                 if(d == SECTOR_OBJECT_TEST)
4086                 {
4087                         if(sector->isValidArea(p + v3s16(0,0,0),
4088                                         p + v3s16(0,0,0), &changed_blocks_sector))
4089                         {
4090                                 MapNode n;
4091                                 n.d = CONTENT_TORCH;
4092                                 sector->setNode(p, n);
4093                                 objects_to_remove.push_back(p);
4094                         }
4095                 }
4096                 else if(d == SECTOR_OBJECT_TREE_1)
4097                 {
4098                         if(ground_found == false)
4099                                 continue;
4100
4101                         v3s16 p_min = gp + v3s16(-1,0,-1);
4102                         v3s16 p_max = gp + v3s16(1,5,1);
4103                         if(sector->isValidArea(p_min, p_max,
4104                                         &changed_blocks_sector))
4105                         {
4106                                 MapNode n;
4107                                 n.d = CONTENT_TREE;
4108                                 sector->setNode(gp+v3s16(0,0,0), n);
4109                                 sector->setNode(gp+v3s16(0,1,0), n);
4110                                 sector->setNode(gp+v3s16(0,2,0), n);
4111                                 sector->setNode(gp+v3s16(0,3,0), n);
4112
4113                                 n.d = CONTENT_LEAVES;
4114
4115                                 if(myrand()%4!=0) sector->setNode(gp+v3s16(0,5,0), n);
4116
4117                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,0), n);
4118                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,0), n);
4119                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,5,-1), n);
4120                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,5,1), n);
4121                                 /*if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,1), n);
4122                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,1), n);
4123                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,-1), n);
4124                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,-1), n);*/
4125
4126                                 sector->setNode(gp+v3s16(0,4,0), n);
4127                                 
4128                                 sector->setNode(gp+v3s16(-1,4,0), n);
4129                                 sector->setNode(gp+v3s16(1,4,0), n);
4130                                 sector->setNode(gp+v3s16(0,4,-1), n);
4131                                 sector->setNode(gp+v3s16(0,4,1), n);
4132                                 sector->setNode(gp+v3s16(1,4,1), n);
4133                                 sector->setNode(gp+v3s16(-1,4,1), n);
4134                                 sector->setNode(gp+v3s16(-1,4,-1), n);
4135                                 sector->setNode(gp+v3s16(1,4,-1), n);
4136
4137                                 sector->setNode(gp+v3s16(-1,3,0), n);
4138                                 sector->setNode(gp+v3s16(1,3,0), n);
4139                                 sector->setNode(gp+v3s16(0,3,-1), n);
4140                                 sector->setNode(gp+v3s16(0,3,1), n);
4141                                 sector->setNode(gp+v3s16(1,3,1), n);
4142                                 sector->setNode(gp+v3s16(-1,3,1), n);
4143                                 sector->setNode(gp+v3s16(-1,3,-1), n);
4144                                 sector->setNode(gp+v3s16(1,3,-1), n);
4145                                 
4146                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,0), n);
4147                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,0), n);
4148                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,2,-1), n);
4149                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,2,1), n);
4150                                 /*if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,1), n);
4151                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,1), n);
4152                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,-1), n);
4153                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,-1), n);*/
4154                                 
4155                                 // Objects are identified by wanted position
4156                                 objects_to_remove.push_back(p);
4157                                 
4158                                 // Lighting has to be recalculated for this one.
4159                                 sector->getBlocksInArea(p_min, p_max, 
4160                                                 lighting_invalidated_blocks);
4161                         }
4162                 }
4163                 else if(d == SECTOR_OBJECT_BUSH_1)
4164                 {
4165                         if(ground_found == false)
4166                                 continue;
4167                         
4168                         if(sector->isValidArea(gp + v3s16(0,0,0),
4169                                         gp + v3s16(0,0,0), &changed_blocks_sector))
4170                         {
4171                                 MapNode n;
4172                                 n.d = CONTENT_LEAVES;
4173                                 sector->setNode(gp+v3s16(0,0,0), n);
4174                                 
4175                                 // Objects are identified by wanted position
4176                                 objects_to_remove.push_back(p);
4177                         }
4178                 }
4179                 else if(d == SECTOR_OBJECT_RAVINE)
4180                 {
4181                         s16 maxdepth = -20;
4182                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
4183                         v3s16 p_max = p + v3s16(6,6,6);
4184                         if(sector->isValidArea(p_min, p_max,
4185                                         &changed_blocks_sector))
4186                         {
4187                                 MapNode n;
4188                                 n.d = CONTENT_STONE;
4189                                 MapNode n2;
4190                                 n2.d = CONTENT_AIR;
4191                                 s16 depth = maxdepth + (myrand()%10);
4192                                 s16 z = 0;
4193                                 s16 minz = -6 - (-2);
4194                                 s16 maxz = 6 -1;
4195                                 for(s16 x=-6; x<=6; x++)
4196                                 {
4197                                         z += -1 + (myrand()%3);
4198                                         if(z < minz)
4199                                                 z = minz;
4200                                         if(z > maxz)
4201                                                 z = maxz;
4202                                         for(s16 y=depth+(myrand()%2); y<=6; y++)
4203                                         {
4204                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
4205                                                                 <<std::endl;*/
4206                                                 {
4207                                                         v3s16 p2 = p + v3s16(x,y,z-2);
4208                                                         //if(is_ground_content(sector->getNode(p2).d))
4209                                                         if(content_features(sector->getNode(p2).d).walkable)
4210                                                                 sector->setNode(p2, n);
4211                                                 }
4212                                                 {
4213                                                         v3s16 p2 = p + v3s16(x,y,z-1);
4214                                                         if(content_features(sector->getNode(p2).d).walkable)
4215                                                                 sector->setNode(p2, n2);
4216                                                 }
4217                                                 {
4218                                                         v3s16 p2 = p + v3s16(x,y,z+0);
4219                                                         if(content_features(sector->getNode(p2).d).walkable)
4220                                                                 sector->setNode(p2, n2);
4221                                                 }
4222                                                 {
4223                                                         v3s16 p2 = p + v3s16(x,y,z+1);
4224                                                         if(content_features(sector->getNode(p2).d).walkable)
4225                                                                 sector->setNode(p2, n);
4226                                                 }
4227
4228                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
4229                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
4230                                         }
4231                                 }
4232                                 
4233                                 objects_to_remove.push_back(p);
4234                                 
4235                                 // Lighting has to be recalculated for this one.
4236                                 sector->getBlocksInArea(p_min, p_max, 
4237                                                 lighting_invalidated_blocks);
4238                         }
4239                 }
4240                 else
4241                 {
4242                         dstream<<"ServerMap::generateBlock(): "
4243                                         "Invalid heightmap object"
4244                                         <<std::endl;
4245                 }
4246
4247                 }//try
4248                 catch(InvalidPositionException &e)
4249                 {
4250                         dstream<<"WARNING: "<<__FUNCTION_NAME
4251                                         <<": while inserting object "<<(int)d
4252                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
4253                                         <<" InvalidPositionException.what()="
4254                                         <<e.what()<<std::endl;
4255                         // This is not too fatal and seems to happen sometimes.
4256                         assert(0);
4257                 }
4258         }
4259
4260         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
4261                         i != objects_to_remove.end(); i++)
4262         {
4263                 objects->remove(*i);
4264         }
4265         
4266         /*
4267                 Translate sector's changed blocks to global changed blocks
4268         */
4269         
4270         for(core::map<s16, MapBlock*>::Iterator
4271                         i = changed_blocks_sector.getIterator();
4272                         i.atEnd() == false; i++)
4273         {
4274                 MapBlock *block = i.getNode()->getValue();
4275
4276                 changed_blocks.insert(block->getPos(), block);
4277         }
4278
4279         block->setLightingExpired(true);
4280         
4281 #if 0
4282         /*
4283                 Debug information
4284         */
4285         dstream
4286         <<"lighting_invalidated_blocks.size()"
4287         <<", has_dungeons"
4288         <<", completely_ug"
4289         <<", some_part_ug"
4290         <<"  "<<lighting_invalidated_blocks.size()
4291         <<", "<<has_dungeons
4292         <<", "<<completely_underground
4293         <<", "<<some_part_underground
4294         <<std::endl;
4295 #endif
4296
4297         return block;
4298 }
4299
4300 MapBlock * ServerMap::createBlock(v3s16 p)
4301 {
4302         DSTACK("%s: p=(%d,%d,%d)",
4303                         __FUNCTION_NAME, p.X, p.Y, p.Z);
4304         
4305         v2s16 p2d(p.X, p.Z);
4306         s16 block_y = p.Y;
4307         /*
4308                 This will create or load a sector if not found in memory.
4309                 If block exists on disk, it will be loaded.
4310
4311                 NOTE: On old save formats, this will be slow, as it generates
4312                       lighting on blocks for them.
4313         */
4314         ServerMapSector *sector;
4315         try{
4316                 sector = (ServerMapSector*)createSector(p2d);
4317                 assert(sector->getId() == MAPSECTOR_SERVER);
4318         }
4319         /*catch(InvalidPositionException &e)
4320         {
4321                 dstream<<"createBlock: createSector() failed"<<std::endl;
4322                 throw e;
4323         }*/
4324         catch(std::exception &e)
4325         {
4326                 dstream<<"createBlock: createSector() failed: "
4327                                 <<e.what()<<std::endl;
4328                 throw e;
4329         }
4330
4331         /*
4332                 Try to get a block from the sector
4333         */
4334
4335         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4336         if(block)
4337                 return block;
4338         // Create blank
4339         block = sector->createBlankBlock(block_y);
4340         return block;
4341 }
4342
4343 MapBlock * ServerMap::emergeBlock(
4344                 v3s16 p,
4345                 bool only_from_disk,
4346                 core::map<v3s16, MapBlock*> &changed_blocks,
4347                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
4348 )
4349 {
4350         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
4351                         __FUNCTION_NAME,
4352                         p.X, p.Y, p.Z, only_from_disk);
4353         
4354         v2s16 p2d(p.X, p.Z);
4355         s16 block_y = p.Y;
4356         /*
4357                 This will create or load a sector if not found in memory.
4358                 If block exists on disk, it will be loaded.
4359
4360                 NOTE: On old save formats, this will be slow, as it generates
4361                       lighting on blocks for them.
4362         */
4363         ServerMapSector *sector;
4364         try{
4365                 sector = (ServerMapSector*)emergeSector(p2d, changed_blocks);
4366                 assert(sector->getId() == MAPSECTOR_SERVER);
4367         }
4368         catch(std::exception &e)
4369         {
4370                 dstream<<"emergeBlock: emergeSector() failed: "
4371                                 <<e.what()<<std::endl;
4372                 throw e;
4373         }
4374
4375         /*
4376                 Try to get a block from the sector
4377         */
4378
4379         bool does_not_exist = false;
4380         bool lighting_expired = false;
4381         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4382
4383         if(block == NULL)
4384         {
4385                 does_not_exist = true;
4386         }
4387         else if(block->isDummy() == true)
4388         {
4389                 does_not_exist = true;
4390         }
4391         else if(block->getLightingExpired())
4392         {
4393                 lighting_expired = true;
4394         }
4395         else
4396         {
4397                 // Valid block
4398                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
4399                 return block;
4400         }
4401         
4402         /*
4403                 If block was not found on disk and not going to generate a
4404                 new one, make sure there is a dummy block in place.
4405         */
4406         if(only_from_disk && (does_not_exist || lighting_expired))
4407         {
4408                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
4409
4410                 if(block == NULL)
4411                 {
4412                         // Create dummy block
4413                         block = new MapBlock(this, p, true);
4414
4415                         // Add block to sector
4416                         sector->insertBlock(block);
4417                 }
4418                 // Done.
4419                 return block;
4420         }
4421
4422         //dstream<<"Not found on disk, generating."<<std::endl;
4423         // 0ms
4424         //TimeTaker("emergeBlock() generate");
4425
4426         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
4427
4428         /*
4429                 If the block doesn't exist, generate the block.
4430         */
4431         if(does_not_exist)
4432         {
4433                 block = generateBlock(p, block, sector, changed_blocks,
4434                                 lighting_invalidated_blocks); 
4435         }
4436
4437         if(lighting_expired)
4438         {
4439                 lighting_invalidated_blocks.insert(p, block);
4440         }
4441
4442         /*
4443                 Initially update sunlight
4444         */
4445         
4446         {
4447                 core::map<v3s16, bool> light_sources;
4448                 bool black_air_left = false;
4449                 bool bottom_invalid =
4450                                 block->propagateSunlight(light_sources, true,
4451                                 &black_air_left, true);
4452
4453                 // If sunlight didn't reach everywhere and part of block is
4454                 // above ground, lighting has to be properly updated
4455                 //if(black_air_left && some_part_underground)
4456                 if(black_air_left)
4457                 {
4458                         lighting_invalidated_blocks[block->getPos()] = block;
4459                 }
4460
4461                 if(bottom_invalid)
4462                 {
4463                         lighting_invalidated_blocks[block->getPos()] = block;
4464                 }
4465         }
4466         
4467         /*
4468                 Debug mode operation
4469         */
4470         bool haxmode = g_settings.getBool("haxmode");
4471         if(haxmode)
4472         {
4473                 // Don't calculate lighting at all
4474                 //lighting_invalidated_blocks.clear();
4475         }
4476
4477         return block;
4478 }
4479
4480 void ServerMap::createDir(std::string path)
4481 {
4482         if(fs::CreateDir(path) == false)
4483         {
4484                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
4485                                 <<"\""<<path<<"\""<<std::endl;
4486                 throw BaseException("ServerMap failed to create directory");
4487         }
4488 }
4489
4490 std::string ServerMap::getSectorSubDir(v2s16 pos)
4491 {
4492         char cc[9];
4493         snprintf(cc, 9, "%.4x%.4x",
4494                         (unsigned int)pos.X&0xffff,
4495                         (unsigned int)pos.Y&0xffff);
4496
4497         return std::string(cc);
4498 }
4499
4500 std::string ServerMap::getSectorDir(v2s16 pos)
4501 {
4502         return m_savedir + "/sectors/" + getSectorSubDir(pos);
4503 }
4504
4505 v2s16 ServerMap::getSectorPos(std::string dirname)
4506 {
4507         if(dirname.size() != 8)
4508                 throw InvalidFilenameException("Invalid sector directory name");
4509         unsigned int x, y;
4510         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
4511         if(r != 2)
4512                 throw InvalidFilenameException("Invalid sector directory name");
4513         v2s16 pos((s16)x, (s16)y);
4514         return pos;
4515 }
4516
4517 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
4518 {
4519         v2s16 p2d = getSectorPos(sectordir);
4520
4521         if(blockfile.size() != 4){
4522                 throw InvalidFilenameException("Invalid block filename");
4523         }
4524         unsigned int y;
4525         int r = sscanf(blockfile.c_str(), "%4x", &y);
4526         if(r != 1)
4527                 throw InvalidFilenameException("Invalid block filename");
4528         return v3s16(p2d.X, y, p2d.Y);
4529 }
4530
4531 // Debug helpers
4532 #define ENABLE_SECTOR_SAVING 1
4533 #define ENABLE_SECTOR_LOADING 1
4534 #define ENABLE_BLOCK_SAVING 1
4535 #define ENABLE_BLOCK_LOADING 1
4536
4537 void ServerMap::save(bool only_changed)
4538 {
4539         DSTACK(__FUNCTION_NAME);
4540         if(m_map_saving_enabled == false)
4541         {
4542                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
4543                 return;
4544         }
4545         
4546         if(only_changed == false)
4547                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
4548                                 <<std::endl;
4549         
4550         saveMasterHeightmap();
4551         
4552         u32 sector_meta_count = 0;
4553         u32 block_count = 0;
4554         
4555         { //sectorlock
4556         JMutexAutoLock lock(m_sector_mutex);
4557         
4558         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
4559         for(; i.atEnd() == false; i++)
4560         {
4561                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
4562                 assert(sector->getId() == MAPSECTOR_SERVER);
4563                 
4564                 if(ENABLE_SECTOR_SAVING)
4565                 {
4566                         if(sector->differs_from_disk || only_changed == false)
4567                         {
4568                                 saveSectorMeta(sector);
4569                                 sector_meta_count++;
4570                         }
4571                 }
4572                 if(ENABLE_BLOCK_SAVING)
4573                 {
4574                         core::list<MapBlock*> blocks;
4575                         sector->getBlocks(blocks);
4576                         core::list<MapBlock*>::Iterator j;
4577                         for(j=blocks.begin(); j!=blocks.end(); j++)
4578                         {
4579                                 MapBlock *block = *j;
4580                                 if(block->getChangedFlag() || only_changed == false)
4581                                 {
4582                                         saveBlock(block);
4583                                         block_count++;
4584                                 }
4585                         }
4586                 }
4587         }
4588
4589         }//sectorlock
4590         
4591         /*
4592                 Only print if something happened or saved whole map
4593         */
4594         if(only_changed == false || sector_meta_count != 0
4595                         || block_count != 0)
4596         {
4597                 dstream<<DTIME<<"ServerMap: Written: "
4598                                 <<sector_meta_count<<" sector metadata files, "
4599                                 <<block_count<<" block files"
4600                                 <<std::endl;
4601         }
4602 }
4603
4604 void ServerMap::loadAll()
4605 {
4606         DSTACK(__FUNCTION_NAME);
4607         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
4608
4609         loadMasterHeightmap();
4610
4611         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
4612
4613         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
4614         
4615         JMutexAutoLock lock(m_sector_mutex);
4616         
4617         s32 counter = 0;
4618         s32 printed_counter = -100000;
4619         s32 count = list.size();
4620
4621         std::vector<fs::DirListNode>::iterator i;
4622         for(i=list.begin(); i!=list.end(); i++)
4623         {
4624                 if(counter > printed_counter + 10)
4625                 {
4626                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
4627                         printed_counter = counter;
4628                 }
4629                 counter++;
4630
4631                 MapSector *sector = NULL;
4632
4633                 // We want directories
4634                 if(i->dir == false)
4635                         continue;
4636                 try{
4637                         sector = loadSectorMeta(i->name);
4638                 }
4639                 catch(InvalidFilenameException &e)
4640                 {
4641                         // This catches unknown crap in directory
4642                 }
4643                 
4644                 if(ENABLE_BLOCK_LOADING)
4645                 {
4646                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
4647                                         (m_savedir+"/sectors/"+i->name);
4648                         std::vector<fs::DirListNode>::iterator i2;
4649                         for(i2=list2.begin(); i2!=list2.end(); i2++)
4650                         {
4651                                 // We want files
4652                                 if(i2->dir)
4653                                         continue;
4654                                 try{
4655                                         loadBlock(i->name, i2->name, sector);
4656                                 }
4657                                 catch(InvalidFilenameException &e)
4658                                 {
4659                                         // This catches unknown crap in directory
4660                                 }
4661                         }
4662                 }
4663         }
4664         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
4665 }
4666
4667 void ServerMap::saveMasterHeightmap()
4668 {
4669         DSTACK(__FUNCTION_NAME);
4670         createDir(m_savedir);
4671         
4672         std::string fullpath = m_savedir + "/master_heightmap";
4673         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4674         if(o.good() == false)
4675                 throw FileNotGoodException("Cannot open master heightmap");
4676         
4677         // Format used for writing
4678         u8 version = SER_FMT_VER_HIGHEST;
4679
4680 #if 0
4681         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
4682         /*
4683                 [0] u8 serialization version
4684                 [1] X master heightmap
4685         */
4686         u32 fullsize = 1 + hmdata.getSize();
4687         SharedBuffer<u8> data(fullsize);
4688
4689         data[0] = version;
4690         memcpy(&data[1], *hmdata, hmdata.getSize());
4691
4692         o.write((const char*)*data, fullsize);
4693 #endif
4694         
4695         m_heightmap->serialize(o, version);
4696 }
4697
4698 void ServerMap::loadMasterHeightmap()
4699 {
4700         DSTACK(__FUNCTION_NAME);
4701         std::string fullpath = m_savedir + "/master_heightmap";
4702         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4703         if(is.good() == false)
4704                 throw FileNotGoodException("Cannot open master heightmap");
4705         
4706         if(m_heightmap != NULL)
4707                 delete m_heightmap;
4708                 
4709         m_heightmap = UnlimitedHeightmap::deSerialize(is, &m_padb);
4710 }
4711
4712 void ServerMap::saveSectorMeta(ServerMapSector *sector)
4713 {
4714         DSTACK(__FUNCTION_NAME);
4715         // Format used for writing
4716         u8 version = SER_FMT_VER_HIGHEST;
4717         // Get destination
4718         v2s16 pos = sector->getPos();
4719         createDir(m_savedir);
4720         createDir(m_savedir+"/sectors");
4721         std::string dir = getSectorDir(pos);
4722         createDir(dir);
4723         
4724         std::string fullpath = dir + "/heightmap";
4725         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4726         if(o.good() == false)
4727                 throw FileNotGoodException("Cannot open master heightmap");
4728
4729         sector->serialize(o, version);
4730         
4731         sector->differs_from_disk = false;
4732 }
4733
4734 MapSector* ServerMap::loadSectorMeta(std::string dirname)
4735 {
4736         DSTACK(__FUNCTION_NAME);
4737         // Get destination
4738         v2s16 p2d = getSectorPos(dirname);
4739         std::string dir = m_savedir + "/sectors/" + dirname;
4740         
4741         std::string fullpath = dir + "/heightmap";
4742         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4743         if(is.good() == false)
4744                 throw FileNotGoodException("Cannot open sector heightmap");
4745
4746         ServerMapSector *sector = ServerMapSector::deSerialize
4747                         (is, this, p2d, &m_hwrapper, m_sectors);
4748         
4749         sector->differs_from_disk = false;
4750
4751         return sector;
4752 }
4753
4754 bool ServerMap::loadSectorFull(v2s16 p2d)
4755 {
4756         DSTACK(__FUNCTION_NAME);
4757         std::string sectorsubdir = getSectorSubDir(p2d);
4758
4759         MapSector *sector = NULL;
4760
4761         JMutexAutoLock lock(m_sector_mutex);
4762
4763         try{
4764                 sector = loadSectorMeta(sectorsubdir);
4765         }
4766         catch(InvalidFilenameException &e)
4767         {
4768                 return false;
4769         }
4770         catch(FileNotGoodException &e)
4771         {
4772                 return false;
4773         }
4774         catch(std::exception &e)
4775         {
4776                 return false;
4777         }
4778
4779         if(ENABLE_BLOCK_LOADING)
4780         {
4781                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
4782                                 (m_savedir+"/sectors/"+sectorsubdir);
4783                 std::vector<fs::DirListNode>::iterator i2;
4784                 for(i2=list2.begin(); i2!=list2.end(); i2++)
4785                 {
4786                         // We want files
4787                         if(i2->dir)
4788                                 continue;
4789                         try{
4790                                 loadBlock(sectorsubdir, i2->name, sector);
4791                         }
4792                         catch(InvalidFilenameException &e)
4793                         {
4794                                 // This catches unknown crap in directory
4795                         }
4796                 }
4797         }
4798         return true;
4799 }
4800
4801 #if 0
4802 bool ServerMap::deFlushSector(v2s16 p2d)
4803 {
4804         DSTACK(__FUNCTION_NAME);
4805         // See if it already exists in memory
4806         try{
4807                 MapSector *sector = getSectorNoGenerate(p2d);
4808                 return true;
4809         }
4810         catch(InvalidPositionException &e)
4811         {
4812                 /*
4813                         Try to load the sector from disk.
4814                 */
4815                 if(loadSectorFull(p2d) == true)
4816                 {
4817                         return true;
4818                 }
4819         }
4820         return false;
4821 }
4822 #endif
4823
4824 void ServerMap::saveBlock(MapBlock *block)
4825 {
4826         DSTACK(__FUNCTION_NAME);
4827         /*
4828                 Dummy blocks are not written
4829         */
4830         if(block->isDummy())
4831         {
4832                 /*v3s16 p = block->getPos();
4833                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
4834                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
4835                 return;
4836         }
4837
4838         // Format used for writing
4839         u8 version = SER_FMT_VER_HIGHEST;
4840         // Get destination
4841         v3s16 p3d = block->getPos();
4842         v2s16 p2d(p3d.X, p3d.Z);
4843         createDir(m_savedir);
4844         createDir(m_savedir+"/sectors");
4845         std::string dir = getSectorDir(p2d);
4846         createDir(dir);
4847         
4848         // Block file is map/sectors/xxxxxxxx/xxxx
4849         char cc[5];
4850         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
4851         std::string fullpath = dir + "/" + cc;
4852         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4853         if(o.good() == false)
4854                 throw FileNotGoodException("Cannot open block data");
4855
4856         /*
4857                 [0] u8 serialization version
4858                 [1] data
4859         */
4860         o.write((char*)&version, 1);
4861         
4862         block->serialize(o, version);
4863
4864         /*
4865                 Versions up from 9 have block objects.
4866         */
4867         if(version >= 9)
4868         {
4869                 block->serializeObjects(o, version);
4870         }
4871         
4872         // We just wrote it to the disk
4873         block->resetChangedFlag();
4874 }
4875
4876 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
4877 {
4878         DSTACK(__FUNCTION_NAME);
4879
4880         try{
4881
4882         // Block file is map/sectors/xxxxxxxx/xxxx
4883         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
4884         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4885         if(is.good() == false)
4886                 throw FileNotGoodException("Cannot open block file");
4887
4888         v3s16 p3d = getBlockPos(sectordir, blockfile);
4889         v2s16 p2d(p3d.X, p3d.Z);
4890         
4891         assert(sector->getPos() == p2d);
4892         
4893         u8 version = SER_FMT_VER_INVALID;
4894         is.read((char*)&version, 1);
4895
4896         /*u32 block_size = MapBlock::serializedLength(version);
4897         SharedBuffer<u8> data(block_size);
4898         is.read((char*)*data, block_size);*/
4899
4900         // This will always return a sector because we're the server
4901         //MapSector *sector = emergeSector(p2d);
4902
4903         MapBlock *block = NULL;
4904         bool created_new = false;
4905         try{
4906                 block = sector->getBlockNoCreate(p3d.Y);
4907         }
4908         catch(InvalidPositionException &e)
4909         {
4910                 block = sector->createBlankBlockNoInsert(p3d.Y);
4911                 created_new = true;
4912         }
4913         
4914         // deserialize block data
4915         block->deSerialize(is, version);
4916         
4917         /*
4918                 Versions up from 9 have block objects.
4919         */
4920         if(version >= 9)
4921         {
4922                 block->updateObjects(is, version, NULL, 0);
4923         }
4924
4925         if(created_new)
4926                 sector->insertBlock(block);
4927         
4928         /*
4929                 Convert old formats to new and save
4930         */
4931
4932         // Save old format blocks in new format
4933         if(version < SER_FMT_VER_HIGHEST)
4934         {
4935                 saveBlock(block);
4936         }
4937         
4938         // We just loaded it from the disk, so it's up-to-date.
4939         block->resetChangedFlag();
4940
4941         }
4942         catch(SerializationError &e)
4943         {
4944                 dstream<<"WARNING: Invalid block data on disk "
4945                                 "(SerializationError). Ignoring."
4946                                 <<std::endl;
4947         }
4948 }
4949
4950 // Gets from master heightmap
4951 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
4952 {
4953         assert(m_heightmap != NULL);
4954         /*
4955                 Corner definition:
4956                 v2s16(0,0),
4957                 v2s16(1,0),
4958                 v2s16(1,1),
4959                 v2s16(0,1),
4960         */
4961         corners[0] = m_heightmap->getGroundHeight
4962                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
4963         corners[1] = m_heightmap->getGroundHeight
4964                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
4965         corners[2] = m_heightmap->getGroundHeight
4966                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
4967         corners[3] = m_heightmap->getGroundHeight
4968                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
4969 }
4970
4971 void ServerMap::PrintInfo(std::ostream &out)
4972 {
4973         out<<"ServerMap: ";
4974 }
4975
4976 #ifndef SERVER
4977
4978 /*
4979         ClientMap
4980 */
4981
4982 ClientMap::ClientMap(
4983                 Client *client,
4984                 MapDrawControl &control,
4985                 scene::ISceneNode* parent,
4986                 scene::ISceneManager* mgr,
4987                 s32 id
4988 ):
4989         Map(dout_client),
4990         scene::ISceneNode(parent, mgr, id),
4991         m_client(client),
4992         mesh(NULL),
4993         m_control(control)
4994 {
4995         mesh_mutex.Init();
4996
4997         /*m_box = core::aabbox3d<f32>(0,0,0,
4998                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
4999         /*m_box = core::aabbox3d<f32>(0,0,0,
5000                         map->getSizeNodes().X * BS,
5001                         map->getSizeNodes().Y * BS,
5002                         map->getSizeNodes().Z * BS);*/
5003         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
5004                         BS*1000000,BS*1000000,BS*1000000);
5005         
5006         //setPosition(v3f(BS,BS,BS));
5007 }
5008
5009 ClientMap::~ClientMap()
5010 {
5011         JMutexAutoLock lock(mesh_mutex);
5012         
5013         if(mesh != NULL)
5014         {
5015                 mesh->drop();
5016                 mesh = NULL;
5017         }
5018 }
5019
5020 MapSector * ClientMap::emergeSector(v2s16 p2d)
5021 {
5022         DSTACK(__FUNCTION_NAME);
5023         // Check that it doesn't exist already
5024         try{
5025                 return getSectorNoGenerate(p2d);
5026         }
5027         catch(InvalidPositionException &e)
5028         {
5029         }
5030         
5031         // Create a sector with no heightmaps
5032         ClientMapSector *sector = new ClientMapSector(this, p2d);
5033         
5034         {
5035                 JMutexAutoLock lock(m_sector_mutex);
5036                 m_sectors.insert(p2d, sector);
5037         }
5038         
5039         return sector;
5040 }
5041
5042 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
5043 {
5044         DSTACK(__FUNCTION_NAME);
5045         ClientMapSector *sector = NULL;
5046
5047         JMutexAutoLock lock(m_sector_mutex);
5048         
5049         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
5050
5051         if(n != NULL)
5052         {
5053                 sector = (ClientMapSector*)n->getValue();
5054                 assert(sector->getId() == MAPSECTOR_CLIENT);
5055         }
5056         else
5057         {
5058                 sector = new ClientMapSector(this, p2d);
5059                 {
5060                         JMutexAutoLock lock(m_sector_mutex);
5061                         m_sectors.insert(p2d, sector);
5062                 }
5063         }
5064
5065         sector->deSerialize(is);
5066 }
5067
5068 void ClientMap::OnRegisterSceneNode()
5069 {
5070         if(IsVisible)
5071         {
5072                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
5073                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
5074         }
5075
5076         ISceneNode::OnRegisterSceneNode();
5077 }
5078
5079 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
5080 {
5081         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
5082         DSTACK(__FUNCTION_NAME);
5083
5084         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
5085
5086         /*
5087                 Get time for measuring timeout.
5088                 
5089                 Measuring time is very useful for long delays when the
5090                 machine is swapping a lot.
5091         */
5092         int time1 = time(0);
5093
5094         u32 daynight_ratio = m_client->getDayNightRatio();
5095
5096         m_camera_mutex.Lock();
5097         v3f camera_position = m_camera_position;
5098         v3f camera_direction = m_camera_direction;
5099         m_camera_mutex.Unlock();
5100
5101         /*
5102                 Get all blocks and draw all visible ones
5103         */
5104
5105         v3s16 cam_pos_nodes(
5106                         camera_position.X / BS,
5107                         camera_position.Y / BS,
5108                         camera_position.Z / BS);
5109
5110         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
5111
5112         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
5113         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
5114
5115         // Take a fair amount as we will be dropping more out later
5116         v3s16 p_blocks_min(
5117                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
5118                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
5119                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
5120         v3s16 p_blocks_max(
5121                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
5122                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
5123                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
5124         
5125         u32 vertex_count = 0;
5126         
5127         // For limiting number of mesh updates per frame
5128         u32 mesh_update_count = 0;
5129         
5130         u32 blocks_would_have_drawn = 0;
5131         u32 blocks_drawn = 0;
5132
5133         //NOTE: The sectors map should be locked but we're not doing it
5134         // because it'd cause too much delays
5135
5136         int timecheck_counter = 0;
5137         core::map<v2s16, MapSector*>::Iterator si;
5138         si = m_sectors.getIterator();
5139         for(; si.atEnd() == false; si++)
5140         {
5141                 {
5142                         timecheck_counter++;
5143                         if(timecheck_counter > 50)
5144                         {
5145                                 int time2 = time(0);
5146                                 if(time2 > time1 + 4)
5147                                 {
5148                                         dstream<<"ClientMap::renderMap(): "
5149                                                 "Rendering takes ages, returning."
5150                                                 <<std::endl;
5151                                         return;
5152                                 }
5153                         }
5154                 }
5155
5156                 MapSector *sector = si.getNode()->getValue();
5157                 v2s16 sp = sector->getPos();
5158                 
5159                 if(m_control.range_all == false)
5160                 {
5161                         if(sp.X < p_blocks_min.X
5162                         || sp.X > p_blocks_max.X
5163                         || sp.Y < p_blocks_min.Z
5164                         || sp.Y > p_blocks_max.Z)
5165                                 continue;
5166                 }
5167
5168                 core::list< MapBlock * > sectorblocks;
5169                 sector->getBlocks(sectorblocks);
5170                 
5171                 /*
5172                         Draw blocks
5173                 */
5174
5175                 core::list< MapBlock * >::Iterator i;
5176                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5177                 {
5178                         MapBlock *block = *i;
5179
5180                         /*
5181                                 Compare block position to camera position, skip
5182                                 if not seen on display
5183                         */
5184                         
5185                         float range = 100000 * BS;
5186                         if(m_control.range_all == false)
5187                                 range = m_control.wanted_range * BS;
5188
5189                         if(isBlockInSight(block->getPos(), camera_position,
5190                                         camera_direction, range) == false)
5191                         {
5192                                 continue;
5193                         }
5194
5195 #if 0                   
5196                         v3s16 blockpos_nodes = block->getPosRelative();
5197                         
5198                         // Block center position
5199                         v3f blockpos(
5200                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
5201                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
5202                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
5203                         );
5204
5205                         // Block position relative to camera
5206                         v3f blockpos_relative = blockpos - camera_position;
5207
5208                         // Distance in camera direction (+=front, -=back)
5209                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
5210
5211                         // Total distance
5212                         f32 d = blockpos_relative.getLength();
5213                         
5214                         if(m_control.range_all == false)
5215                         {
5216                                 // If block is far away, don't draw it
5217                                 if(d > m_control.wanted_range * BS)
5218                                         continue;
5219                         }
5220                         
5221                         // Maximum radius of a block
5222                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
5223                         
5224                         // If block is (nearly) touching the camera, don't
5225                         // bother validating further (that is, render it anyway)
5226                         if(d > block_max_radius * 1.5)
5227                         {
5228                                 // Cosine of the angle between the camera direction
5229                                 // and the block direction (camera_direction is an unit vector)
5230                                 f32 cosangle = dforward / d;
5231                                 
5232                                 // Compensate for the size of the block
5233                                 // (as the block has to be shown even if it's a bit off FOV)
5234                                 // This is an estimate.
5235                                 cosangle += block_max_radius / dforward;
5236
5237                                 // If block is not in the field of view, skip it
5238                                 //if(cosangle < cos(FOV_ANGLE/2))
5239                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
5240                                         continue;
5241                         }
5242 #endif                  
5243
5244                         v3s16 blockpos_nodes = block->getPosRelative();
5245                         
5246                         // Block center position
5247                         v3f blockpos(
5248                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
5249                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
5250                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
5251                         );
5252
5253                         // Block position relative to camera
5254                         v3f blockpos_relative = blockpos - camera_position;
5255
5256                         // Total distance
5257                         f32 d = blockpos_relative.getLength();
5258                         
5259 #if 1
5260                         /*
5261                                 Update expired mesh
5262                         */
5263
5264                         bool mesh_expired = false;
5265                         
5266                         {
5267                                 JMutexAutoLock lock(block->mesh_mutex);
5268
5269                                 mesh_expired = block->getMeshExpired();
5270
5271                                 // Mesh has not been expired and there is no mesh:
5272                                 // block has no content
5273                                 if(block->mesh == NULL && mesh_expired == false)
5274                                         continue;
5275                         }
5276
5277                         f32 faraway = BS*50;
5278                         //f32 faraway = m_control.wanted_range * BS;
5279                         
5280                         /*
5281                                 This has to be done with the mesh_mutex unlocked
5282                         */
5283                         // Pretty random but this should work somewhat nicely
5284                         if(mesh_expired && (
5285                                         (mesh_update_count < 3
5286                                                 && (d < faraway || mesh_update_count < 2)
5287                                         )
5288                                         || 
5289                                         (m_control.range_all && mesh_update_count < 20)
5290                                 )
5291                         )
5292                         /*if(mesh_expired && mesh_update_count < 6
5293                                         && (d < faraway || mesh_update_count < 3))*/
5294                         {
5295                                 mesh_update_count++;
5296
5297                                 // Mesh has been expired: generate new mesh
5298                                 //block->updateMeshes(daynight_i);
5299                                 block->updateMesh(daynight_ratio);
5300
5301                                 mesh_expired = false;
5302                         }
5303                         
5304                         /*
5305                                 Don't draw an expired mesh that is far away
5306                         */
5307                         /*if(mesh_expired && d >= faraway)
5308                         //if(mesh_expired)
5309                         {
5310                                 // Instead, delete it
5311                                 JMutexAutoLock lock(block->mesh_mutex);
5312                                 if(block->mesh)
5313                                 {
5314                                         block->mesh->drop();
5315                                         block->mesh = NULL;
5316                                 }
5317                                 // And continue to next block
5318                                 continue;
5319                         }*/
5320 #endif
5321                         /*
5322                                 Draw the faces of the block
5323                         */
5324                         {
5325                                 JMutexAutoLock lock(block->mesh_mutex);
5326
5327                                 scene::SMesh *mesh = block->mesh;
5328
5329                                 if(mesh == NULL)
5330                                         continue;
5331                                 
5332                                 blocks_would_have_drawn++;
5333                                 if(blocks_drawn >= m_control.wanted_max_blocks
5334                                                 && m_control.range_all == false
5335                                                 && d > m_control.wanted_min_range * BS)
5336                                         continue;
5337                                 blocks_drawn++;
5338
5339                                 u32 c = mesh->getMeshBufferCount();
5340
5341                                 for(u32 i=0; i<c; i++)
5342                                 {
5343                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
5344                                         const video::SMaterial& material = buf->getMaterial();
5345                                         video::IMaterialRenderer* rnd =
5346                                                         driver->getMaterialRenderer(material.MaterialType);
5347                                         bool transparent = (rnd && rnd->isTransparent());
5348                                         // Render transparent on transparent pass and likewise.
5349                                         if(transparent == is_transparent_pass)
5350                                         {
5351                                                 driver->setMaterial(buf->getMaterial());
5352                                                 driver->drawMeshBuffer(buf);
5353                                                 vertex_count += buf->getVertexCount();
5354                                         }
5355                                 }
5356                         }
5357                 } // foreach sectorblocks
5358         }
5359         
5360         m_control.blocks_drawn = blocks_drawn;
5361         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
5362
5363         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
5364                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
5365 }
5366
5367 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
5368                 core::map<v3s16, MapBlock*> *affected_blocks)
5369 {
5370         bool changed = false;
5371         /*
5372                 Add it to all blocks touching it
5373         */
5374         v3s16 dirs[7] = {
5375                 v3s16(0,0,0), // this
5376                 v3s16(0,0,1), // back
5377                 v3s16(0,1,0), // top
5378                 v3s16(1,0,0), // right
5379                 v3s16(0,0,-1), // front
5380                 v3s16(0,-1,0), // bottom
5381                 v3s16(-1,0,0), // left
5382         };
5383         for(u16 i=0; i<7; i++)
5384         {
5385                 v3s16 p2 = p + dirs[i];
5386                 // Block position of neighbor (or requested) node
5387                 v3s16 blockpos = getNodeBlockPos(p2);
5388                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5389                 if(blockref == NULL)
5390                         continue;
5391                 // Relative position of requested node
5392                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5393                 if(blockref->setTempMod(relpos, mod))
5394                 {
5395                         changed = true;
5396                 }
5397         }
5398         if(changed && affected_blocks!=NULL)
5399         {
5400                 for(u16 i=0; i<7; i++)
5401                 {
5402                         v3s16 p2 = p + dirs[i];
5403                         // Block position of neighbor (or requested) node
5404                         v3s16 blockpos = getNodeBlockPos(p2);
5405                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5406                         if(blockref == NULL)
5407                                 continue;
5408                         affected_blocks->insert(blockpos, blockref);
5409                 }
5410         }
5411         return changed;
5412 }
5413
5414 bool ClientMap::clearTempMod(v3s16 p,
5415                 core::map<v3s16, MapBlock*> *affected_blocks)
5416 {
5417         bool changed = false;
5418         v3s16 dirs[7] = {
5419                 v3s16(0,0,0), // this
5420                 v3s16(0,0,1), // back
5421                 v3s16(0,1,0), // top
5422                 v3s16(1,0,0), // right
5423                 v3s16(0,0,-1), // front
5424                 v3s16(0,-1,0), // bottom
5425                 v3s16(-1,0,0), // left
5426         };
5427         for(u16 i=0; i<7; i++)
5428         {
5429                 v3s16 p2 = p + dirs[i];
5430                 // Block position of neighbor (or requested) node
5431                 v3s16 blockpos = getNodeBlockPos(p2);
5432                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5433                 if(blockref == NULL)
5434                         continue;
5435                 // Relative position of requested node
5436                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5437                 if(blockref->clearTempMod(relpos))
5438                 {
5439                         changed = true;
5440                 }
5441         }
5442         if(changed && affected_blocks!=NULL)
5443         {
5444                 for(u16 i=0; i<7; i++)
5445                 {
5446                         v3s16 p2 = p + dirs[i];
5447                         // Block position of neighbor (or requested) node
5448                         v3s16 blockpos = getNodeBlockPos(p2);
5449                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5450                         if(blockref == NULL)
5451                                 continue;
5452                         affected_blocks->insert(blockpos, blockref);
5453                 }
5454         }
5455         return changed;
5456 }
5457
5458 void ClientMap::PrintInfo(std::ostream &out)
5459 {
5460         out<<"ClientMap: ";
5461 }
5462
5463 #endif // !SERVER
5464
5465 /*
5466         MapVoxelManipulator
5467 */
5468
5469 MapVoxelManipulator::MapVoxelManipulator(Map *map)
5470 {
5471         m_map = map;
5472 }
5473
5474 MapVoxelManipulator::~MapVoxelManipulator()
5475 {
5476         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
5477                         <<std::endl;*/
5478 }
5479
5480 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5481 {
5482         TimeTaker timer1("emerge", &emerge_time);
5483
5484         // Units of these are MapBlocks
5485         v3s16 p_min = getNodeBlockPos(a.MinEdge);
5486         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
5487
5488         VoxelArea block_area_nodes
5489                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5490
5491         addArea(block_area_nodes);
5492
5493         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5494         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5495         for(s32 x=p_min.X; x<=p_max.X; x++)
5496         {
5497                 v3s16 p(x,y,z);
5498                 core::map<v3s16, bool>::Node *n;
5499                 n = m_loaded_blocks.find(p);
5500                 if(n != NULL)
5501                         continue;
5502                 
5503                 bool block_data_inexistent = false;
5504                 try
5505                 {
5506                         TimeTaker timer1("emerge load", &emerge_load_time);
5507
5508                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
5509                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5510                                         <<" wanted area: ";
5511                         a.print(dstream);
5512                         dstream<<std::endl;*/
5513                         
5514                         MapBlock *block = m_map->getBlockNoCreate(p);
5515                         if(block->isDummy())
5516                                 block_data_inexistent = true;
5517                         else
5518                                 block->copyTo(*this);
5519                 }
5520                 catch(InvalidPositionException &e)
5521                 {
5522                         block_data_inexistent = true;
5523                 }
5524
5525                 if(block_data_inexistent)
5526                 {
5527                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5528                         // Fill with VOXELFLAG_INEXISTENT
5529                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
5530                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
5531                         {
5532                                 s32 i = m_area.index(a.MinEdge.X,y,z);
5533                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
5534                         }
5535                 }
5536
5537                 m_loaded_blocks.insert(p, !block_data_inexistent);
5538         }
5539
5540         //dstream<<"emerge done"<<std::endl;
5541 }
5542
5543 /*
5544         SUGG: Add an option to only update eg. water and air nodes.
5545               This will make it interfere less with important stuff if
5546                   run on background.
5547 */
5548 void MapVoxelManipulator::blitBack
5549                 (core::map<v3s16, MapBlock*> & modified_blocks)
5550 {
5551         if(m_area.getExtent() == v3s16(0,0,0))
5552                 return;
5553         
5554         //TimeTaker timer1("blitBack");
5555
5556         /*dstream<<"blitBack(): m_loaded_blocks.size()="
5557                         <<m_loaded_blocks.size()<<std::endl;*/
5558         
5559         /*
5560                 Initialize block cache
5561         */
5562         v3s16 blockpos_last;
5563         MapBlock *block = NULL;
5564         bool block_checked_in_modified = false;
5565
5566         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
5567         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
5568         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
5569         {
5570                 v3s16 p(x,y,z);
5571
5572                 u8 f = m_flags[m_area.index(p)];
5573                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
5574                         continue;
5575
5576                 MapNode &n = m_data[m_area.index(p)];
5577                         
5578                 v3s16 blockpos = getNodeBlockPos(p);
5579                 
5580                 try
5581                 {
5582                         // Get block
5583                         if(block == NULL || blockpos != blockpos_last){
5584                                 block = m_map->getBlockNoCreate(blockpos);
5585                                 blockpos_last = blockpos;
5586                                 block_checked_in_modified = false;
5587                         }
5588                         
5589                         // Calculate relative position in block
5590                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
5591
5592                         // Don't continue if nothing has changed here
5593                         if(block->getNode(relpos) == n)
5594                                 continue;
5595
5596                         //m_map->setNode(m_area.MinEdge + p, n);
5597                         block->setNode(relpos, n);
5598                         
5599                         /*
5600                                 Make sure block is in modified_blocks
5601                         */
5602                         if(block_checked_in_modified == false)
5603                         {
5604                                 modified_blocks[blockpos] = block;
5605                                 block_checked_in_modified = true;
5606                         }
5607                 }
5608                 catch(InvalidPositionException &e)
5609                 {
5610                 }
5611         }
5612 }
5613
5614 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
5615                 MapVoxelManipulator(map)
5616 {
5617 }
5618
5619 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
5620 {
5621 }
5622
5623 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5624 {
5625         // Just create the area so that it can be pointed to
5626         VoxelManipulator::emerge(a, caller_id);
5627 }
5628
5629 void ManualMapVoxelManipulator::initialEmerge(
5630                 v3s16 blockpos_min, v3s16 blockpos_max)
5631 {
5632         TimeTaker timer1("initialEmerge", &emerge_time);
5633
5634         // Units of these are MapBlocks
5635         v3s16 p_min = blockpos_min;
5636         v3s16 p_max = blockpos_max;
5637
5638         VoxelArea block_area_nodes
5639                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5640         
5641         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
5642         if(size_MB >= 1)
5643         {
5644                 dstream<<"initialEmerge: area: ";
5645                 block_area_nodes.print(dstream);
5646                 dstream<<" ("<<size_MB<<"MB)";
5647                 dstream<<std::endl;
5648         }
5649
5650         addArea(block_area_nodes);
5651
5652         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5653         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5654         for(s32 x=p_min.X; x<=p_max.X; x++)
5655         {
5656                 v3s16 p(x,y,z);
5657                 core::map<v3s16, bool>::Node *n;
5658                 n = m_loaded_blocks.find(p);
5659                 if(n != NULL)
5660                         continue;
5661                 
5662                 bool block_data_inexistent = false;
5663                 try
5664                 {
5665                         TimeTaker timer1("emerge load", &emerge_load_time);
5666
5667                         MapBlock *block = m_map->getBlockNoCreate(p);
5668                         if(block->isDummy())
5669                                 block_data_inexistent = true;
5670                         else
5671                                 block->copyTo(*this);
5672                 }
5673                 catch(InvalidPositionException &e)
5674                 {
5675                         block_data_inexistent = true;
5676                 }
5677
5678                 if(block_data_inexistent)
5679                 {
5680                         /*
5681                                 Mark area inexistent
5682                         */
5683                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5684                         // Fill with VOXELFLAG_INEXISTENT
5685                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
5686                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
5687                         {
5688                                 s32 i = m_area.index(a.MinEdge.X,y,z);
5689                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
5690                         }
5691                 }
5692
5693                 m_loaded_blocks.insert(p, !block_data_inexistent);
5694         }
5695 }
5696
5697 void ManualMapVoxelManipulator::blitBackAll(
5698                 core::map<v3s16, MapBlock*> * modified_blocks)
5699 {
5700         if(m_area.getExtent() == v3s16(0,0,0))
5701                 return;
5702         
5703         /*
5704                 Copy data of all blocks
5705         */
5706         for(core::map<v3s16, bool>::Iterator
5707                         i = m_loaded_blocks.getIterator();
5708                         i.atEnd() == false; i++)
5709         {
5710                 bool existed = i.getNode()->getValue();
5711                 if(existed == false)
5712                         continue;
5713                 v3s16 p = i.getNode()->getKey();
5714                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
5715                 if(block == NULL)
5716                 {
5717                         dstream<<"WARNING: "<<__FUNCTION_NAME
5718                                         <<": got NULL block "
5719                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5720                                         <<std::endl;
5721                         continue;
5722                 }
5723
5724                 block->copyFrom(*this);
5725
5726                 if(modified_blocks)
5727                         modified_blocks->insert(p, block);
5728         }
5729 }
5730
5731 //END