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