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