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