working nicely
[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 "player.h"
22 #include "main.h"
23 #include "jmutexautolock.h"
24 #include "client.h"
25 #include "filesys.h"
26 #include "utility.h"
27 #include "voxel.h"
28
29 #ifdef _WIN32
30         #include <windows.h>
31         #define sleep_ms(x) Sleep(x)
32 #else
33         #include <unistd.h>
34         #define sleep_ms(x) usleep(x*1000)
35 #endif
36
37 MapBlockPointerCache::MapBlockPointerCache(Map *map)
38 {
39         m_map = map;
40         m_map->m_blockcachelock.cacheCreated();
41
42         m_from_cache_count = 0;
43         m_from_map_count = 0;
44 }
45
46 MapBlockPointerCache::~MapBlockPointerCache()
47 {
48         m_map->m_blockcachelock.cacheRemoved();
49
50         /*dstream<<"MapBlockPointerCache:"
51                         <<" from_cache_count="<<m_from_cache_count
52                         <<" from_map_count="<<m_from_map_count
53                         <<std::endl;*/
54 }
55
56 MapBlock * MapBlockPointerCache::getBlockNoCreate(v3s16 p)
57 {
58         core::map<v3s16, MapBlock*>::Node *n = NULL;
59         n = m_blocks.find(p);
60         if(n != NULL)
61         {
62                 m_from_cache_count++;
63                 return n->getValue();
64         }
65         
66         m_from_map_count++;
67         
68         // Throws InvalidPositionException if not found
69         MapBlock *b = m_map->getBlockNoCreate(p);
70         m_blocks[p] = b;
71         return b;
72 }
73
74 /*
75         Map
76 */
77
78 Map::Map(std::ostream &dout):
79         m_dout(dout),
80         m_camera_position(0,0,0),
81         m_camera_direction(0,0,1),
82         m_sector_cache(NULL),
83         m_hwrapper(this),
84         drawoffset(0,0,0)
85 {
86         m_sector_mutex.Init();
87         m_camera_mutex.Init();
88         assert(m_sector_mutex.IsInitialized());
89         assert(m_camera_mutex.IsInitialized());
90         
91         // Get this so that the player can stay on it at first
92         //getSector(v2s16(0,0));
93 }
94
95 Map::~Map()
96 {
97         /*
98                 Stop updater thread
99         */
100         /*updater.setRun(false);
101         while(updater.IsRunning())
102                 sleep_s(1);*/
103
104         /*
105                 Free all MapSectors.
106         */
107         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
108         for(; i.atEnd() == false; i++)
109         {
110                 MapSector *sector = i.getNode()->getValue();
111                 delete sector;
112         }
113 }
114
115 /*bool Map::sectorExists(v2s16 p)
116 {
117         JMutexAutoLock lock(m_sector_mutex);
118         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
119         return (n != NULL);
120 }*/
121
122 MapSector * Map::getSectorNoGenerate(v2s16 p)
123 {
124         JMutexAutoLock lock(m_sector_mutex);
125
126         if(m_sector_cache != NULL && p == m_sector_cache_p){
127                 MapSector * sector = m_sector_cache;
128                 // Reset inactivity timer
129                 sector->usage_timer = 0.0;
130                 return sector;
131         }
132         
133         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
134         // If sector doesn't exist, throw an exception
135         if(n == NULL)
136         {
137                 throw InvalidPositionException();
138         }
139         
140         MapSector *sector = n->getValue();
141         
142         // Cache the last result
143         m_sector_cache_p = p;
144         m_sector_cache = sector;
145
146         //MapSector * ref(sector);
147         
148         // Reset inactivity timer
149         sector->usage_timer = 0.0;
150         return sector;
151 }
152
153 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
154 {       
155         v2s16 p2d(p3d.X, p3d.Z);
156         MapSector * sector = getSectorNoGenerate(p2d);
157
158         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
159
160         return block;
161 }
162
163 /*MapBlock * Map::getBlock(v3s16 p3d, bool generate)
164 {
165         dstream<<"Map::getBlock() with generate=true called"
166                         <<std::endl;
167         v2s16 p2d(p3d.X, p3d.Z);
168         //MapSector * sector = getSector(p2d, generate);
169         MapSector * sector = getSectorNoGenerate(p2d);
170
171         if(sector == NULL)
172                 throw InvalidPositionException();
173
174         return sector->getBlockNoCreate(p3d.Y);
175 }*/
176
177 f32 Map::getGroundHeight(v2s16 p, bool generate)
178 {
179         try{
180                 v2s16 sectorpos = getNodeSectorPos(p);
181                 MapSector * sref = getSectorNoGenerate(sectorpos);
182                 v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
183                 f32 y = sref->getGroundHeight(relpos);
184                 return y;
185         }
186         catch(InvalidPositionException &e)
187         {
188                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
189         }
190 }
191
192 void Map::setGroundHeight(v2s16 p, f32 y, bool generate)
193 {
194         /*m_dout<<DTIME<<"Map::setGroundHeight(("
195                         <<p.X<<","<<p.Y
196                         <<"), "<<y<<")"<<std::endl;*/
197         v2s16 sectorpos = getNodeSectorPos(p);
198         MapSector * sref = getSectorNoGenerate(sectorpos);
199         v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
200         //sref->mutex.Lock();
201         sref->setGroundHeight(relpos, y);
202         //sref->mutex.Unlock();
203 }
204
205 bool Map::isNodeUnderground(v3s16 p)
206 {
207         v3s16 blockpos = getNodeBlockPos(p);
208         try{
209                 MapBlock * block = getBlockNoCreate(blockpos);
210                 return block->getIsUnderground();
211         }
212         catch(InvalidPositionException &e)
213         {
214                 return false;
215         }
216 }
217
218 #if 0
219 void Map::interpolate(v3s16 block,
220                 core::map<v3s16, MapBlock*> & modified_blocks)
221 {
222         const v3s16 dirs[6] = {
223                 v3s16(0,0,1), // back
224                 v3s16(0,1,0), // top
225                 v3s16(1,0,0), // right
226                 v3s16(0,0,-1), // front
227                 v3s16(0,-1,0), // bottom
228                 v3s16(-1,0,0), // left
229         };
230
231         if(from_nodes.size() == 0)
232                 return;
233         
234         u32 blockchangecount = 0;
235
236         core::map<v3s16, bool> lighted_nodes;
237         core::map<v3s16, bool>::Iterator j;
238         j = from_nodes.getIterator();
239
240         /*
241                 Initialize block cache
242         */
243         v3s16 blockpos_last;
244         MapBlock *block = NULL;
245         // Cache this a bit, too
246         bool block_checked_in_modified = false;
247         
248         for(; j.atEnd() == false; j++)
249         //for(; j != from_nodes.end(); j++)
250         {
251                 v3s16 pos = j.getNode()->getKey();
252                 //v3s16 pos = *j;
253                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
254                 v3s16 blockpos = getNodeBlockPos(pos);
255                 
256                 // Only fetch a new block if the block position has changed
257                 try{
258                         if(block == NULL || blockpos != blockpos_last){
259                                 block = getBlockNoCreate(blockpos);
260                                 blockpos_last = blockpos;
261
262                                 block_checked_in_modified = false;
263                                 blockchangecount++;
264                         }
265                 }
266                 catch(InvalidPositionException &e)
267                 {
268                         continue;
269                 }
270
271                 if(block->isDummy())
272                         continue;
273
274                 // Calculate relative position in block
275                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
276
277                 // Get node straight from the block
278                 MapNode n = block->getNode(relpos);
279
280                 u8 oldlight = n.getLight();
281                 u8 newlight = diminish_light(oldlight);
282
283                 // Loop through 6 neighbors
284                 for(u16 i=0; i<6; i++){
285                         // Get the position of the neighbor node
286                         v3s16 n2pos = pos + dirs[i];
287                         
288                         // Get the block where the node is located
289                         v3s16 blockpos = getNodeBlockPos(n2pos);
290
291                         try
292                         {
293                                 // Only fetch a new block if the block position has changed
294                                 try{
295                                         if(block == NULL || blockpos != blockpos_last){
296                                                 block = getBlockNoCreate(blockpos);
297                                                 blockpos_last = blockpos;
298
299                                                 block_checked_in_modified = false;
300                                                 blockchangecount++;
301                                         }
302                                 }
303                                 catch(InvalidPositionException &e)
304                                 {
305                                         continue;
306                                 }
307                                 
308                                 // Calculate relative position in block
309                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
310                                 // Get node straight from the block
311                                 MapNode n2 = block->getNode(relpos);
312                                 
313                                 bool changed = false;
314                                 /*
315                                         If the neighbor is brighter than the current node,
316                                         add to list (it will light up this node on its turn)
317                                 */
318                                 if(n2.getLight() > undiminish_light(oldlight))
319                                 {
320                                         lighted_nodes.insert(n2pos, true);
321                                         //lighted_nodes.push_back(n2pos);
322                                         changed = true;
323                                 }
324                                 /*
325                                         If the neighbor is dimmer than how much light this node
326                                         would spread on it, add to list
327                                 */
328                                 if(n2.getLight() < newlight)
329                                 {
330                                         if(n2.light_propagates())
331                                         {
332                                                 n2.setLight(newlight);
333                                                 block->setNode(relpos, n2);
334                                                 lighted_nodes.insert(n2pos, true);
335                                                 //lighted_nodes.push_back(n2pos);
336                                                 changed = true;
337                                         }
338                                 }
339
340                                 // Add to modified_blocks
341                                 if(changed == true && block_checked_in_modified == false)
342                                 {
343                                         // If the block is not found in modified_blocks, add.
344                                         if(modified_blocks.find(blockpos) == NULL)
345                                         {
346                                                 modified_blocks.insert(blockpos, block);
347                                         }
348                                         block_checked_in_modified = true;
349                                 }
350                         }
351                         catch(InvalidPositionException &e)
352                         {
353                                 continue;
354                         }
355                 }
356         }
357
358         /*dstream<<"spreadLight(): Changed block "
359                         <<blockchangecount<<" times"
360                         <<" for "<<from_nodes.size()<<" nodes"
361                         <<std::endl;*/
362         
363         if(lighted_nodes.size() > 0)
364                 spreadLight(lighted_nodes, modified_blocks);
365 }
366 #endif
367
368 /*
369         Goes recursively through the neighbours of the node.
370
371         Alters only transparent nodes.
372
373         If the lighting of the neighbour is lower than the lighting of
374         the node was (before changing it to 0 at the step before), the
375         lighting of the neighbour is set to 0 and then the same stuff
376         repeats for the neighbour.
377
378         The ending nodes of the routine are stored in light_sources.
379         This is useful when a light is removed. In such case, this
380         routine can be called for the light node and then again for
381         light_sources to re-light the area without the removed light.
382
383         values of from_nodes are lighting values.
384 */
385 void Map::unspreadLight(core::map<v3s16, u8> & from_nodes,
386                 core::map<v3s16, bool> & light_sources,
387                 core::map<v3s16, MapBlock*>  & modified_blocks)
388 {
389         v3s16 dirs[6] = {
390                 v3s16(0,0,1), // back
391                 v3s16(0,1,0), // top
392                 v3s16(1,0,0), // right
393                 v3s16(0,0,-1), // front
394                 v3s16(0,-1,0), // bottom
395                 v3s16(-1,0,0), // left
396         };
397         
398         if(from_nodes.size() == 0)
399                 return;
400         
401         u32 blockchangecount = 0;
402
403         core::map<v3s16, u8> unlighted_nodes;
404         core::map<v3s16, u8>::Iterator j;
405         j = from_nodes.getIterator();
406
407         /*
408                 Initialize block cache
409         */
410         v3s16 blockpos_last;
411         MapBlock *block = NULL;
412         // Cache this a bit, too
413         bool block_checked_in_modified = false;
414         
415         for(; j.atEnd() == false; j++)
416         {
417                 v3s16 pos = j.getNode()->getKey();
418                 v3s16 blockpos = getNodeBlockPos(pos);
419                 
420                 // Only fetch a new block if the block position has changed
421                 try{
422                         if(block == NULL || blockpos != blockpos_last){
423                                 block = getBlockNoCreate(blockpos);
424                                 blockpos_last = blockpos;
425
426                                 block_checked_in_modified = false;
427                                 blockchangecount++;
428                         }
429                 }
430                 catch(InvalidPositionException &e)
431                 {
432                         continue;
433                 }
434
435                 if(block->isDummy())
436                         continue;
437
438                 // Calculate relative position in block
439                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
440
441                 // Get node straight from the block
442                 MapNode n = block->getNode(relpos);
443                 
444                 u8 oldlight = j.getNode()->getValue();
445                 
446                 // Loop through 6 neighbors
447                 for(u16 i=0; i<6; i++)
448                 {
449                         // Get the position of the neighbor node
450                         v3s16 n2pos = pos + dirs[i];
451                         
452                         // Get the block where the node is located
453                         v3s16 blockpos = getNodeBlockPos(n2pos);
454
455                         try
456                         {
457                                 // Only fetch a new block if the block position has changed
458                                 try{
459                                         if(block == NULL || blockpos != blockpos_last){
460                                                 block = getBlockNoCreate(blockpos);
461                                                 blockpos_last = blockpos;
462
463                                                 block_checked_in_modified = false;
464                                                 blockchangecount++;
465                                         }
466                                 }
467                                 catch(InvalidPositionException &e)
468                                 {
469                                         continue;
470                                 }
471                                 
472                                 // Calculate relative position in block
473                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
474                                 // Get node straight from the block
475                                 MapNode n2 = block->getNode(relpos);
476                                 
477                                 bool changed = false;
478
479                                 //TODO: Optimize output by optimizing light_sources?
480
481                                 /*
482                                         If the neighbor is dimmer than what was specified
483                                         as oldlight (the light of the previous node)
484                                 */
485                                 if(n2.getLight() < oldlight)
486                                 {
487                                         /*
488                                                 And the neighbor is transparent and it has some light
489                                         */
490                                         if(n2.light_propagates() && n2.getLight() != 0)
491                                         {
492                                                 /*
493                                                         Set light to 0 and add to queue
494                                                 */
495
496                                                 u8 current_light = n2.getLight();
497                                                 n2.setLight(0);
498                                                 block->setNode(relpos, n2);
499
500                                                 unlighted_nodes.insert(n2pos, current_light);
501                                                 changed = true;
502
503                                                 /*
504                                                         Remove from light_sources if it is there
505                                                         NOTE: This doesn't happen nearly at all
506                                                 */
507                                                 /*if(light_sources.find(n2pos))
508                                                 {
509                                                         std::cout<<"Removed from light_sources"<<std::endl;
510                                                         light_sources.remove(n2pos);
511                                                 }*/
512                                         }
513                                         
514                                         /*// DEBUG
515                                         if(light_sources.find(n2pos) != NULL)
516                                                 light_sources.remove(n2pos);*/
517                                 }
518                                 else{
519                                         light_sources.insert(n2pos, true);
520                                 }
521
522                                 // Add to modified_blocks
523                                 if(changed == true && block_checked_in_modified == false)
524                                 {
525                                         // If the block is not found in modified_blocks, add.
526                                         if(modified_blocks.find(blockpos) == NULL)
527                                         {
528                                                 modified_blocks.insert(blockpos, block);
529                                         }
530                                         block_checked_in_modified = true;
531                                 }
532                         }
533                         catch(InvalidPositionException &e)
534                         {
535                                 continue;
536                         }
537                 }
538         }
539
540         /*dstream<<"unspreadLight(): Changed block "
541                         <<blockchangecount<<" times"
542                         <<" for "<<from_nodes.size()<<" nodes"
543                         <<std::endl;*/
544         
545         if(unlighted_nodes.size() > 0)
546                 unspreadLight(unlighted_nodes, light_sources, modified_blocks);
547 }
548
549 /*
550         A single-node wrapper of the above
551 */
552 void Map::unLightNeighbors(v3s16 pos, u8 lightwas,
553                 core::map<v3s16, bool> & light_sources,
554                 core::map<v3s16, MapBlock*>  & modified_blocks)
555 {
556         core::map<v3s16, u8> from_nodes;
557         from_nodes.insert(pos, lightwas);
558
559         unspreadLight(from_nodes, light_sources, modified_blocks);
560 }
561
562 /*
563         Lights neighbors of from_nodes, collects all them and then
564         goes on recursively.
565 */
566 void Map::spreadLight(core::map<v3s16, bool> & from_nodes,
567                 core::map<v3s16, MapBlock*> & modified_blocks)
568 {
569         const v3s16 dirs[6] = {
570                 v3s16(0,0,1), // back
571                 v3s16(0,1,0), // top
572                 v3s16(1,0,0), // right
573                 v3s16(0,0,-1), // front
574                 v3s16(0,-1,0), // bottom
575                 v3s16(-1,0,0), // left
576         };
577
578         if(from_nodes.size() == 0)
579                 return;
580         
581         u32 blockchangecount = 0;
582
583         core::map<v3s16, bool> lighted_nodes;
584         core::map<v3s16, bool>::Iterator j;
585         j = from_nodes.getIterator();
586
587         /*
588                 Initialize block cache
589         */
590         v3s16 blockpos_last;
591         MapBlock *block = NULL;
592         // Cache this a bit, too
593         bool block_checked_in_modified = false;
594         
595         for(; j.atEnd() == false; j++)
596         //for(; j != from_nodes.end(); j++)
597         {
598                 v3s16 pos = j.getNode()->getKey();
599                 //v3s16 pos = *j;
600                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
601                 v3s16 blockpos = getNodeBlockPos(pos);
602                 
603                 // Only fetch a new block if the block position has changed
604                 try{
605                         if(block == NULL || blockpos != blockpos_last){
606                                 block = getBlockNoCreate(blockpos);
607                                 blockpos_last = blockpos;
608
609                                 block_checked_in_modified = false;
610                                 blockchangecount++;
611                         }
612                 }
613                 catch(InvalidPositionException &e)
614                 {
615                         continue;
616                 }
617
618                 if(block->isDummy())
619                         continue;
620
621                 // Calculate relative position in block
622                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
623
624                 // Get node straight from the block
625                 MapNode n = block->getNode(relpos);
626
627                 u8 oldlight = n.getLight();
628                 u8 newlight = diminish_light(oldlight);
629
630                 // Loop through 6 neighbors
631                 for(u16 i=0; i<6; i++){
632                         // Get the position of the neighbor node
633                         v3s16 n2pos = pos + dirs[i];
634                         
635                         // Get the block where the node is located
636                         v3s16 blockpos = getNodeBlockPos(n2pos);
637
638                         try
639                         {
640                                 // Only fetch a new block if the block position has changed
641                                 try{
642                                         if(block == NULL || blockpos != blockpos_last){
643                                                 block = getBlockNoCreate(blockpos);
644                                                 blockpos_last = blockpos;
645
646                                                 block_checked_in_modified = false;
647                                                 blockchangecount++;
648                                         }
649                                 }
650                                 catch(InvalidPositionException &e)
651                                 {
652                                         continue;
653                                 }
654                                 
655                                 // Calculate relative position in block
656                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
657                                 // Get node straight from the block
658                                 MapNode n2 = block->getNode(relpos);
659                                 
660                                 bool changed = false;
661                                 /*
662                                         If the neighbor is brighter than the current node,
663                                         add to list (it will light up this node on its turn)
664                                 */
665                                 if(n2.getLight() > undiminish_light(oldlight))
666                                 {
667                                         lighted_nodes.insert(n2pos, true);
668                                         //lighted_nodes.push_back(n2pos);
669                                         changed = true;
670                                 }
671                                 /*
672                                         If the neighbor is dimmer than how much light this node
673                                         would spread on it, add to list
674                                 */
675                                 if(n2.getLight() < newlight)
676                                 {
677                                         if(n2.light_propagates())
678                                         {
679                                                 n2.setLight(newlight);
680                                                 block->setNode(relpos, n2);
681                                                 lighted_nodes.insert(n2pos, true);
682                                                 //lighted_nodes.push_back(n2pos);
683                                                 changed = true;
684                                         }
685                                 }
686
687                                 // Add to modified_blocks
688                                 if(changed == true && block_checked_in_modified == false)
689                                 {
690                                         // If the block is not found in modified_blocks, add.
691                                         if(modified_blocks.find(blockpos) == NULL)
692                                         {
693                                                 modified_blocks.insert(blockpos, block);
694                                         }
695                                         block_checked_in_modified = true;
696                                 }
697                         }
698                         catch(InvalidPositionException &e)
699                         {
700                                 continue;
701                         }
702                 }
703         }
704
705         /*dstream<<"spreadLight(): Changed block "
706                         <<blockchangecount<<" times"
707                         <<" for "<<from_nodes.size()<<" nodes"
708                         <<std::endl;*/
709         
710         if(lighted_nodes.size() > 0)
711                 spreadLight(lighted_nodes, modified_blocks);
712 }
713
714 /*
715         A single-node source variation of the above.
716 */
717 void Map::lightNeighbors(v3s16 pos,
718                 core::map<v3s16, MapBlock*> & modified_blocks)
719 {
720         core::map<v3s16, bool> from_nodes;
721         from_nodes.insert(pos, true);
722         spreadLight(from_nodes, modified_blocks);
723 }
724
725 v3s16 Map::getBrightestNeighbour(v3s16 p)
726 {
727         v3s16 dirs[6] = {
728                 v3s16(0,0,1), // back
729                 v3s16(0,1,0), // top
730                 v3s16(1,0,0), // right
731                 v3s16(0,0,-1), // front
732                 v3s16(0,-1,0), // bottom
733                 v3s16(-1,0,0), // left
734         };
735         
736         u8 brightest_light = 0;
737         v3s16 brightest_pos(0,0,0);
738         bool found_something = false;
739
740         // Loop through 6 neighbors
741         for(u16 i=0; i<6; i++){
742                 // Get the position of the neighbor node
743                 v3s16 n2pos = p + dirs[i];
744                 MapNode n2;
745                 try{
746                         n2 = getNode(n2pos);
747                 }
748                 catch(InvalidPositionException &e)
749                 {
750                         continue;
751                 }
752                 if(n2.getLight() > brightest_light || found_something == false){
753                         brightest_light = n2.getLight();
754                         brightest_pos = n2pos;
755                         found_something = true;
756                 }
757         }
758
759         if(found_something == false)
760                 throw InvalidPositionException();
761                 
762         return brightest_pos;
763 }
764
765 /*
766         Propagates sunlight down from a node.
767         Starting point gets sunlight.
768
769         Returns the lowest y value of where the sunlight went.
770 */
771 s16 Map::propagateSunlight(v3s16 start,
772                 core::map<v3s16, MapBlock*> & modified_blocks)
773 {
774         s16 y = start.Y;
775         for(; ; y--)
776         {
777                 v3s16 pos(start.X, y, start.Z);
778                 
779                 v3s16 blockpos = getNodeBlockPos(pos);
780                 MapBlock *block;
781                 try{
782                         block = getBlockNoCreate(blockpos);
783                 }
784                 catch(InvalidPositionException &e)
785                 {
786                         break;
787                 }
788
789                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
790                 MapNode n = block->getNode(relpos);
791
792                 if(n.sunlight_propagates())
793                 {
794                         n.setLight(LIGHT_SUN);
795                         block->setNode(relpos, n);
796
797                         modified_blocks.insert(blockpos, block);
798                 }
799                 else{
800                         break;
801                 }
802         }
803         return y + 1;
804 }
805
806 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
807                 core::map<v3s16, MapBlock*> & modified_blocks)
808 {
809         /*m_dout<<DTIME<<"Map::updateLighting(): "
810                         <<a_blocks.getSize()<<" blocks... ";*/
811         
812         // For debugging
813         bool debug=false;
814         u32 count_was = modified_blocks.size();
815
816         /*core::list<MapBlock *>::Iterator i = a_blocks.begin();
817         for(; i != a_blocks.end(); i++)
818         {
819                 MapBlock *block = *i;*/
820
821         core::map<v3s16, bool> light_sources;
822         
823         core::map<v3s16, u8> unlight_from;
824                 
825         core::map<v3s16, MapBlock*>::Iterator i;
826         i = a_blocks.getIterator();
827         for(; i.atEnd() == false; i++)
828         {
829                 MapBlock *block = i.getNode()->getValue();
830                 
831                 for(;;)
832                 {
833                         // Don't bother with dummy blocks.
834                         if(block->isDummy())
835                                 break;
836                 
837                         v3s16 pos = block->getPos();
838                         modified_blocks.insert(pos, block);
839
840                         /*
841                                 Clear all light from block
842                         */
843                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
844                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
845                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
846                         {
847                                 
848                                 try{
849                                         v3s16 p(x,y,z);
850                                         MapNode n = block->getNode(v3s16(x,y,z));
851                                         u8 oldlight = n.getLight();
852                                         n.setLight(0);
853                                         block->setNode(v3s16(x,y,z), n);
854                                         
855                                         // Collect borders for unlighting
856                                         if(x==0 || x == MAP_BLOCKSIZE-1
857                                         || y==0 || y == MAP_BLOCKSIZE-1
858                                         || z==0 || z == MAP_BLOCKSIZE-1)
859                                         {
860                                                 v3s16 p_map = p + v3s16(
861                                                                 MAP_BLOCKSIZE*pos.X,
862                                                                 MAP_BLOCKSIZE*pos.Y,
863                                                                 MAP_BLOCKSIZE*pos.Z);
864                                                 unlight_from.insert(p_map, oldlight);
865                                         }
866                                 }
867                                 catch(InvalidPositionException &e)
868                                 {
869                                         /*
870                                                 This would happen when dealing with a
871                                                 dummy block.
872                                         */
873                                         //assert(0);
874                                         dstream<<"updateLighting(): InvalidPositionException"
875                                                         <<std::endl;
876                                 }
877                         }
878                         
879                         bool bottom_valid = block->propagateSunlight(light_sources);
880
881                         // If bottom is valid, we're done.
882                         if(bottom_valid)
883                                 break;
884                                 
885                         /*dstream<<"Bottom for sunlight-propagated block ("
886                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
887                                         <<std::endl;*/
888
889                         // Else get the block below and loop to it
890
891                         pos.Y--;
892                         try{
893                                 block = getBlockNoCreate(pos);
894                         }
895                         catch(InvalidPositionException &e)
896                         {
897                                 assert(0);
898                         }
899                         
900                 }
901         }
902         
903         {
904                 //TimeTaker timer("unspreadLight", g_device);
905                 unspreadLight(unlight_from, light_sources, modified_blocks);
906         }
907         
908         if(debug)
909         {
910                 u32 diff = modified_blocks.size() - count_was;
911                 count_was = modified_blocks.size();
912                 dstream<<"unspreadLight modified "<<diff<<std::endl;
913         }
914
915         // TODO: Spread light from propagated sunlight?
916         // Yes, add it to light_sources... somehow.
917         // It has to be added at somewhere above, in the loop.
918         // TODO
919         // NOTE: This actually works quite fine without it
920         //       - Find out why it works
921
922         {
923                 //TimeTaker timer("spreadLight", g_device);
924                 spreadLight(light_sources, modified_blocks);
925         }
926         
927         if(debug)
928         {
929                 u32 diff = modified_blocks.size() - count_was;
930                 count_was = modified_blocks.size();
931                 dstream<<"spreadLight modified "<<diff<<std::endl;
932         }
933
934         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
935 }
936
937 /*
938         This is called after changing a node from transparent to opaque.
939         The lighting value of the node should be left as-is after changing
940         other values. This sets the lighting value to 0.
941 */
942 /*void Map::nodeAddedUpdate(v3s16 p, u8 lightwas,
943                 core::map<v3s16, MapBlock*> &modified_blocks)*/
944 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
945                 core::map<v3s16, MapBlock*> &modified_blocks)
946 {
947         /*PrintInfo(m_dout);
948         m_dout<<DTIME<<"Map::nodeAddedUpdate(): p=("
949                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
950
951         u8 lightwas = getNode(p).getLight();
952
953         //core::list<v3s16> light_sources;
954         core::map<v3s16, bool> light_sources;
955         //MapNode n = getNode(p);
956
957         /*
958                 From this node to nodes underneath:
959                 If lighting is sunlight (1.0), unlight neighbours and
960                 set lighting to 0.
961                 Else discontinue.
962         */
963
964         bool node_under_sunlight = true;
965         
966         v3s16 toppos = p + v3s16(0,1,0);
967
968         /*
969                 If there is a node at top and it doesn't have sunlight,
970                 there has not been any sunlight going down.
971
972                 Otherwise there probably is.
973         */
974         try{
975                 MapNode topnode = getNode(toppos);
976
977                 if(topnode.getLight() != LIGHT_SUN)
978                         node_under_sunlight = false;
979         }
980         catch(InvalidPositionException &e)
981         {
982         }
983
984         // Add the block of the added node to modified_blocks
985         v3s16 blockpos = getNodeBlockPos(p);
986         MapBlock * block = getBlockNoCreate(blockpos);
987         assert(block != NULL);
988         modified_blocks.insert(blockpos, block);
989         
990         if(isValidPosition(p) == false)
991                 throw;
992                 
993         // Unlight neighbours of node.
994         // This means setting light of all consequent dimmer nodes
995         // to 0.
996         // This also collects the nodes at the border which will spread
997         // light again into this.
998         unLightNeighbors(p, lightwas, light_sources, modified_blocks);
999
1000         n.setLight(0);
1001         setNode(p, n);
1002         
1003         /*
1004                 If node is under sunlight, take all sunlighted nodes under
1005                 it and clear light from them and from where the light has
1006                 been spread.
1007         */
1008         if(node_under_sunlight)
1009         {
1010                 s16 y = p.Y - 1;
1011                 for(;; y--){
1012                         //m_dout<<DTIME<<"y="<<y<<std::endl;
1013                         v3s16 n2pos(p.X, y, p.Z);
1014                         
1015                         MapNode n2;
1016                         try{
1017                                 n2 = getNode(n2pos);
1018                         }
1019                         catch(InvalidPositionException &e)
1020                         {
1021                                 break;
1022                         }
1023
1024                         if(n2.getLight() == LIGHT_SUN)
1025                         {
1026                                 //m_dout<<DTIME<<"doing"<<std::endl;
1027                                 unLightNeighbors(n2pos, n2.getLight(), light_sources, modified_blocks);
1028                                 n2.setLight(0);
1029                                 setNode(n2pos, n2);
1030                         }
1031                         else
1032                                 break;
1033                 }
1034         }
1035         
1036         /*
1037                 Spread light from all nodes that might be capable of doing so
1038                 TODO: Convert to spreadLight
1039         */
1040         spreadLight(light_sources, modified_blocks);
1041 }
1042
1043 /*
1044 */
1045 void Map::removeNodeAndUpdate(v3s16 p,
1046                 core::map<v3s16, MapBlock*> &modified_blocks)
1047 {
1048         /*PrintInfo(m_dout);
1049         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1050                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1051         
1052         bool node_under_sunlight = true;
1053         
1054         v3s16 toppos = p + v3s16(0,1,0);
1055
1056         // Node will be replaced with this
1057         u8 replace_material = CONTENT_AIR;
1058         
1059         // NOTE: Water is now managed elsewhere
1060 #if 0
1061         {
1062                 /*
1063                         Find out with what material the node will be replaced.
1064                         It will be replaced with the mostly seen buildable_to.
1065                 */
1066
1067                 v3s16 dirs[6] = {
1068                         v3s16(0,0,1), // back
1069                         v3s16(0,1,0), // top
1070                         v3s16(1,0,0), // right
1071                         v3s16(0,0,-1), // front
1072                         v3s16(0,-1,0), // bottom
1073                         v3s16(-1,0,0), // left
1074                 };
1075
1076                 core::map<u8, u16> neighbor_rankings;
1077                 
1078                 for(u32 i=0; i<sizeof(dirs)/sizeof(dirs[0]); i++)
1079                 {
1080                         try{
1081                                 MapNode n2 = getNode(p + dirs[i]);
1082
1083                                 if(material_buildable_to(n2.d))
1084                                 {
1085                                         if(neighbor_rankings.find(n2.d) == NULL)
1086                                                 neighbor_rankings[n2.d] = 1;
1087                                         else
1088                                                 neighbor_rankings[n2.d]
1089                                                         = neighbor_rankings[n2.d] + 1;
1090                                 }
1091                         }
1092                         catch(InvalidPositionException &e)
1093                         {
1094                         }
1095                 }
1096
1097                 u16 highest_ranking = 0;
1098                 
1099                 for(core::map<u8, u16>::Iterator
1100                                 i = neighbor_rankings.getIterator();
1101                                 i.atEnd() == false; i++)
1102                 {
1103                         u8 m = i.getNode()->getKey();
1104                         u8 c = i.getNode()->getValue();
1105                         if(
1106                                         c > highest_ranking ||
1107                                         // Prefer something else than air
1108                                         (c >= highest_ranking && m != CONTENT_AIR)
1109
1110                         )
1111                         {
1112                                 replace_material = m;
1113                                 highest_ranking = c;
1114                         }
1115                 }
1116         }
1117
1118 #endif
1119
1120         /*
1121                 If there is a node at top and it doesn't have sunlight,
1122                 there will be no sunlight going down.
1123         */
1124         try{
1125                 MapNode topnode = getNode(toppos);
1126
1127                 if(topnode.getLight() != LIGHT_SUN)
1128                         node_under_sunlight = false;
1129         }
1130         catch(InvalidPositionException &e)
1131         {
1132         }
1133
1134         /*
1135                 Unlight neighbors (in case the node is a light source)
1136         */
1137         //core::list<v3s16> light_sources;
1138         core::map<v3s16, bool> light_sources;
1139         unLightNeighbors(p, getNode(p).getLight(),
1140                         light_sources, modified_blocks);
1141
1142         /*
1143                 Remove the node
1144         */
1145         MapNode n;
1146         n.d = replace_material;
1147         n.setLight(0);
1148         setNode(p, n);
1149         
1150         /*
1151                 Recalculate lighting
1152         */
1153         spreadLight(light_sources, modified_blocks);
1154
1155         // Add the block of the removed node to modified_blocks
1156         v3s16 blockpos = getNodeBlockPos(p);
1157         MapBlock * block = getBlockNoCreate(blockpos);
1158         assert(block != NULL);
1159         modified_blocks.insert(blockpos, block);
1160
1161         /*
1162                 If the removed node was under sunlight, propagate the
1163                 sunlight down from it and then light all neighbors
1164                 of the propagated blocks.
1165         */
1166         if(node_under_sunlight)
1167         {
1168                 s16 ybottom = propagateSunlight(p, modified_blocks);
1169                 /*m_dout<<DTIME<<"Node was under sunlight. "
1170                                 "Propagating sunlight";
1171                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1172                 s16 y = p.Y;
1173                 for(; y >= ybottom; y--)
1174                 {
1175                         v3s16 p2(p.X, y, p.Z);
1176                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1177                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1178                                         <<std::endl;*/
1179                         lightNeighbors(p2, modified_blocks);
1180                 }
1181         }
1182         else
1183         {
1184                 // Set the lighting of this node to 0
1185                 try{
1186                         MapNode n = getNode(p);
1187                         n.setLight(0);
1188                         setNode(p, n);
1189                 }
1190                 catch(InvalidPositionException &e)
1191                 {
1192                         throw;
1193                 }
1194         }
1195
1196         // Get the brightest neighbour node and propagate light from it
1197         v3s16 n2p = getBrightestNeighbour(p);
1198         try{
1199                 MapNode n2 = getNode(n2p);
1200                 lightNeighbors(n2p, modified_blocks);
1201         }
1202         catch(InvalidPositionException &e)
1203         {
1204         }
1205 }
1206
1207 void Map::updateMeshes(v3s16 blockpos)
1208 {
1209         assert(mapType() == MAPTYPE_CLIENT);
1210
1211         try{
1212                 v3s16 p = blockpos + v3s16(0,0,0);
1213                 MapBlock *b = getBlockNoCreate(p);
1214                 b->updateMesh();
1215         }
1216         catch(InvalidPositionException &e){}
1217         try{
1218                 v3s16 p = blockpos + v3s16(-1,0,0);
1219                 MapBlock *b = getBlockNoCreate(p);
1220                 b->updateMesh();
1221         }
1222         catch(InvalidPositionException &e){}
1223         try{
1224                 v3s16 p = blockpos + v3s16(0,-1,0);
1225                 MapBlock *b = getBlockNoCreate(p);
1226                 b->updateMesh();
1227         }
1228         catch(InvalidPositionException &e){}
1229         try{
1230                 v3s16 p = blockpos + v3s16(0,0,-1);
1231                 MapBlock *b = getBlockNoCreate(p);
1232                 b->updateMesh();
1233         }
1234         catch(InvalidPositionException &e){}
1235 }
1236
1237 /*
1238         Updates usage timers
1239 */
1240 void Map::timerUpdate(float dtime)
1241 {
1242         JMutexAutoLock lock(m_sector_mutex);
1243
1244         core::map<v2s16, MapSector*>::Iterator si;
1245
1246         si = m_sectors.getIterator();
1247         for(; si.atEnd() == false; si++)
1248         {
1249                 MapSector *sector = si.getNode()->getValue();
1250                 sector->usage_timer += dtime;
1251         }
1252 }
1253
1254 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
1255 {
1256         /*
1257                 Wait for caches to be removed before continuing.
1258                 
1259                 This disables the existence of caches while locked
1260         */
1261         SharedPtr<JMutexAutoLock> cachelock(m_blockcachelock.waitCaches());
1262
1263         core::list<v2s16>::Iterator j;
1264         for(j=list.begin(); j!=list.end(); j++)
1265         {
1266                 MapSector *sector = m_sectors[*j];
1267                 if(only_blocks)
1268                 {
1269                         sector->deleteBlocks();
1270                 }
1271                 else
1272                 {
1273                         /*
1274                                 If sector is in sector cache, remove it from there
1275                         */
1276                         if(m_sector_cache == sector)
1277                         {
1278                                 m_sector_cache = NULL;
1279                         }
1280                         /*
1281                                 Remove from map and delete
1282                         */
1283                         m_sectors.remove(*j);
1284                         delete sector;
1285                 }
1286         }
1287 }
1288
1289 u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
1290                 core::list<v3s16> *deleted_blocks)
1291 {
1292         JMutexAutoLock lock(m_sector_mutex);
1293
1294         core::list<v2s16> sector_deletion_queue;
1295         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
1296         for(; i.atEnd() == false; i++)
1297         {
1298                 MapSector *sector = i.getNode()->getValue();
1299                 /*
1300                         Delete sector from memory if it hasn't been used in a long time
1301                 */
1302                 if(sector->usage_timer > timeout)
1303                 {
1304                         sector_deletion_queue.push_back(i.getNode()->getKey());
1305                         
1306                         if(deleted_blocks != NULL)
1307                         {
1308                                 // Collect positions of blocks of sector
1309                                 MapSector *sector = i.getNode()->getValue();
1310                                 core::list<MapBlock*> blocks;
1311                                 sector->getBlocks(blocks);
1312                                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1313                                                 i != blocks.end(); i++)
1314                                 {
1315                                         deleted_blocks->push_back((*i)->getPos());
1316                                 }
1317                         }
1318                 }
1319         }
1320         deleteSectors(sector_deletion_queue, only_blocks);
1321         return sector_deletion_queue.getSize();
1322 }
1323
1324 void Map::PrintInfo(std::ostream &out)
1325 {
1326         out<<"Map: ";
1327 }
1328
1329 /*
1330         ServerMap
1331 */
1332
1333 ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
1334         Map(dout_server),
1335         m_heightmap(NULL)
1336 {
1337         m_savedir = savedir;
1338         m_map_saving_enabled = false;
1339         
1340         try
1341         {
1342                 // If directory exists, check contents and load if possible
1343                 if(fs::PathExists(m_savedir))
1344                 {
1345                         // If directory is empty, it is safe to save into it.
1346                         if(fs::GetDirListing(m_savedir).size() == 0)
1347                         {
1348                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1349                                                 <<std::endl;
1350                                 m_map_saving_enabled = true;
1351                         }
1352                         else
1353                         {
1354                                 // Load master heightmap
1355                                 loadMasterHeightmap();
1356                                 
1357                                 // Load sector (0,0) and throw and exception on fail
1358                                 if(loadSectorFull(v2s16(0,0)) == false)
1359                                         throw LoadError("Failed to load sector (0,0)");
1360
1361                                 dstream<<DTIME<<"Server: Successfully loaded master "
1362                                                 "heightmap and sector (0,0) from "<<savedir<<
1363                                                 ", assuming valid save directory."
1364                                                 <<std::endl;
1365
1366                                 m_map_saving_enabled = true;
1367                                 // Map loaded, not creating new one
1368                                 return;
1369                         }
1370                 }
1371                 // If directory doesn't exist, it is safe to save to it
1372                 else{
1373                         m_map_saving_enabled = true;
1374                 }
1375         }
1376         catch(std::exception &e)
1377         {
1378                 dstream<<DTIME<<"Server: Failed to load map from "<<savedir
1379                                 <<", exception: "<<e.what()<<std::endl;
1380                 dstream<<DTIME<<"Please remove the map or fix it."<<std::endl;
1381                 dstream<<DTIME<<"WARNING: Map saving will be disabled."<<std::endl;
1382         }
1383
1384         dstream<<DTIME<<"Initializing new map."<<std::endl;
1385         
1386         // Create master heightmap
1387         ValueGenerator *maxgen =
1388                         ValueGenerator::deSerialize(hmp.randmax);
1389         ValueGenerator *factorgen =
1390                         ValueGenerator::deSerialize(hmp.randfactor);
1391         ValueGenerator *basegen =
1392                         ValueGenerator::deSerialize(hmp.base);
1393         m_heightmap = new UnlimitedHeightmap
1394                         (hmp.blocksize, maxgen, factorgen, basegen);
1395         
1396         // Set map parameters
1397         m_params = mp;
1398         
1399         // Create zero sector
1400         emergeSector(v2s16(0,0));
1401
1402         // Initially write whole map
1403         save(false);
1404 }
1405
1406 ServerMap::~ServerMap()
1407 {
1408         try
1409         {
1410                 if(m_map_saving_enabled)
1411                 {
1412                         //save(false);
1413                         // Save only changed parts
1414                         save(true);
1415                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1416                 }
1417                 else
1418                 {
1419                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1420                 }
1421         }
1422         catch(std::exception &e)
1423         {
1424                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1425                                 <<", exception: "<<e.what()<<std::endl;
1426         }
1427         
1428         if(m_heightmap != NULL)
1429                 delete m_heightmap;
1430 }
1431
1432 MapSector * ServerMap::emergeSector(v2s16 p2d)
1433 {
1434         DSTACK("%s: p2d=(%d,%d)",
1435                         __FUNCTION_NAME,
1436                         p2d.X, p2d.Y);
1437         // Check that it doesn't exist already
1438         try{
1439                 return getSectorNoGenerate(p2d);
1440         }
1441         catch(InvalidPositionException &e)
1442         {
1443         }
1444         
1445         /*
1446                 Try to load the sector from disk.
1447         */
1448         if(loadSectorFull(p2d) == true)
1449         {
1450                 return getSectorNoGenerate(p2d);
1451         }
1452
1453         /*
1454                 If there is no master heightmap, throw.
1455         */
1456         if(m_heightmap == NULL)
1457         {
1458                 throw InvalidPositionException("emergeSector(): no heightmap");
1459         }
1460
1461         /*
1462                 Do not generate over-limit
1463         */
1464         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1465         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1466         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1467         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
1468                 throw InvalidPositionException("emergeSector(): pos. over limit");
1469
1470         /*
1471                 Generate sector and heightmaps
1472         */
1473         
1474         // Number of heightmaps in sector in each direction
1475         u16 hm_split = SECTOR_HEIGHTMAP_SPLIT;
1476
1477         // Heightmap side width
1478         s16 hm_d = MAP_BLOCKSIZE / hm_split;
1479
1480         ServerMapSector *sector = new ServerMapSector(this, p2d, hm_split);
1481
1482         /*dstream<<"Generating sector ("<<p2d.X<<","<<p2d.Y<<")"
1483                         " heightmaps and objects"<<std::endl;*/
1484         
1485         // Loop through sub-heightmaps
1486         for(s16 y=0; y<hm_split; y++)
1487         for(s16 x=0; x<hm_split; x++)
1488         {
1489                 v2s16 p_in_sector = v2s16(x,y);
1490                 v2s16 mhm_p = p2d * hm_split + p_in_sector;
1491                 f32 corners[4] = {
1492                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)),
1493                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)),
1494                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)),
1495                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)),
1496                 };
1497
1498                 /*dstream<<"p_in_sector=("<<p_in_sector.X<<","<<p_in_sector.Y<<")"
1499                                 <<" mhm_p=("<<mhm_p.X<<","<<mhm_p.Y<<")"
1500                                 <<std::endl;*/
1501
1502                 FixedHeightmap *hm = new FixedHeightmap(&m_hwrapper,
1503                                 mhm_p, hm_d);
1504                 sector->setHeightmap(p_in_sector, hm);
1505
1506                 //TODO: Make these values configurable
1507                 hm->generateContinued(1.0, 0.2, corners);
1508                 //hm->generateContinued(2.0, 0.2, corners);
1509
1510                 //hm->print();
1511                 
1512         }
1513
1514         /*
1515                 Generate objects
1516         */
1517         
1518         core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
1519         sector->setObjects(objects);
1520         
1521         v2s16 mhm_p = p2d * hm_split;
1522         f32 corners[4] = {
1523                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split),
1524                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split),
1525                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split),
1526                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split),
1527         };
1528         
1529         float avgheight = (corners[0]+corners[1]+corners[2]+corners[3])/4.0;
1530         float avgslope = 0.0;
1531         avgslope += fabs(avgheight - corners[0]);
1532         avgslope += fabs(avgheight - corners[1]);
1533         avgslope += fabs(avgheight - corners[2]);
1534         avgslope += fabs(avgheight - corners[3]);
1535         avgslope /= 4.0;
1536         avgslope /= MAP_BLOCKSIZE;
1537         //dstream<<"avgslope="<<avgslope<<std::endl;
1538
1539         float pitness = 0.0;
1540         v2f32 a;
1541         a = m_heightmap->getSlope(p2d+v2s16(0,0));
1542         pitness += -a.X;
1543         pitness += -a.Y;
1544         a = m_heightmap->getSlope(p2d+v2s16(0,1));
1545         pitness += -a.X;
1546         pitness += a.Y;
1547         a = m_heightmap->getSlope(p2d+v2s16(1,1));
1548         pitness += a.X;
1549         pitness += a.Y;
1550         a = m_heightmap->getSlope(p2d+v2s16(1,0));
1551         pitness += a.X;
1552         pitness += -a.Y;
1553         pitness /= 4.0;
1554         pitness /= MAP_BLOCKSIZE;
1555         //dstream<<"pitness="<<pitness<<std::endl;
1556         
1557         /*
1558                 Plant some trees if there is not much slope
1559         */
1560         {
1561                 // Avgslope is the derivative of a hill
1562                 float t = avgslope * avgslope;
1563                 float a = MAP_BLOCKSIZE * m_params.plants_amount;
1564                 u32 tree_max;
1565                 if(t > 0.03)
1566                         tree_max = a / (t/0.03);
1567                 else
1568                         tree_max = a;
1569                 u32 count = (rand()%(tree_max+1));
1570                 //u32 count = tree_max;
1571                 for(u32 i=0; i<count; i++)
1572                 {
1573                         s16 x = (rand()%(MAP_BLOCKSIZE-2))+1;
1574                         s16 z = (rand()%(MAP_BLOCKSIZE-2))+1;
1575                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1576                         if(y < WATER_LEVEL)
1577                                 continue;
1578                         objects->insert(v3s16(x, y, z),
1579                                         SECTOR_OBJECT_TREE_1);
1580                 }
1581         }
1582         /*
1583                 Plant some bushes if sector is pit-like
1584         */
1585         {
1586                 // Pitness usually goes at around -0.5...0.5
1587                 u32 bush_max = 0;
1588                 u32 a = MAP_BLOCKSIZE * 3.0 * m_params.plants_amount;
1589                 if(pitness > 0)
1590                         bush_max = (pitness*a*4);
1591                 if(bush_max > a)
1592                         bush_max = a;
1593                 u32 count = (rand()%(bush_max+1));
1594                 for(u32 i=0; i<count; i++)
1595                 {
1596                         s16 x = rand()%(MAP_BLOCKSIZE-0)+0;
1597                         s16 z = rand()%(MAP_BLOCKSIZE-0)+0;
1598                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1599                         if(y < WATER_LEVEL)
1600                                 continue;
1601                         objects->insert(v3s16(x, y, z),
1602                                         SECTOR_OBJECT_BUSH_1);
1603                 }
1604         }
1605         /*
1606                 Add ravine (randomly)
1607         */
1608         if(m_params.ravines_amount != 0)
1609         {
1610                 if(rand()%(s32)(20.0 / m_params.ravines_amount) == 0)
1611                 {
1612                         s16 s = 6;
1613                         s16 x = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
1614                         s16 z = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
1615                         /*s16 x = 8;
1616                         s16 z = 8;*/
1617                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1618                         objects->insert(v3s16(x, y, z),
1619                                         SECTOR_OBJECT_RAVINE);
1620                 }
1621         }
1622
1623         /*
1624                 Insert to container
1625         */
1626         JMutexAutoLock lock(m_sector_mutex);
1627         m_sectors.insert(p2d, sector);
1628         
1629         return sector;
1630 }
1631
1632 MapBlock * ServerMap::emergeBlock(
1633                 v3s16 p,
1634                 bool only_from_disk,
1635                 core::map<v3s16, MapBlock*> &changed_blocks,
1636                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
1637 )
1638 {
1639         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
1640                         __FUNCTION_NAME,
1641                         p.X, p.Y, p.Z, only_from_disk);
1642                         
1643         /*dstream<<"ServerMap::emergeBlock(): "
1644                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1645                         <<", only_from_disk="<<only_from_disk<<std::endl;*/
1646         v2s16 p2d(p.X, p.Z);
1647         s16 block_y = p.Y;
1648         /*
1649                 This will create or load a sector if not found in memory.
1650                 If block exists on disk, it will be loaded.
1651
1652                 NOTE: On old save formats, this will be slow, as it generates
1653                       lighting on blocks for them.
1654         */
1655         ServerMapSector *sector = (ServerMapSector*)emergeSector(p2d);
1656         assert(sector->getId() == MAPSECTOR_SERVER);
1657
1658         // Try to get a block from the sector
1659         MapBlock *block = NULL;
1660         bool not_on_disk = false;
1661         try{
1662                 block = sector->getBlockNoCreate(block_y);
1663                 if(block->isDummy() == true)
1664                         not_on_disk = true;
1665                 else
1666                         return block;
1667         }
1668         catch(InvalidPositionException &e)
1669         {
1670                 not_on_disk = true;
1671         }
1672         
1673         /*
1674                 If block was not found on disk and not going to generate a
1675                 new one, make sure there is a dummy block in place.
1676         */
1677         if(not_on_disk && only_from_disk)
1678         {
1679                 if(block == NULL)
1680                 {
1681                         // Create dummy block
1682                         block = new MapBlock(this, p, true);
1683
1684                         // Add block to sector
1685                         sector->insertBlock(block);
1686                 }
1687                 // Done.
1688                 return block;
1689         }
1690
1691         //dstream<<"Not found on disk, generating."<<std::endl;
1692
1693         /*
1694                 Do not generate over-limit
1695         */
1696         if(blockpos_over_limit(p))
1697                 throw InvalidPositionException("emergeBlock(): pos. over limit");
1698
1699         /*
1700                 OK; Not found.
1701
1702                 Go on generating the block.
1703
1704                 TODO: If a dungeon gets generated so that it's side gets
1705                       revealed to the outside air, the lighting should be
1706                           recalculated.
1707         */
1708         
1709         /*
1710                 If block doesn't exist, create one.
1711                 If it exists, it is a dummy. In that case unDummify() it.
1712         */
1713         if(block == NULL)
1714         {
1715                 block = sector->createBlankBlockNoInsert(block_y);
1716         }
1717         else
1718         {
1719                 // Remove the block so that nobody can get a half-generated one.
1720                 sector->removeBlock(block);
1721                 // Allocate the block to be a proper one.
1722                 block->unDummify();
1723         }
1724
1725         // Randomize a bit. This makes dungeons.
1726         /*bool low_block_is_empty = false;
1727         if(rand() % 4 == 0)
1728                 low_block_is_empty = true;*/
1729         
1730         const s32 ued = 4;
1731         //const s32 ued = 8;
1732         bool underground_emptiness[ued*ued*ued];
1733         for(s32 i=0; i<ued*ued*ued; i++)
1734         {
1735                 underground_emptiness[i] = ((rand() % 5) == 0);
1736         }
1737
1738 #if 0
1739         /*
1740                 This is a messy hack to sort the emptiness a bit
1741         */
1742         for(s32 j=0; j<2; j++)
1743         for(s32 y0=0; y0<ued; y0++)
1744         for(s32 z0=0; z0<ued; z0++)
1745         for(s32 x0=0; x0<ued; x0++)
1746         {
1747                 v3s16 p0(x0,y0,z0);
1748                 bool &e0 = underground_emptiness[
1749                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1750                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1751                                 +(x0*ued/MAP_BLOCKSIZE)];
1752                                 
1753                 v3s16 dirs[6] = {
1754                         v3s16(0,0,1), // back
1755                         v3s16(1,0,0), // right
1756                         v3s16(0,0,-1), // front
1757                         v3s16(-1,0,0), // left
1758                         /*v3s16(0,1,0), // top
1759                         v3s16(0,-1,0), // bottom*/
1760                 };
1761                 for(s32 i=0; i<4; i++)
1762                 {
1763                         v3s16 p1 = p0 + dirs[i];
1764                         if(isInArea(p1, ued) == false)
1765                                 continue;
1766                         bool &e1 = underground_emptiness[
1767                                         ued*ued*(p1.Z*ued/MAP_BLOCKSIZE)
1768                                         +ued*(p1.Y*ued/MAP_BLOCKSIZE)
1769                                         +(p1.X*ued/MAP_BLOCKSIZE)];
1770                         if(e0 == e1)
1771                                 continue;
1772                                 
1773                         v3s16 dirs[6] = {
1774                                 v3s16(0,1,0), // top
1775                                 v3s16(0,-1,0), // bottom
1776                                 /*v3s16(0,0,1), // back
1777                                 v3s16(1,0,0), // right
1778                                 v3s16(0,0,-1), // front
1779                                 v3s16(-1,0,0), // left*/
1780                         };
1781                         for(s32 i=0; i<2; i++)
1782                         {
1783                                 v3s16 p2 = p1 + dirs[i];
1784                                 if(p2 == p0)
1785                                         continue;
1786                                 if(isInArea(p2, ued) == false)
1787                                         continue;
1788                                 bool &e2 = underground_emptiness[
1789                                                 ued*ued*(p2.Z*ued/MAP_BLOCKSIZE)
1790                                                 +ued*(p2.Y*ued/MAP_BLOCKSIZE)
1791                                                 +(p2.X*ued/MAP_BLOCKSIZE)];
1792                                 if(e2 != e0)
1793                                         continue;
1794                                 
1795                                 bool t = e1;
1796                                 e1 = e2;
1797                                 e2 = t;
1798
1799                                 break;
1800                         }
1801                         //break;
1802                 }
1803         }
1804 #endif
1805         
1806         // This is the basic material of what the visible flat ground
1807         // will consist of
1808         u8 material = CONTENT_GRASS;
1809
1810         u8 water_material = CONTENT_WATER;
1811         if(g_settings.getBool("endless_water"))
1812                 water_material = CONTENT_OCEAN;
1813         
1814         s32 lowest_ground_y = 32767;
1815         s32 highest_ground_y = -32768;
1816         
1817         // DEBUG
1818         //sector->printHeightmaps();
1819
1820         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1821         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1822         {
1823                 //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
1824
1825                 float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
1826                 //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
1827                 if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE)
1828                 {
1829                         dstream<<"WARNING: Surface height not found in sector "
1830                                         "for block that is being emerged"<<std::endl;
1831                         surface_y_f = 0.0;
1832                 }
1833
1834                 s16 surface_y = surface_y_f;
1835                 //avg_ground_y += surface_y;
1836                 if(surface_y < lowest_ground_y)
1837                         lowest_ground_y = surface_y;
1838                 if(surface_y > highest_ground_y)
1839                         highest_ground_y = surface_y;
1840
1841                 s32 surface_depth = 0;
1842                 
1843                 float slope = sector->getSlope(v2s16(x0,z0)).getLength();
1844                 
1845                 //float min_slope = 0.45;
1846                 //float max_slope = 0.85;
1847                 float min_slope = 0.70;
1848                 float max_slope = 1.20;
1849                 float min_slope_depth = 4.0;
1850                 //float min_slope_depth = 5.0;
1851                 float max_slope_depth = 0;
1852                 if(slope < min_slope)
1853                         surface_depth = min_slope_depth;
1854                 else if(slope > max_slope)
1855                         surface_depth = max_slope_depth;
1856                 else
1857                         surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
1858
1859                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1860                 {
1861                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
1862                         MapNode n;
1863                         /*
1864                                 Calculate lighting
1865                                 
1866                                 NOTE: If there are some man-made structures above the
1867                                 newly created block, they won't be taken into account.
1868                         */
1869                         if(real_y > surface_y)
1870                                 n.setLight(LIGHT_SUN);
1871
1872                         /*
1873                                 Calculate material
1874                         */
1875
1876                         // If node is very low
1877                         /*if(real_y <= surface_y - 7)
1878                         {
1879                                 // Create dungeons
1880                                 if(underground_emptiness[
1881                                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1882                                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1883                                                 +(x0*ued/MAP_BLOCKSIZE)])
1884                                 {
1885                                         n.d = CONTENT_AIR;
1886                                 }
1887                                 else
1888                                 {
1889                                         n.d = CONTENT_STONE;
1890                                 }
1891                         }
1892                         // If node is under surface level
1893                         else if(real_y <= surface_y - surface_depth)
1894                                 n.d = CONTENT_STONE;
1895                         */
1896                         if(real_y <= surface_y - surface_depth)
1897                         {
1898                                 // Create dungeons
1899                                 if(underground_emptiness[
1900                                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1901                                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1902                                                 +(x0*ued/MAP_BLOCKSIZE)])
1903                                 {
1904                                         n.d = CONTENT_AIR;
1905                                 }
1906                                 else
1907                                 {
1908                                         n.d = CONTENT_STONE;
1909                                 }
1910                         }
1911                         // If node is at or under heightmap y
1912                         else if(real_y <= surface_y)
1913                         {
1914                                 // If under water level, it's mud
1915                                 if(real_y < WATER_LEVEL)
1916                                         n.d = CONTENT_MUD;
1917                                 // Only the topmost node is grass
1918                                 else if(real_y <= surface_y - 1)
1919                                         n.d = CONTENT_MUD;
1920                                 // Else it's the main material
1921                                 else
1922                                         n.d = material;
1923                         }
1924                         // If node is over heightmap y
1925                         else{
1926                                 // If under water level, it's water
1927                                 if(real_y < WATER_LEVEL)
1928                                 {
1929                                         n.d = water_material;
1930                                         n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
1931                                 }
1932                                 // else air
1933                                 else
1934                                         n.d = CONTENT_AIR;
1935                         }
1936                         block->setNode(v3s16(x0,y0,z0), n);
1937                 }
1938         }
1939
1940         /*
1941                 Calculate is_underground
1942         */
1943         // Probably underground if the highest part of block is under lowest
1944         // ground height
1945         bool is_underground = (block_y+1) * MAP_BLOCKSIZE <= lowest_ground_y;
1946         block->setIsUnderground(is_underground);
1947
1948         /*
1949                 Force lighting update if some part of block is underground
1950                 This is needed because of caves.
1951         */
1952         
1953         bool some_part_underground = (block_y+0) * MAP_BLOCKSIZE < highest_ground_y;
1954         if(some_part_underground)
1955         //if(is_underground)
1956         {
1957                 lighting_invalidated_blocks[block->getPos()] = block;
1958         }
1959         
1960         /*
1961                 Add some minerals
1962         */
1963
1964         if(is_underground)
1965         {
1966                 s16 underground_level = lowest_ground_y/MAP_BLOCKSIZE - block_y;
1967                 for(s16 i=0; i<underground_level*3; i++)
1968                 {
1969                         if(rand()%2 == 0)
1970                         {
1971                                 v3s16 cp(
1972                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1973                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1974                                         (rand()%(MAP_BLOCKSIZE-2))+1
1975                                 );
1976
1977                                 MapNode n;
1978                                 n.d = CONTENT_MESE;
1979                                 
1980                                 if(is_ground_content(block->getNode(cp).d))
1981                                         if(rand()%8 == 0)
1982                                                 block->setNode(cp, n);
1983
1984                                 for(u16 i=0; i<26; i++)
1985                                 {
1986                                         if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
1987                                                 if(rand()%8 == 0)
1988                                                         block->setNode(cp+g_26dirs[i], n);
1989                                 }
1990                         }
1991                 }
1992         }
1993         
1994         /*
1995                 Create a few rats in empty blocks underground
1996         */
1997         if(is_underground)
1998         {
1999                 //for(u16 i=0; i<2; i++)
2000                 {
2001                         v3s16 cp(
2002                                 (rand()%(MAP_BLOCKSIZE-2))+1,
2003                                 (rand()%(MAP_BLOCKSIZE-2))+1,
2004                                 (rand()%(MAP_BLOCKSIZE-2))+1
2005                         );
2006
2007                         // Check that the place is empty
2008                         //if(!is_ground_content(block->getNode(cp).d))
2009                         if(1)
2010                         {
2011                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
2012                                 block->addObject(obj);
2013                         }
2014                 }
2015         }
2016         
2017         /*
2018                 Add block to sector.
2019         */
2020         sector->insertBlock(block);
2021         
2022         /*
2023                 Do some interpolation for dungeons
2024         */
2025
2026 #if 0   
2027         {
2028         TimeTaker timer("interpolation", g_device);
2029         
2030         MapVoxelManipulator vmanip(this);
2031         
2032         v3s16 relpos = block->getPosRelative();
2033
2034         vmanip.interpolate(VoxelArea(relpos-v3s16(1,1,1),
2035                         relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE+1)));
2036         /*vmanip.interpolate(VoxelArea(relpos,
2037                         relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE-1)));*/
2038         
2039         core::map<v3s16, MapBlock*> modified_blocks;
2040         vmanip.blitBack(modified_blocks);
2041         dstream<<"blitBack modified "<<modified_blocks.size()
2042                         <<" blocks"<<std::endl;
2043
2044         // Add modified blocks to changed_blocks and lighting_invalidated_blocks
2045         for(core::map<v3s16, MapBlock*>::Iterator
2046                         i = modified_blocks.getIterator();
2047                         i.atEnd() == false; i++)
2048         {
2049                 MapBlock *block = i.getNode()->getValue();
2050
2051                 changed_blocks.insert(block->getPos(), block);
2052                 //lighting_invalidated_blocks.insert(block->getPos(), block);
2053         }
2054
2055         }
2056 #endif
2057
2058         /*
2059                 Sector object stuff
2060         */
2061                 
2062         // An y-wise container of changed blocks
2063         core::map<s16, MapBlock*> changed_blocks_sector;
2064
2065         /*
2066                 Check if any sector's objects can be placed now.
2067                 If so, place them.
2068         */
2069         core::map<v3s16, u8> *objects = sector->getObjects();
2070         core::list<v3s16> objects_to_remove;
2071         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
2072                         i.atEnd() == false; i++)
2073         {
2074                 v3s16 p = i.getNode()->getKey();
2075                 v2s16 p2d(p.X,p.Z);
2076                 u8 d = i.getNode()->getValue();
2077
2078                 //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
2079                 
2080                 try
2081                 {
2082
2083                 if(d == SECTOR_OBJECT_TEST)
2084                 {
2085                         if(sector->isValidArea(p + v3s16(0,0,0),
2086                                         p + v3s16(0,0,0), &changed_blocks_sector))
2087                         {
2088                                 MapNode n;
2089                                 n.d = CONTENT_LIGHT;
2090                                 sector->setNode(p, n);
2091                                 objects_to_remove.push_back(p);
2092                         }
2093                 }
2094                 else if(d == SECTOR_OBJECT_TREE_1)
2095                 {
2096                         v3s16 p_min = p + v3s16(-1,0,-1);
2097                         v3s16 p_max = p + v3s16(1,4,1);
2098                         if(sector->isValidArea(p_min, p_max,
2099                                         &changed_blocks_sector))
2100                         {
2101                                 MapNode n;
2102                                 n.d = CONTENT_TREE;
2103                                 sector->setNode(p+v3s16(0,0,0), n);
2104                                 sector->setNode(p+v3s16(0,1,0), n);
2105                                 sector->setNode(p+v3s16(0,2,0), n);
2106                                 sector->setNode(p+v3s16(0,3,0), n);
2107
2108                                 n.d = CONTENT_LEAVES;
2109
2110                                 sector->setNode(p+v3s16(0,4,0), n);
2111                                 
2112                                 sector->setNode(p+v3s16(-1,4,0), n);
2113                                 sector->setNode(p+v3s16(1,4,0), n);
2114                                 sector->setNode(p+v3s16(0,4,-1), n);
2115                                 sector->setNode(p+v3s16(0,4,1), n);
2116                                 sector->setNode(p+v3s16(1,4,1), n);
2117                                 sector->setNode(p+v3s16(-1,4,1), n);
2118                                 sector->setNode(p+v3s16(-1,4,-1), n);
2119                                 sector->setNode(p+v3s16(1,4,-1), n);
2120
2121                                 sector->setNode(p+v3s16(-1,3,0), n);
2122                                 sector->setNode(p+v3s16(1,3,0), n);
2123                                 sector->setNode(p+v3s16(0,3,-1), n);
2124                                 sector->setNode(p+v3s16(0,3,1), n);
2125                                 sector->setNode(p+v3s16(1,3,1), n);
2126                                 sector->setNode(p+v3s16(-1,3,1), n);
2127                                 sector->setNode(p+v3s16(-1,3,-1), n);
2128                                 sector->setNode(p+v3s16(1,3,-1), n);
2129                                 
2130                                 objects_to_remove.push_back(p);
2131                                 
2132                                 // Lighting has to be recalculated for this one.
2133                                 sector->getBlocksInArea(p_min, p_max, 
2134                                                 lighting_invalidated_blocks);
2135                         }
2136                 }
2137                 else if(d == SECTOR_OBJECT_BUSH_1)
2138                 {
2139                         if(sector->isValidArea(p + v3s16(0,0,0),
2140                                         p + v3s16(0,0,0), &changed_blocks_sector))
2141                         {
2142                                 MapNode n;
2143                                 n.d = CONTENT_LEAVES;
2144                                 sector->setNode(p+v3s16(0,0,0), n);
2145                                 
2146                                 objects_to_remove.push_back(p);
2147                         }
2148                 }
2149                 else if(d == SECTOR_OBJECT_RAVINE)
2150                 {
2151                         s16 maxdepth = -20;
2152                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
2153                         v3s16 p_max = p + v3s16(6,6,6);
2154                         if(sector->isValidArea(p_min, p_max,
2155                                         &changed_blocks_sector))
2156                         {
2157                                 MapNode n;
2158                                 n.d = CONTENT_STONE;
2159                                 MapNode n2;
2160                                 n2.d = CONTENT_AIR;
2161                                 s16 depth = maxdepth + (rand()%10);
2162                                 s16 z = 0;
2163                                 s16 minz = -6 - (-2);
2164                                 s16 maxz = 6 -1;
2165                                 for(s16 x=-6; x<=6; x++)
2166                                 {
2167                                         z += -1 + (rand()%3);
2168                                         if(z < minz)
2169                                                 z = minz;
2170                                         if(z > maxz)
2171                                                 z = maxz;
2172                                         for(s16 y=depth+(rand()%2); y<=6; y++)
2173                                         {
2174                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
2175                                                                 <<std::endl;*/
2176                                                 {
2177                                                         v3s16 p2 = p + v3s16(x,y,z-2);
2178                                                         if(is_ground_content(sector->getNode(p2).d))
2179                                                                 sector->setNode(p2, n);
2180                                                 }
2181                                                 {
2182                                                         v3s16 p2 = p + v3s16(x,y,z-1);
2183                                                         if(is_ground_content(sector->getNode(p2).d))
2184                                                                 sector->setNode(p2, n2);
2185                                                 }
2186                                                 {
2187                                                         v3s16 p2 = p + v3s16(x,y,z+0);
2188                                                         if(is_ground_content(sector->getNode(p2).d))
2189                                                                 sector->setNode(p2, n2);
2190                                                 }
2191                                                 {
2192                                                         v3s16 p2 = p + v3s16(x,y,z+1);
2193                                                         if(is_ground_content(sector->getNode(p2).d))
2194                                                                 sector->setNode(p2, n);
2195                                                 }
2196
2197                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
2198                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
2199                                         }
2200                                 }
2201                                 
2202                                 objects_to_remove.push_back(p);
2203                                 
2204                                 // Lighting has to be recalculated for this one.
2205                                 sector->getBlocksInArea(p_min, p_max, 
2206                                                 lighting_invalidated_blocks);
2207                         }
2208                 }
2209                 else
2210                 {
2211                         dstream<<"ServerMap::emergeBlock(): "
2212                                         "Invalid heightmap object"
2213                                         <<std::endl;
2214                 }
2215
2216                 }//try
2217                 catch(InvalidPositionException &e)
2218                 {
2219                         dstream<<"WARNING: "<<__FUNCTION_NAME
2220                                         <<": while inserting object "<<(int)d
2221                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
2222                                         <<" InvalidPositionException.what()="
2223                                         <<e.what()<<std::endl;
2224                         // This is not too fatal and seems to happen sometimes.
2225                         assert(0);
2226                 }
2227         }
2228
2229         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
2230                         i != objects_to_remove.end(); i++)
2231         {
2232                 objects->remove(*i);
2233         }
2234
2235         for(core::map<s16, MapBlock*>::Iterator
2236                         i = changed_blocks_sector.getIterator();
2237                         i.atEnd() == false; i++)
2238         {
2239                 MapBlock *block = i.getNode()->getValue();
2240
2241                 changed_blocks.insert(block->getPos(), block);
2242         }
2243
2244         return block;
2245 }
2246
2247 void ServerMap::createDir(std::string path)
2248 {
2249         if(fs::CreateDir(path) == false)
2250         {
2251                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2252                                 <<"\""<<path<<"\""<<std::endl;
2253                 throw BaseException("ServerMap failed to create directory");
2254         }
2255 }
2256
2257 std::string ServerMap::getSectorSubDir(v2s16 pos)
2258 {
2259         char cc[9];
2260         snprintf(cc, 9, "%.4x%.4x",
2261                         (unsigned int)pos.X&0xffff,
2262                         (unsigned int)pos.Y&0xffff);
2263
2264         return std::string(cc);
2265 }
2266
2267 std::string ServerMap::getSectorDir(v2s16 pos)
2268 {
2269         return m_savedir + "/sectors/" + getSectorSubDir(pos);
2270 }
2271
2272 v2s16 ServerMap::getSectorPos(std::string dirname)
2273 {
2274         if(dirname.size() != 8)
2275                 throw InvalidFilenameException("Invalid sector directory name");
2276         unsigned int x, y;
2277         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
2278         if(r != 2)
2279                 throw InvalidFilenameException("Invalid sector directory name");
2280         v2s16 pos((s16)x, (s16)y);
2281         return pos;
2282 }
2283
2284 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2285 {
2286         v2s16 p2d = getSectorPos(sectordir);
2287
2288         if(blockfile.size() != 4){
2289                 throw InvalidFilenameException("Invalid block filename");
2290         }
2291         unsigned int y;
2292         int r = sscanf(blockfile.c_str(), "%4x", &y);
2293         if(r != 1)
2294                 throw InvalidFilenameException("Invalid block filename");
2295         return v3s16(p2d.X, y, p2d.Y);
2296 }
2297
2298 // Debug helpers
2299 #define ENABLE_SECTOR_SAVING 1
2300 #define ENABLE_SECTOR_LOADING 1
2301 #define ENABLE_BLOCK_SAVING 1
2302 #define ENABLE_BLOCK_LOADING 1
2303
2304 void ServerMap::save(bool only_changed)
2305 {
2306         DSTACK(__FUNCTION_NAME);
2307         if(m_map_saving_enabled == false)
2308         {
2309                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2310                 return;
2311         }
2312         
2313         if(only_changed == false)
2314                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2315                                 <<std::endl;
2316         
2317         saveMasterHeightmap();
2318         
2319         u32 sector_meta_count = 0;
2320         u32 block_count = 0;
2321         
2322         { //sectorlock
2323         JMutexAutoLock lock(m_sector_mutex);
2324         
2325         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2326         for(; i.atEnd() == false; i++)
2327         {
2328                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2329                 assert(sector->getId() == MAPSECTOR_SERVER);
2330                 
2331                 if(ENABLE_SECTOR_SAVING)
2332                 {
2333                         if(sector->differs_from_disk || only_changed == false)
2334                         {
2335                                 saveSectorMeta(sector);
2336                                 sector_meta_count++;
2337                         }
2338                 }
2339                 if(ENABLE_BLOCK_SAVING)
2340                 {
2341                         core::list<MapBlock*> blocks;
2342                         sector->getBlocks(blocks);
2343                         core::list<MapBlock*>::Iterator j;
2344                         for(j=blocks.begin(); j!=blocks.end(); j++)
2345                         {
2346                                 MapBlock *block = *j;
2347                                 if(block->getChangedFlag() || only_changed == false)
2348                                 {
2349                                         saveBlock(block);
2350                                         block_count++;
2351                                 }
2352                         }
2353                 }
2354         }
2355
2356         }//sectorlock
2357         
2358         u32 deleted_count = 0;
2359         deleted_count = deleteUnusedSectors
2360                         (SERVERMAP_DELETE_UNUSED_SECTORS_TIMEOUT);
2361         
2362         /*
2363                 Only print if something happened or saved whole map
2364         */
2365         if(only_changed == false || sector_meta_count != 0
2366                         || block_count != 0 || deleted_count != 0)
2367         {
2368                 dstream<<DTIME<<"ServerMap: Written: "
2369                                 <<sector_meta_count<<" sector metadata files, "
2370                                 <<block_count<<" block files, "
2371                                 <<deleted_count<<" sectors unloaded from memory."
2372                                 <<std::endl;
2373         }
2374 }
2375
2376 void ServerMap::loadAll()
2377 {
2378         DSTACK(__FUNCTION_NAME);
2379         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
2380
2381         loadMasterHeightmap();
2382
2383         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
2384
2385         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
2386         
2387         JMutexAutoLock lock(m_sector_mutex);
2388         
2389         s32 counter = 0;
2390         s32 printed_counter = -100000;
2391         s32 count = list.size();
2392
2393         std::vector<fs::DirListNode>::iterator i;
2394         for(i=list.begin(); i!=list.end(); i++)
2395         {
2396                 if(counter > printed_counter + 10)
2397                 {
2398                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
2399                         printed_counter = counter;
2400                 }
2401                 counter++;
2402
2403                 MapSector *sector = NULL;
2404
2405                 // We want directories
2406                 if(i->dir == false)
2407                         continue;
2408                 try{
2409                         sector = loadSectorMeta(i->name);
2410                 }
2411                 catch(InvalidFilenameException &e)
2412                 {
2413                         // This catches unknown crap in directory
2414                 }
2415                 
2416                 if(ENABLE_BLOCK_LOADING)
2417                 {
2418                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2419                                         (m_savedir+"/sectors/"+i->name);
2420                         std::vector<fs::DirListNode>::iterator i2;
2421                         for(i2=list2.begin(); i2!=list2.end(); i2++)
2422                         {
2423                                 // We want files
2424                                 if(i2->dir)
2425                                         continue;
2426                                 try{
2427                                         loadBlock(i->name, i2->name, sector);
2428                                 }
2429                                 catch(InvalidFilenameException &e)
2430                                 {
2431                                         // This catches unknown crap in directory
2432                                 }
2433                         }
2434                 }
2435         }
2436         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
2437 }
2438
2439 void ServerMap::saveMasterHeightmap()
2440 {
2441         DSTACK(__FUNCTION_NAME);
2442         createDir(m_savedir);
2443         
2444         std::string fullpath = m_savedir + "/master_heightmap";
2445         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2446         if(o.good() == false)
2447                 throw FileNotGoodException("Cannot open master heightmap");
2448         
2449         // Format used for writing
2450         u8 version = SER_FMT_VER_HIGHEST;
2451
2452 #if 0
2453         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
2454         /*
2455                 [0] u8 serialization version
2456                 [1] X master heightmap
2457         */
2458         u32 fullsize = 1 + hmdata.getSize();
2459         SharedBuffer<u8> data(fullsize);
2460
2461         data[0] = version;
2462         memcpy(&data[1], *hmdata, hmdata.getSize());
2463
2464         o.write((const char*)*data, fullsize);
2465 #endif
2466         
2467         m_heightmap->serialize(o, version);
2468 }
2469
2470 void ServerMap::loadMasterHeightmap()
2471 {
2472         DSTACK(__FUNCTION_NAME);
2473         std::string fullpath = m_savedir + "/master_heightmap";
2474         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2475         if(is.good() == false)
2476                 throw FileNotGoodException("Cannot open master heightmap");
2477         
2478         if(m_heightmap != NULL)
2479                 delete m_heightmap;
2480                 
2481         m_heightmap = UnlimitedHeightmap::deSerialize(is);
2482 }
2483
2484 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2485 {
2486         DSTACK(__FUNCTION_NAME);
2487         // Format used for writing
2488         u8 version = SER_FMT_VER_HIGHEST;
2489         // Get destination
2490         v2s16 pos = sector->getPos();
2491         createDir(m_savedir);
2492         createDir(m_savedir+"/sectors");
2493         std::string dir = getSectorDir(pos);
2494         createDir(dir);
2495         
2496         std::string fullpath = dir + "/heightmap";
2497         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2498         if(o.good() == false)
2499                 throw FileNotGoodException("Cannot open master heightmap");
2500
2501         sector->serialize(o, version);
2502         
2503         sector->differs_from_disk = false;
2504 }
2505
2506 MapSector* ServerMap::loadSectorMeta(std::string dirname)
2507 {
2508         DSTACK(__FUNCTION_NAME);
2509         // Get destination
2510         v2s16 p2d = getSectorPos(dirname);
2511         std::string dir = m_savedir + "/sectors/" + dirname;
2512         
2513         std::string fullpath = dir + "/heightmap";
2514         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2515         if(is.good() == false)
2516                 throw FileNotGoodException("Cannot open sector heightmap");
2517
2518         ServerMapSector *sector = ServerMapSector::deSerialize
2519                         (is, this, p2d, &m_hwrapper, m_sectors);
2520         
2521         sector->differs_from_disk = false;
2522
2523         return sector;
2524 }
2525
2526 bool ServerMap::loadSectorFull(v2s16 p2d)
2527 {
2528         DSTACK(__FUNCTION_NAME);
2529         std::string sectorsubdir = getSectorSubDir(p2d);
2530
2531         MapSector *sector = NULL;
2532
2533         JMutexAutoLock lock(m_sector_mutex);
2534
2535         try{
2536                 sector = loadSectorMeta(sectorsubdir);
2537         }
2538         catch(InvalidFilenameException &e)
2539         {
2540                 return false;
2541         }
2542         catch(FileNotGoodException &e)
2543         {
2544                 return false;
2545         }
2546         catch(std::exception &e)
2547         {
2548                 return false;
2549         }
2550
2551         if(ENABLE_BLOCK_LOADING)
2552         {
2553                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
2554                                 (m_savedir+"/sectors/"+sectorsubdir);
2555                 std::vector<fs::DirListNode>::iterator i2;
2556                 for(i2=list2.begin(); i2!=list2.end(); i2++)
2557                 {
2558                         // We want files
2559                         if(i2->dir)
2560                                 continue;
2561                         try{
2562                                 loadBlock(sectorsubdir, i2->name, sector);
2563                         }
2564                         catch(InvalidFilenameException &e)
2565                         {
2566                                 // This catches unknown crap in directory
2567                         }
2568                 }
2569         }
2570         return true;
2571 }
2572
2573 #if 0
2574 bool ServerMap::deFlushSector(v2s16 p2d)
2575 {
2576         DSTACK(__FUNCTION_NAME);
2577         // See if it already exists in memory
2578         try{
2579                 MapSector *sector = getSectorNoGenerate(p2d);
2580                 return true;
2581         }
2582         catch(InvalidPositionException &e)
2583         {
2584                 /*
2585                         Try to load the sector from disk.
2586                 */
2587                 if(loadSectorFull(p2d) == true)
2588                 {
2589                         return true;
2590                 }
2591         }
2592         return false;
2593 }
2594 #endif
2595
2596 void ServerMap::saveBlock(MapBlock *block)
2597 {
2598         DSTACK(__FUNCTION_NAME);
2599         /*
2600                 Dummy blocks are not written
2601         */
2602         if(block->isDummy())
2603         {
2604                 /*v3s16 p = block->getPos();
2605                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
2606                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2607                 return;
2608         }
2609
2610         // Format used for writing
2611         u8 version = SER_FMT_VER_HIGHEST;
2612         // Get destination
2613         v3s16 p3d = block->getPos();
2614         v2s16 p2d(p3d.X, p3d.Z);
2615         createDir(m_savedir);
2616         createDir(m_savedir+"/sectors");
2617         std::string dir = getSectorDir(p2d);
2618         createDir(dir);
2619         
2620         // Block file is map/sectors/xxxxxxxx/xxxx
2621         char cc[5];
2622         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
2623         std::string fullpath = dir + "/" + cc;
2624         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2625         if(o.good() == false)
2626                 throw FileNotGoodException("Cannot open block data");
2627
2628         /*
2629                 [0] u8 serialization version
2630                 [1] data
2631         */
2632         o.write((char*)&version, 1);
2633         
2634         block->serialize(o, version);
2635
2636         /*
2637                 Versions up from 9 have block objects.
2638         */
2639         if(version >= 9)
2640         {
2641                 block->serializeObjects(o, version);
2642         }
2643         
2644         // We just wrote it to the disk
2645         block->resetChangedFlag();
2646 }
2647
2648 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
2649 {
2650         DSTACK(__FUNCTION_NAME);
2651
2652         try{
2653
2654         // Block file is map/sectors/xxxxxxxx/xxxx
2655         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
2656         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2657         if(is.good() == false)
2658                 throw FileNotGoodException("Cannot open block file");
2659
2660         v3s16 p3d = getBlockPos(sectordir, blockfile);
2661         v2s16 p2d(p3d.X, p3d.Z);
2662         
2663         assert(sector->getPos() == p2d);
2664         
2665         u8 version = SER_FMT_VER_INVALID;
2666         is.read((char*)&version, 1);
2667
2668         /*u32 block_size = MapBlock::serializedLength(version);
2669         SharedBuffer<u8> data(block_size);
2670         is.read((char*)*data, block_size);*/
2671
2672         // This will always return a sector because we're the server
2673         //MapSector *sector = emergeSector(p2d);
2674
2675         MapBlock *block = NULL;
2676         bool created_new = false;
2677         try{
2678                 block = sector->getBlockNoCreate(p3d.Y);
2679         }
2680         catch(InvalidPositionException &e)
2681         {
2682                 block = sector->createBlankBlockNoInsert(p3d.Y);
2683                 created_new = true;
2684         }
2685         
2686         // deserialize block data
2687         block->deSerialize(is, version);
2688         
2689         /*
2690                 Versions up from 9 have block objects.
2691         */
2692         if(version >= 9)
2693         {
2694                 block->updateObjects(is, version, NULL);
2695         }
2696
2697         if(created_new)
2698                 sector->insertBlock(block);
2699         
2700         /*
2701                 Convert old formats to new and save
2702         */
2703
2704         // Save old format blocks in new format
2705         if(version < SER_FMT_VER_HIGHEST)
2706         {
2707                 saveBlock(block);
2708         }
2709         
2710         // We just loaded it from the disk, so it's up-to-date.
2711         block->resetChangedFlag();
2712
2713         }
2714         catch(SerializationError &e)
2715         {
2716                 dstream<<"WARNING: Invalid block data on disk "
2717                                 "(SerializationError). Ignoring."
2718                                 <<std::endl;
2719         }
2720 }
2721
2722 // Gets from master heightmap
2723 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
2724 {
2725         assert(m_heightmap != NULL);
2726         /*
2727                 Corner definition:
2728                 v2s16(0,0),
2729                 v2s16(1,0),
2730                 v2s16(1,1),
2731                 v2s16(0,1),
2732         */
2733         corners[0] = m_heightmap->getGroundHeight
2734                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
2735         corners[1] = m_heightmap->getGroundHeight
2736                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
2737         corners[2] = m_heightmap->getGroundHeight
2738                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
2739         corners[3] = m_heightmap->getGroundHeight
2740                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
2741 }
2742
2743 void ServerMap::PrintInfo(std::ostream &out)
2744 {
2745         out<<"ServerMap: ";
2746 }
2747
2748 /*
2749         ClientMap
2750 */
2751
2752 ClientMap::ClientMap(
2753                 Client *client,
2754                 video::SMaterial *materials,
2755                 scene::ISceneNode* parent,
2756                 scene::ISceneManager* mgr,
2757                 s32 id
2758 ):
2759         Map(dout_client),
2760         scene::ISceneNode(parent, mgr, id),
2761         m_client(client),
2762         m_materials(materials),
2763         mesh(NULL)
2764 {
2765         /*m_box = core::aabbox3d<f32>(0,0,0,
2766                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
2767         /*m_box = core::aabbox3d<f32>(0,0,0,
2768                         map->getSizeNodes().X * BS,
2769                         map->getSizeNodes().Y * BS,
2770                         map->getSizeNodes().Z * BS);*/
2771         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
2772                         BS*1000000,BS*1000000,BS*1000000);
2773
2774         mesh_mutex.Init();
2775 }
2776
2777 ClientMap::~ClientMap()
2778 {
2779         JMutexAutoLock lock(mesh_mutex);
2780         
2781         if(mesh != NULL)
2782         {
2783                 mesh->drop();
2784                 mesh = NULL;
2785         }
2786 }
2787
2788 MapSector * ClientMap::emergeSector(v2s16 p2d)
2789 {
2790         DSTACK(__FUNCTION_NAME);
2791         // Check that it doesn't exist already
2792         try{
2793                 return getSectorNoGenerate(p2d);
2794         }
2795         catch(InvalidPositionException &e)
2796         {
2797         }
2798         
2799         // Create a sector with no heightmaps
2800         ClientMapSector *sector = new ClientMapSector(this, p2d);
2801         
2802         {
2803                 JMutexAutoLock lock(m_sector_mutex);
2804                 m_sectors.insert(p2d, sector);
2805         }
2806         
2807         return sector;
2808 }
2809
2810 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
2811 {
2812         DSTACK(__FUNCTION_NAME);
2813         ClientMapSector *sector = NULL;
2814
2815         JMutexAutoLock lock(m_sector_mutex);
2816         
2817         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
2818
2819         if(n != NULL)
2820         {
2821                 sector = (ClientMapSector*)n->getValue();
2822                 assert(sector->getId() == MAPSECTOR_CLIENT);
2823         }
2824         else
2825         {
2826                 sector = new ClientMapSector(this, p2d);
2827                 {
2828                         JMutexAutoLock lock(m_sector_mutex);
2829                         m_sectors.insert(p2d, sector);
2830                 }
2831         }
2832
2833         sector->deSerialize(is);
2834 }
2835
2836 void ClientMap::renderMap(video::IVideoDriver* driver,
2837         video::SMaterial *materials, s32 pass)
2838 {
2839         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
2840         DSTACK(__FUNCTION_NAME);
2841
2842         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
2843
2844         /*
2845                 Get time for measuring timeout.
2846                 
2847                 Measuring time is very useful for long delays when the
2848                 machine is swapping a lot.
2849         */
2850         int time1 = time(0);
2851
2852         /*
2853                 Collect all blocks that are in the view range
2854
2855                 Should not optimize more here as we want to auto-update
2856                 all changed nodes in viewing range at the next step.
2857         */
2858
2859         s16 viewing_range_nodes;
2860         bool viewing_range_all;
2861         {
2862                 JMutexAutoLock lock(g_range_mutex);
2863                 viewing_range_nodes = g_viewing_range_nodes;
2864                 viewing_range_all = g_viewing_range_all;
2865         }
2866
2867         m_camera_mutex.Lock();
2868         v3f camera_position = m_camera_position;
2869         v3f camera_direction = m_camera_direction;
2870         m_camera_mutex.Unlock();
2871
2872         /*
2873                 Get all blocks and draw all visible ones
2874         */
2875
2876         v3s16 cam_pos_nodes(
2877                         camera_position.X / BS,
2878                         camera_position.Y / BS,
2879                         camera_position.Z / BS);
2880
2881         v3s16 box_nodes_d = viewing_range_nodes * v3s16(1,1,1);
2882
2883         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2884         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2885
2886         // Take a fair amount as we will be dropping more out later
2887         v3s16 p_blocks_min(
2888                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2889                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2890                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2891         v3s16 p_blocks_max(
2892                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2893                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2894                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2895         
2896         u32 vertex_count = 0;
2897         
2898         core::map<v2s16, MapSector*>::Iterator si;
2899
2900         //NOTE: The sectors map should be locked but we're not doing it
2901         // because it'd cause too much delays
2902
2903         si = m_sectors.getIterator();
2904         for(; si.atEnd() == false; si++)
2905         {
2906                 {
2907                         static int timecheck_counter = 0;
2908                         timecheck_counter++;
2909                         if(timecheck_counter > 50)
2910                         {
2911                                 int time2 = time(0);
2912                                 if(time2 > time1 + 4)
2913                                 {
2914                                         dstream<<"ClientMap::renderMap(): "
2915                                                 "Rendering takes ages, returning."
2916                                                 <<std::endl;
2917                                         return;
2918                                 }
2919                         }
2920                 }
2921
2922                 MapSector *sector = si.getNode()->getValue();
2923                 v2s16 sp = sector->getPos();
2924                 
2925                 if(viewing_range_all == false)
2926                 {
2927                         if(sp.X < p_blocks_min.X
2928                         || sp.X > p_blocks_max.X
2929                         || sp.Y < p_blocks_min.Z
2930                         || sp.Y > p_blocks_max.Z)
2931                                 continue;
2932                 }
2933
2934                 core::list< MapBlock * > sectorblocks;
2935                 sector->getBlocks(sectorblocks);
2936                 
2937                 /*
2938                         Draw blocks
2939                 */
2940
2941                 core::list< MapBlock * >::Iterator i;
2942                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
2943                 {
2944                         MapBlock *block = *i;
2945
2946                         /*
2947                                 Compare block position to camera position, skip
2948                                 if not seen on display
2949                         */
2950                         
2951                         v3s16 blockpos_nodes = block->getPosRelative();
2952                         
2953                         // Block center position
2954                         v3f blockpos(
2955                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
2956                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
2957                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
2958                         );
2959
2960                         // Block position relative to camera
2961                         v3f blockpos_relative = blockpos - camera_position;
2962
2963                         // Distance in camera direction (+=front, -=back)
2964                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
2965
2966                         // Total distance
2967                         f32 d = blockpos_relative.getLength();
2968                         
2969                         if(viewing_range_all == false)
2970                         {
2971                                 // If block is far away, don't draw it
2972                                 if(d > viewing_range_nodes * BS)
2973                                         continue;
2974                         }
2975                         
2976                         // Maximum radius of a block
2977                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
2978                         
2979                         // If block is (nearly) touching the camera, don't
2980                         // bother validating further (that is, render it anyway)
2981                         if(d > block_max_radius * 1.5)
2982                         {
2983                                 // Cosine of the angle between the camera direction
2984                                 // and the block direction (camera_direction is an unit vector)
2985                                 f32 cosangle = dforward / d;
2986                                 
2987                                 // Compensate for the size of the block
2988                                 // (as the block has to be shown even if it's a bit off FOV)
2989                                 // This is an estimate.
2990                                 cosangle += block_max_radius / dforward;
2991
2992                                 // If block is not in the field of view, skip it
2993                                 //if(cosangle < cos(FOV_ANGLE/2))
2994                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
2995                                         continue;
2996                         }
2997                         
2998                         /*
2999                                 Draw the faces of the block
3000                         */
3001                         
3002                         {
3003                                 JMutexAutoLock lock(block->mesh_mutex);
3004
3005                                 // Cancel if block has no mesh
3006                                 if(block->mesh == NULL)
3007                                         continue;
3008
3009                                 u32 c = block->mesh->getMeshBufferCount();
3010
3011                                 for(u32 i=0; i<c; i++)
3012                                 {
3013                                         scene::IMeshBuffer *buf = block->mesh->getMeshBuffer(i);
3014                                         const video::SMaterial& material = buf->getMaterial();
3015                                         video::IMaterialRenderer* rnd =
3016                                                         driver->getMaterialRenderer(material.MaterialType);
3017                                         bool transparent = (rnd && rnd->isTransparent());
3018                                         // Render transparent on transparent pass and likewise.
3019                                         if(transparent == is_transparent_pass)
3020                                         {
3021                                                 driver->setMaterial(buf->getMaterial());
3022                                                 driver->drawMeshBuffer(buf);
3023                                                 vertex_count += buf->getVertexCount();
3024                                         }
3025                                 }
3026                         }
3027                 } // foreach sectorblocks
3028         }
3029
3030         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3031                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3032 }
3033
3034 void ClientMap::updateMesh()
3035 {
3036 #if 0
3037         DSTACK(__FUNCTION_NAME);
3038         //TODO
3039         /*
3040                 Check what sectors don't draw anything useful at ground level
3041                 and create a mesh of the rough heightmap at those positions.
3042         */
3043
3044         m_camera_mutex.Lock();
3045         v3f camera_position = m_camera_position;
3046         v3f camera_direction = m_camera_direction;
3047         m_camera_mutex.Unlock();
3048
3049         v3s16 cam_pos_nodes(
3050                         camera_position.X / BS,
3051                         camera_position.Y / BS,
3052                         camera_position.Z / BS);
3053
3054         v3s16 box_nodes_d = HEIGHTMAP_RANGE_NODES * v3s16(1,1,1);
3055
3056         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3057         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3058
3059         // Take a fair amount as we will be dropping more out later
3060         v3s16 p_blocks_min(
3061                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
3062                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
3063                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
3064         v3s16 p_blocks_max(
3065                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3066                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3067                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3068         
3069         /*
3070                 Initialize new mesh
3071         */
3072         
3073         scene::SMesh *mesh_new = new scene::SMesh();
3074         //scene::IMeshBuffer *buf = NULL;
3075         scene::SMeshBuffer *buf = NULL;
3076
3077         u8 material_in_use = 0;
3078
3079         /*
3080                 Loop through sectors
3081         */
3082         
3083         for(core::map<v2s16, MapSector*>::Iterator
3084                         si = m_sectors.getIterator();
3085                         si.atEnd() == false; si++)
3086         {
3087                 MapSector *sector = si.getNode()->getValue();
3088                 
3089                 if(sector->getId() != MAPSECTOR_CLIENT)
3090                 {
3091                         dstream<<"WARNING: Client has a non-client sector"
3092                                         <<std::endl;
3093                         continue;
3094                 }
3095                 
3096                 ClientMapSector *cs = (ClientMapSector*)sector;
3097
3098                 v2s16 sp = sector->getPos();
3099
3100                 if(sp.X < p_blocks_min.X
3101                 || sp.X > p_blocks_max.X
3102                 || sp.Y < p_blocks_min.Z
3103                 || sp.Y > p_blocks_max.Z)
3104                         continue;
3105                 
3106                 /*
3107                         Get some ground level info
3108                 */
3109                 
3110                 s16 a = -5;
3111
3112                 s16 cn[4] = 
3113                 {
3114                         cs->getCorner(0)+a,
3115                         cs->getCorner(1)+a,
3116                         cs->getCorner(2)+a,
3117                         cs->getCorner(3)+a,
3118                 };
3119                 s16 cn_avg = (cn[0]+cn[1]+cn[2]+cn[3])/4;
3120                 s16 cn_min = 32767;
3121                 s16 cn_max = -32768;
3122                 for(s16 i=0; i<4; i++)
3123                 {
3124                         if(cn[i] < cn_min)
3125                                 cn_min = cn[i];
3126                         if(cn[i] > cn_max)
3127                                 cn_max = cn[i];
3128                 }
3129                 s16 cn_slope = cn_max - cn_min;
3130                 
3131                 /*
3132                         Generate this part of the heightmap mesh
3133                 */
3134
3135                 u8 material;
3136                 if(cn_avg + MAP_BLOCKSIZE/4 <= WATER_LEVEL)
3137                         material = 0;
3138                 else if(cn_slope <= MAP_BLOCKSIZE)
3139                         material = 1;
3140                 else
3141                         material = 2;
3142
3143                 if(material != material_in_use || buf == NULL)
3144                 {
3145                         // Try to get a meshbuffer associated with the material
3146                         buf = (scene::SMeshBuffer*)mesh_new->getMeshBuffer
3147                                         (g_mesh_materials[material]);
3148                         // If not found, create one
3149                         if(buf == NULL)
3150                         {
3151                                 // This is a "Standard MeshBuffer",
3152                                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
3153                                 buf = new scene::SMeshBuffer();
3154
3155                                 // Set material
3156                                 buf->Material = g_mesh_materials[material];
3157                                 // Use VBO
3158                                 //buf->setHardwareMappingHint(scene::EHM_STATIC);
3159                                 // Add to mesh
3160                                 mesh_new->addMeshBuffer(buf);
3161                                 // Mesh grabbed it
3162                                 buf->drop();
3163                         }
3164                         material_in_use = material;
3165                 }
3166
3167                 // Sector side width in floating-point units
3168                 f32 sd = BS * MAP_BLOCKSIZE;
3169                 // Sector position in global floating-point units
3170                 v3f spf = v3f((f32)sp.X, 0, (f32)sp.Y) * sd;
3171
3172                 //video::SColor c(255,255,255,255);
3173                 u8 cc = 180;
3174                 video::SColor c(255,cc,cc,cc);
3175                 
3176                 video::S3DVertex vertices[4] =
3177                 {
3178                         video::S3DVertex(spf.X,   (f32)BS*cn[0],spf.Z,   0,0,0, c, 0,1),
3179                         video::S3DVertex(spf.X+sd,(f32)BS*cn[1],spf.Z,   0,0,0, c, 1,1),
3180                         video::S3DVertex(spf.X+sd,(f32)BS*cn[2],spf.Z+sd,0,0,0, c, 1,0),
3181                         video::S3DVertex(spf.X,   (f32)BS*cn[3],spf.Z+sd,0,0,0, c, 0,0),
3182                 };
3183                 u16 indices[] = {0,1,2,2,3,0};
3184                 
3185                 buf->append(vertices, 4, indices, 6);
3186         }
3187         
3188         // Set VBO on
3189         //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
3190
3191         /*
3192                 Replace the mesh
3193         */
3194
3195         mesh_mutex.Lock();
3196
3197         scene::SMesh *mesh_old = mesh;
3198
3199         //DEBUG
3200         /*mesh = NULL;
3201         mesh_new->drop();*/
3202         mesh = mesh_new;
3203         
3204         mesh_mutex.Unlock();
3205
3206         if(mesh_old != NULL)
3207         {
3208                 /*dstream<<"mesh_old refcount="<<mesh_old->getReferenceCount()
3209                                 <<std::endl;
3210                 scene::IMeshBuffer *buf = mesh_new->getMeshBuffer
3211                                 (g_materials[CONTENT_GRASS]);
3212                 if(buf != NULL)
3213                         dstream<<"grass buf refcount="<<buf->getReferenceCount()
3214                                         <<std::endl;*/
3215
3216                 mesh_old->drop();
3217         }
3218         else
3219         {
3220                 dstream<<"WARNING: There was no old master heightmap mesh"<<std::endl;
3221         }
3222 #endif
3223 }
3224
3225 void ClientMap::PrintInfo(std::ostream &out)
3226 {
3227         out<<"ClientMap: ";
3228 }
3229
3230
3231 /*
3232         MapVoxelManipulator
3233 */
3234
3235 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3236 {
3237         m_map = map;
3238 }
3239
3240 MapVoxelManipulator::~MapVoxelManipulator()
3241 {
3242         dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3243                         <<std::endl;
3244 }
3245
3246 #if 1
3247 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3248 {
3249         TimeTaker timer1("emerge", g_device, &emerge_time);
3250
3251         // Units of these are MapBlocks
3252         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3253         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3254
3255         VoxelArea block_area_nodes
3256                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3257
3258         addArea(block_area_nodes);
3259
3260         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3261         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3262         for(s32 x=p_min.X; x<=p_max.X; x++)
3263         {
3264                 v3s16 p(x,y,z);
3265                 core::map<v3s16, bool>::Node *n;
3266                 n = m_loaded_blocks.find(p);
3267                 if(n != NULL)
3268                         continue;
3269                 
3270                 bool block_data_inexistent = false;
3271                 try
3272                 {
3273                         TimeTaker timer1("emerge load", g_device, &emerge_load_time);
3274
3275                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3276                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3277                                         <<" wanted area: ";
3278                         a.print(dstream);
3279                         dstream<<std::endl;*/
3280                         
3281                         MapBlock *block = m_map->getBlockNoCreate(p);
3282                         if(block->isDummy())
3283                                 block_data_inexistent = true;
3284                         else
3285                                 block->copyTo(*this);
3286                 }
3287                 catch(InvalidPositionException &e)
3288                 {
3289                         block_data_inexistent = true;
3290                 }
3291
3292                 if(block_data_inexistent)
3293                 {
3294                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3295                         // Fill with VOXELFLAG_INEXISTENT
3296                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3297                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3298                         {
3299                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3300                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3301                         }
3302                 }
3303
3304                 m_loaded_blocks.insert(p, true);
3305         }
3306
3307         //dstream<<"emerge done"<<std::endl;
3308 }
3309 #endif
3310
3311 #if 0
3312 void MapVoxelManipulator::emerge(VoxelArea a)
3313 {
3314         TimeTaker timer1("emerge", g_device, &emerge_time);
3315         
3316         v3s16 size = a.getExtent();
3317         
3318         VoxelArea padded = a;
3319         padded.pad(m_area.getExtent() / 4);
3320         addArea(padded);
3321
3322         for(s16 z=0; z<size.Z; z++)
3323         for(s16 y=0; y<size.Y; y++)
3324         for(s16 x=0; x<size.X; x++)
3325         {
3326                 v3s16 p(x,y,z);
3327                 s32 i = m_area.index(a.MinEdge + p);
3328                 // Don't touch nodes that have already been loaded
3329                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
3330                         continue;
3331                 try
3332                 {
3333                         TimeTaker timer1("emerge load", g_device, &emerge_load_time);
3334                         MapNode n = m_map->getNode(a.MinEdge + p);
3335                         m_data[i] = n;
3336                         m_flags[i] = 0;
3337                 }
3338                 catch(InvalidPositionException &e)
3339                 {
3340                         m_flags[i] = VOXELFLAG_INEXISTENT;
3341                 }
3342         }
3343 }
3344 #endif
3345
3346
3347 /*
3348         TODO: Add an option to only update eg. water and air nodes.
3349               This will make it interfere less with important stuff if
3350                   run on background.
3351 */
3352 void MapVoxelManipulator::blitBack
3353                 (core::map<v3s16, MapBlock*> & modified_blocks)
3354 {
3355         if(m_area.getExtent() == v3s16(0,0,0))
3356                 return;
3357         
3358         TimeTaker timer1("blitBack", g_device);
3359         
3360         /*
3361                 Initialize block cache
3362         */
3363         v3s16 blockpos_last;
3364         MapBlock *block = NULL;
3365         bool block_checked_in_modified = false;
3366
3367         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3368         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3369         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3370         {
3371                 v3s16 p(x,y,z);
3372
3373                 u8 f = m_flags[m_area.index(p)];
3374                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3375                         continue;
3376
3377                 MapNode &n = m_data[m_area.index(p)];
3378                         
3379                 v3s16 blockpos = getNodeBlockPos(p);
3380                 
3381                 try
3382                 {
3383                         // Get block
3384                         if(block == NULL || blockpos != blockpos_last){
3385                                 block = m_map->getBlockNoCreate(blockpos);
3386                                 blockpos_last = blockpos;
3387                                 block_checked_in_modified = false;
3388                         }
3389                         
3390                         // Calculate relative position in block
3391                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3392
3393                         // Don't continue if nothing has changed here
3394                         if(block->getNode(relpos) == n)
3395                                 continue;
3396
3397                         //m_map->setNode(m_area.MinEdge + p, n);
3398                         block->setNode(relpos, n);
3399                         
3400                         /*
3401                                 Make sure block is in modified_blocks
3402                         */
3403                         if(block_checked_in_modified == false)
3404                         {
3405                                 modified_blocks[blockpos] = block;
3406                                 block_checked_in_modified = true;
3407                         }
3408                 }
3409                 catch(InvalidPositionException &e)
3410                 {
3411                 }
3412         }
3413 }
3414
3415 //END