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