]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
fixed face updating slowness bug
[dragonfireclient.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 * 2 * 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         {
1524                 if(rand()%(s32)(10.0 * m_params.ravines_amount) == 0)
1525                 {
1526                         s16 s = 6;
1527                         s16 x = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
1528                         s16 z = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
1529                         /*s16 x = 8;
1530                         s16 z = 8;*/
1531                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1532                         objects->insert(v3s16(x, y, z),
1533                                         SECTOR_OBJECT_RAVINE);
1534                 }
1535         }
1536
1537         /*
1538                 Insert to container
1539         */
1540         JMutexAutoLock lock(m_sector_mutex);
1541         m_sectors.insert(p2d, sector);
1542         
1543         return sector;
1544 }
1545
1546 MapBlock * ServerMap::emergeBlock(
1547                 v3s16 p,
1548                 bool only_from_disk,
1549                 core::map<v3s16, MapBlock*> &changed_blocks,
1550                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
1551 )
1552 {
1553         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
1554                         __FUNCTION_NAME,
1555                         p.X, p.Y, p.Z, only_from_disk);
1556                         
1557         /*dstream<<"ServerMap::emergeBlock(): "
1558                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1559                         <<", only_from_disk="<<only_from_disk<<std::endl;*/
1560         v2s16 p2d(p.X, p.Z);
1561         s16 block_y = p.Y;
1562         /*
1563                 This will create or load a sector if not found in memory.
1564                 If block exists on disk, it will be loaded.
1565
1566                 NOTE: On old save formats, this will be slow, as it generates
1567                       lighting on blocks for them.
1568         */
1569         ServerMapSector *sector = (ServerMapSector*)emergeSector(p2d);
1570         assert(sector->getId() == MAPSECTOR_SERVER);
1571
1572         // Try to get a block from the sector
1573         MapBlock *block = NULL;
1574         bool not_on_disk = false;
1575         try{
1576                 block = sector->getBlockNoCreate(block_y);
1577                 if(block->isDummy() == true)
1578                         not_on_disk = true;
1579                 else
1580                         return block;
1581         }
1582         catch(InvalidPositionException &e)
1583         {
1584                 not_on_disk = true;
1585         }
1586         
1587         /*
1588                 If block was not found on disk and not going to generate a
1589                 new one, make sure there is a dummy block in place.
1590         */
1591         if(not_on_disk && only_from_disk)
1592         {
1593                 if(block == NULL)
1594                 {
1595                         // Create dummy block
1596                         block = new MapBlock(this, p, true);
1597
1598                         // Add block to sector
1599                         sector->insertBlock(block);
1600                 }
1601                 // Done.
1602                 return block;
1603         }
1604
1605         //dstream<<"Not found on disk, generating."<<std::endl;
1606
1607         /*
1608                 Do not generate over-limit
1609         */
1610         if(blockpos_over_limit(p))
1611                 throw InvalidPositionException("emergeBlock(): pos. over limit");
1612
1613         /*
1614                 OK; Not found.
1615
1616                 Go on generating the block.
1617
1618                 TODO: If a dungeon gets generated so that it's side gets
1619                       revealed to the outside air, the lighting should be
1620                           recalculated.
1621         */
1622         
1623         /*
1624                 If block doesn't exist, create one.
1625                 If it exists, it is a dummy. In that case unDummify() it.
1626         */
1627         if(block == NULL)
1628         {
1629                 block = sector->createBlankBlockNoInsert(block_y);
1630         }
1631         else
1632         {
1633                 // Remove the block so that nobody can get a half-generated one.
1634                 sector->removeBlock(block);
1635                 // Allocate the block to be a proper one.
1636                 block->unDummify();
1637         }
1638
1639         // Randomize a bit. This makes dungeons.
1640         /*bool low_block_is_empty = false;
1641         if(rand() % 4 == 0)
1642                 low_block_is_empty = true;*/
1643         
1644         const s32 ued = 4;
1645         bool underground_emptiness[ued*ued*ued];
1646         for(s32 i=0; i<ued*ued*ued; i++)
1647         {
1648                 underground_emptiness[i] = ((rand() % 4) == 0);
1649         }
1650         
1651         // This is the basic material of what the visible flat ground
1652         // will consist of
1653         u8 material = MATERIAL_GRASS;
1654         
1655         s32 lowest_ground_y = 32767;
1656         
1657         // DEBUG
1658         //sector->printHeightmaps();
1659
1660         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1661         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1662         {
1663                 //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
1664                 float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
1665                 assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
1666                 s16 surface_y = surface_y_f;
1667                 //avg_ground_y += surface_y;
1668                 if(surface_y < lowest_ground_y)
1669                         lowest_ground_y = surface_y;
1670
1671                 s32 surface_depth = 0;
1672                 
1673                 float slope = sector->getSlope(v2s16(x0,z0)).getLength();
1674                 
1675                 float min_slope = 0.45;
1676                 float max_slope = 0.85;
1677                 float min_slope_depth = 5.0;
1678                 float max_slope_depth = 0;
1679                 if(slope < min_slope)
1680                         surface_depth = min_slope_depth;
1681                 else if(slope > max_slope)
1682                         surface_depth = max_slope_depth;
1683                 else
1684                         surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
1685
1686                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1687                 {
1688                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
1689                         MapNode n;
1690                         /*
1691                                 Calculate lighting
1692                                 
1693                                 NOTE: If there are some man-made structures above the
1694                                 newly created block, they won't be taken into account.
1695                         */
1696                         if(real_y > surface_y)
1697                                 n.setLight(LIGHT_SUN);
1698                         /*
1699                                 Calculate material
1700                         */
1701                         // If node is very low
1702                         if(real_y <= surface_y - 7){
1703                                 // Create dungeons
1704                                 if(underground_emptiness[
1705                                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1706                                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1707                                                 +(x0*ued/MAP_BLOCKSIZE)])
1708                                 {
1709                                         n.d = MATERIAL_AIR;
1710                                 }
1711                                 else
1712                                 {
1713                                         n.d = MATERIAL_STONE;
1714                                 }
1715                         }
1716                         // If node is under surface level
1717                         else if(real_y <= surface_y - surface_depth)
1718                                 n.d = MATERIAL_STONE;
1719                         // If node is at or under heightmap y
1720                         else if(real_y <= surface_y)
1721                         {
1722                                 // If under water level, it's mud
1723                                 if(real_y < WATER_LEVEL)
1724                                         n.d = MATERIAL_MUD;
1725                                 // Else it's the main material
1726                                 else
1727                                         n.d = material;
1728                         }
1729                         // If node is over heightmap y
1730                         else{
1731                                 // If under water level, it's water
1732                                 if(real_y < WATER_LEVEL)
1733                                 {
1734                                         n.d = MATERIAL_WATER;
1735                                         n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
1736                                 }
1737                                 // else air
1738                                 else
1739                                         n.d = MATERIAL_AIR;
1740                         }
1741                         block->setNode(v3s16(x0,y0,z0), n);
1742                 }
1743         }
1744
1745         /*
1746                 Calculate is_underground
1747         */
1748         // Probably underground if the highest part of block is under lowest
1749         // ground height
1750         bool is_underground = (block_y+1) * MAP_BLOCKSIZE < lowest_ground_y;
1751         block->setIsUnderground(is_underground);
1752
1753         /*
1754                 Force lighting update if underground.
1755                 This is needed because of ravines.
1756         */
1757
1758         if(is_underground)
1759         {
1760                 lighting_invalidated_blocks[block->getPos()] = block;
1761         }
1762         
1763         /*
1764                 Add some minerals
1765         */
1766
1767         if(is_underground)
1768         {
1769                 s16 underground_level = lowest_ground_y/MAP_BLOCKSIZE - block_y;
1770                 for(s16 i=0; i<underground_level*3; i++)
1771                 {
1772                         if(rand()%2 == 0)
1773                         {
1774                                 v3s16 cp(
1775                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1776                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1777                                         (rand()%(MAP_BLOCKSIZE-2))+1
1778                                 );
1779
1780                                 MapNode n;
1781                                 n.d = MATERIAL_MESE;
1782                                 
1783                                 if(is_ground_material(block->getNode(cp).d))
1784                                         if(rand()%8 == 0)
1785                                                 block->setNode(cp, n);
1786
1787                                 for(u16 i=0; i<26; i++)
1788                                 {
1789                                         if(is_ground_material(block->getNode(cp+g_26dirs[i]).d))
1790                                                 if(rand()%8 == 0)
1791                                                         block->setNode(cp+g_26dirs[i], n);
1792                                 }
1793                         }
1794                 }
1795         }
1796         
1797         /*
1798                 Create a few rats in empty blocks underground
1799         */
1800         if(is_underground)
1801         {
1802                 //for(u16 i=0; i<2; i++)
1803                 {
1804                         v3s16 cp(
1805                                 (rand()%(MAP_BLOCKSIZE-2))+1,
1806                                 (rand()%(MAP_BLOCKSIZE-2))+1,
1807                                 (rand()%(MAP_BLOCKSIZE-2))+1
1808                         );
1809
1810                         // Check that the place is empty
1811                         //if(!is_ground_material(block->getNode(cp).d))
1812                         if(1)
1813                         {
1814                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
1815                                 block->addObject(obj);
1816                         }
1817                 }
1818         }
1819         
1820         /*
1821                 Add block to sector.
1822         */
1823         sector->insertBlock(block);
1824         
1825         /*
1826                 Do some interpolation for dungeons
1827         */
1828
1829 #if 0   
1830         {
1831         TimeTaker timer("interpolation", g_device);
1832         
1833         MapVoxelManipulator vmanip(this);
1834         
1835         v3s16 relpos = block->getPosRelative();
1836
1837         vmanip.interpolate(VoxelArea(relpos-v3s16(1,1,1),
1838                         relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE+1)));
1839         /*vmanip.interpolate(VoxelArea(relpos,
1840                         relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE-1)));*/
1841         
1842         core::map<v3s16, MapBlock*> modified_blocks;
1843         vmanip.blitBack(modified_blocks);
1844         dstream<<"blitBack modified "<<modified_blocks.size()
1845                         <<" blocks"<<std::endl;
1846
1847         // Add modified blocks to changed_blocks and lighting_invalidated_blocks
1848         for(core::map<v3s16, MapBlock*>::Iterator
1849                         i = modified_blocks.getIterator();
1850                         i.atEnd() == false; i++)
1851         {
1852                 MapBlock *block = i.getNode()->getValue();
1853
1854                 changed_blocks.insert(block->getPos(), block);
1855                 //lighting_invalidated_blocks.insert(block->getPos(), block);
1856         }
1857
1858         }
1859 #endif
1860
1861         /*
1862                 Sector object stuff
1863         */
1864                 
1865         // An y-wise container of changed blocks
1866         core::map<s16, MapBlock*> changed_blocks_sector;
1867
1868         /*
1869                 Check if any sector's objects can be placed now.
1870                 If so, place them.
1871         */
1872         core::map<v3s16, u8> *objects = sector->getObjects();
1873         core::list<v3s16> objects_to_remove;
1874         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
1875                         i.atEnd() == false; i++)
1876         {
1877                 v3s16 p = i.getNode()->getKey();
1878                 v2s16 p2d(p.X,p.Z);
1879                 u8 d = i.getNode()->getValue();
1880
1881                 //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
1882                 
1883                 try
1884                 {
1885
1886                 if(d == SECTOR_OBJECT_TEST)
1887                 {
1888                         if(sector->isValidArea(p + v3s16(0,0,0),
1889                                         p + v3s16(0,0,0), &changed_blocks_sector))
1890                         {
1891                                 MapNode n;
1892                                 n.d = MATERIAL_LIGHT;
1893                                 sector->setNode(p, n);
1894                                 objects_to_remove.push_back(p);
1895                         }
1896                 }
1897                 else if(d == SECTOR_OBJECT_TREE_1)
1898                 {
1899                         v3s16 p_min = p + v3s16(-1,0,-1);
1900                         v3s16 p_max = p + v3s16(1,4,1);
1901                         if(sector->isValidArea(p_min, p_max,
1902                                         &changed_blocks_sector))
1903                         {
1904                                 MapNode n;
1905                                 n.d = MATERIAL_TREE;
1906                                 sector->setNode(p+v3s16(0,0,0), n);
1907                                 sector->setNode(p+v3s16(0,1,0), n);
1908                                 sector->setNode(p+v3s16(0,2,0), n);
1909                                 sector->setNode(p+v3s16(0,3,0), n);
1910
1911                                 n.d = MATERIAL_LEAVES;
1912
1913                                 sector->setNode(p+v3s16(0,4,0), n);
1914                                 
1915                                 sector->setNode(p+v3s16(-1,4,0), n);
1916                                 sector->setNode(p+v3s16(1,4,0), n);
1917                                 sector->setNode(p+v3s16(0,4,-1), n);
1918                                 sector->setNode(p+v3s16(0,4,1), n);
1919                                 sector->setNode(p+v3s16(1,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
1924                                 sector->setNode(p+v3s16(-1,3,0), n);
1925                                 sector->setNode(p+v3s16(1,3,0), n);
1926                                 sector->setNode(p+v3s16(0,3,-1), n);
1927                                 sector->setNode(p+v3s16(0,3,1), n);
1928                                 sector->setNode(p+v3s16(1,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                                 
1933                                 objects_to_remove.push_back(p);
1934                                 
1935                                 // Lighting has to be recalculated for this one.
1936                                 sector->getBlocksInArea(p_min, p_max, 
1937                                                 lighting_invalidated_blocks);
1938                         }
1939                 }
1940                 else if(d == SECTOR_OBJECT_BUSH_1)
1941                 {
1942                         if(sector->isValidArea(p + v3s16(0,0,0),
1943                                         p + v3s16(0,0,0), &changed_blocks_sector))
1944                         {
1945                                 MapNode n;
1946                                 n.d = MATERIAL_LEAVES;
1947                                 sector->setNode(p+v3s16(0,0,0), n);
1948                                 
1949                                 objects_to_remove.push_back(p);
1950                         }
1951                 }
1952                 else if(d == SECTOR_OBJECT_RAVINE)
1953                 {
1954                         s16 maxdepth = -20;
1955                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
1956                         v3s16 p_max = p + v3s16(6,6,6);
1957                         if(sector->isValidArea(p_min, p_max,
1958                                         &changed_blocks_sector))
1959                         {
1960                                 MapNode n;
1961                                 n.d = MATERIAL_STONE;
1962                                 MapNode n2;
1963                                 n2.d = MATERIAL_AIR;
1964                                 s16 depth = maxdepth + (rand()%10);
1965                                 s16 z = 0;
1966                                 s16 minz = -6 - (-2);
1967                                 s16 maxz = 6 -1;
1968                                 for(s16 x=-6; x<=6; x++)
1969                                 {
1970                                         z += -1 + (rand()%3);
1971                                         if(z < minz)
1972                                                 z = minz;
1973                                         if(z > maxz)
1974                                                 z = maxz;
1975                                         for(s16 y=depth+(rand()%2); y<=6; y++)
1976                                         {
1977                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1978                                                                 <<std::endl;*/
1979                                                 {
1980                                                         v3s16 p2 = p + v3s16(x,y,z-2);
1981                                                         if(is_ground_material(sector->getNode(p2).d))
1982                                                                 sector->setNode(p2, n);
1983                                                 }
1984                                                 {
1985                                                         v3s16 p2 = p + v3s16(x,y,z-1);
1986                                                         if(is_ground_material(sector->getNode(p2).d))
1987                                                                 sector->setNode(p2, n2);
1988                                                 }
1989                                                 {
1990                                                         v3s16 p2 = p + v3s16(x,y,z+0);
1991                                                         if(is_ground_material(sector->getNode(p2).d))
1992                                                                 sector->setNode(p2, n2);
1993                                                 }
1994                                                 {
1995                                                         v3s16 p2 = p + v3s16(x,y,z+1);
1996                                                         if(is_ground_material(sector->getNode(p2).d))
1997                                                                 sector->setNode(p2, n);
1998                                                 }
1999
2000                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
2001                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
2002                                         }
2003                                 }
2004                                 
2005                                 objects_to_remove.push_back(p);
2006                                 
2007                                 // Lighting has to be recalculated for this one.
2008                                 sector->getBlocksInArea(p_min, p_max, 
2009                                                 lighting_invalidated_blocks);
2010                         }
2011                 }
2012                 else
2013                 {
2014                         dstream<<"ServerMap::emergeBlock(): "
2015                                         "Invalid heightmap object"
2016                                         <<std::endl;
2017                 }
2018
2019                 }//try
2020                 catch(InvalidPositionException &e)
2021                 {
2022                         dstream<<"WARNING: "<<__FUNCTION_NAME
2023                                         <<": while inserting object "<<(int)d
2024                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
2025                                         <<" InvalidPositionException.what()="
2026                                         <<e.what()<<std::endl;
2027                         // This is not too fatal and seems to happen sometimes.
2028                         assert(0);
2029                 }
2030         }
2031
2032         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
2033                         i != objects_to_remove.end(); i++)
2034         {
2035                 objects->remove(*i);
2036         }
2037
2038         for(core::map<s16, MapBlock*>::Iterator
2039                         i = changed_blocks_sector.getIterator();
2040                         i.atEnd() == false; i++)
2041         {
2042                 MapBlock *block = i.getNode()->getValue();
2043
2044                 changed_blocks.insert(block->getPos(), block);
2045         }
2046
2047         return block;
2048 }
2049
2050 void ServerMap::createDir(std::string path)
2051 {
2052         if(fs::CreateDir(path) == false)
2053         {
2054                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2055                                 <<"\""<<path<<"\""<<std::endl;
2056                 throw BaseException("ServerMap failed to create directory");
2057         }
2058 }
2059
2060 std::string ServerMap::getSectorSubDir(v2s16 pos)
2061 {
2062         char cc[9];
2063         snprintf(cc, 9, "%.4x%.4x",
2064                         (unsigned int)pos.X&0xffff,
2065                         (unsigned int)pos.Y&0xffff);
2066
2067         return std::string(cc);
2068 }
2069
2070 std::string ServerMap::getSectorDir(v2s16 pos)
2071 {
2072         return m_savedir + "/sectors/" + getSectorSubDir(pos);
2073 }
2074
2075 v2s16 ServerMap::getSectorPos(std::string dirname)
2076 {
2077         if(dirname.size() != 8)
2078                 throw InvalidFilenameException("Invalid sector directory name");
2079         unsigned int x, y;
2080         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
2081         if(r != 2)
2082                 throw InvalidFilenameException("Invalid sector directory name");
2083         v2s16 pos((s16)x, (s16)y);
2084         return pos;
2085 }
2086
2087 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2088 {
2089         v2s16 p2d = getSectorPos(sectordir);
2090
2091         if(blockfile.size() != 4){
2092                 throw InvalidFilenameException("Invalid block filename");
2093         }
2094         unsigned int y;
2095         int r = sscanf(blockfile.c_str(), "%4x", &y);
2096         if(r != 1)
2097                 throw InvalidFilenameException("Invalid block filename");
2098         return v3s16(p2d.X, y, p2d.Y);
2099 }
2100
2101 // Debug helpers
2102 #define ENABLE_SECTOR_SAVING 1
2103 #define ENABLE_SECTOR_LOADING 1
2104 #define ENABLE_BLOCK_SAVING 1
2105 #define ENABLE_BLOCK_LOADING 1
2106
2107 void ServerMap::save(bool only_changed)
2108 {
2109         DSTACK(__FUNCTION_NAME);
2110         if(m_map_saving_enabled == false)
2111         {
2112                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2113                 return;
2114         }
2115         
2116         if(only_changed == false)
2117                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2118                                 <<std::endl;
2119         
2120         saveMasterHeightmap();
2121         
2122         u32 sector_meta_count = 0;
2123         u32 block_count = 0;
2124         
2125         { //sectorlock
2126         JMutexAutoLock lock(m_sector_mutex);
2127         
2128         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2129         for(; i.atEnd() == false; i++)
2130         {
2131                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2132                 assert(sector->getId() == MAPSECTOR_SERVER);
2133                 
2134                 if(ENABLE_SECTOR_SAVING)
2135                 {
2136                         if(sector->differs_from_disk || only_changed == false)
2137                         {
2138                                 saveSectorMeta(sector);
2139                                 sector_meta_count++;
2140                         }
2141                 }
2142                 if(ENABLE_BLOCK_SAVING)
2143                 {
2144                         core::list<MapBlock*> blocks;
2145                         sector->getBlocks(blocks);
2146                         core::list<MapBlock*>::Iterator j;
2147                         for(j=blocks.begin(); j!=blocks.end(); j++)
2148                         {
2149                                 MapBlock *block = *j;
2150                                 if(block->getChangedFlag() || only_changed == false)
2151                                 {
2152                                         saveBlock(block);
2153                                         block_count++;
2154                                 }
2155                         }
2156                 }
2157         }
2158
2159         }//sectorlock
2160         
2161         u32 deleted_count = 0;
2162         deleted_count = deleteUnusedSectors
2163                         (SERVERMAP_DELETE_UNUSED_SECTORS_TIMEOUT);
2164         
2165         /*
2166                 Only print if something happened or saved whole map
2167         */
2168         if(only_changed == false || sector_meta_count != 0
2169                         || block_count != 0 || deleted_count != 0)
2170         {
2171                 dstream<<DTIME<<"ServerMap: Written: "
2172                                 <<sector_meta_count<<" sector metadata files, "
2173                                 <<block_count<<" block files, "
2174                                 <<deleted_count<<" sectors unloaded from memory."
2175                                 <<std::endl;
2176         }
2177 }
2178
2179 void ServerMap::loadAll()
2180 {
2181         DSTACK(__FUNCTION_NAME);
2182         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
2183
2184         loadMasterHeightmap();
2185
2186         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
2187
2188         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
2189         
2190         JMutexAutoLock lock(m_sector_mutex);
2191         
2192         s32 counter = 0;
2193         s32 printed_counter = -100000;
2194         s32 count = list.size();
2195
2196         std::vector<fs::DirListNode>::iterator i;
2197         for(i=list.begin(); i!=list.end(); i++)
2198         {
2199                 if(counter > printed_counter + 10)
2200                 {
2201                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
2202                         printed_counter = counter;
2203                 }
2204                 counter++;
2205
2206                 MapSector *sector = NULL;
2207
2208                 // We want directories
2209                 if(i->dir == false)
2210                         continue;
2211                 try{
2212                         sector = loadSectorMeta(i->name);
2213                 }
2214                 catch(InvalidFilenameException &e)
2215                 {
2216                         // This catches unknown crap in directory
2217                 }
2218                 
2219                 if(ENABLE_BLOCK_LOADING)
2220                 {
2221                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2222                                         (m_savedir+"/sectors/"+i->name);
2223                         std::vector<fs::DirListNode>::iterator i2;
2224                         for(i2=list2.begin(); i2!=list2.end(); i2++)
2225                         {
2226                                 // We want files
2227                                 if(i2->dir)
2228                                         continue;
2229                                 try{
2230                                         loadBlock(i->name, i2->name, sector);
2231                                 }
2232                                 catch(InvalidFilenameException &e)
2233                                 {
2234                                         // This catches unknown crap in directory
2235                                 }
2236                         }
2237                 }
2238         }
2239         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
2240 }
2241
2242 void ServerMap::saveMasterHeightmap()
2243 {
2244         DSTACK(__FUNCTION_NAME);
2245         createDir(m_savedir);
2246         
2247         std::string fullpath = m_savedir + "/master_heightmap";
2248         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2249         if(o.good() == false)
2250                 throw FileNotGoodException("Cannot open master heightmap");
2251         
2252         // Format used for writing
2253         u8 version = SER_FMT_VER_HIGHEST;
2254
2255 #if 0
2256         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
2257         /*
2258                 [0] u8 serialization version
2259                 [1] X master heightmap
2260         */
2261         u32 fullsize = 1 + hmdata.getSize();
2262         SharedBuffer<u8> data(fullsize);
2263
2264         data[0] = version;
2265         memcpy(&data[1], *hmdata, hmdata.getSize());
2266
2267         o.write((const char*)*data, fullsize);
2268 #endif
2269         
2270         m_heightmap->serialize(o, version);
2271 }
2272
2273 void ServerMap::loadMasterHeightmap()
2274 {
2275         DSTACK(__FUNCTION_NAME);
2276         std::string fullpath = m_savedir + "/master_heightmap";
2277         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2278         if(is.good() == false)
2279                 throw FileNotGoodException("Cannot open master heightmap");
2280         
2281         if(m_heightmap != NULL)
2282                 delete m_heightmap;
2283                 
2284         m_heightmap = UnlimitedHeightmap::deSerialize(is);
2285 }
2286
2287 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2288 {
2289         DSTACK(__FUNCTION_NAME);
2290         // Format used for writing
2291         u8 version = SER_FMT_VER_HIGHEST;
2292         // Get destination
2293         v2s16 pos = sector->getPos();
2294         createDir(m_savedir);
2295         createDir(m_savedir+"/sectors");
2296         std::string dir = getSectorDir(pos);
2297         createDir(dir);
2298         
2299         std::string fullpath = dir + "/heightmap";
2300         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2301         if(o.good() == false)
2302                 throw FileNotGoodException("Cannot open master heightmap");
2303
2304         sector->serialize(o, version);
2305         
2306         sector->differs_from_disk = false;
2307 }
2308
2309 MapSector* ServerMap::loadSectorMeta(std::string dirname)
2310 {
2311         DSTACK(__FUNCTION_NAME);
2312         // Get destination
2313         v2s16 p2d = getSectorPos(dirname);
2314         std::string dir = m_savedir + "/sectors/" + dirname;
2315         
2316         std::string fullpath = dir + "/heightmap";
2317         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2318         if(is.good() == false)
2319                 throw FileNotGoodException("Cannot open sector heightmap");
2320
2321         ServerMapSector *sector = ServerMapSector::deSerialize
2322                         (is, this, p2d, &m_hwrapper, m_sectors);
2323         
2324         sector->differs_from_disk = false;
2325
2326         return sector;
2327 }
2328
2329 bool ServerMap::loadSectorFull(v2s16 p2d)
2330 {
2331         DSTACK(__FUNCTION_NAME);
2332         std::string sectorsubdir = getSectorSubDir(p2d);
2333
2334         MapSector *sector = NULL;
2335
2336         JMutexAutoLock lock(m_sector_mutex);
2337
2338         try{
2339                 sector = loadSectorMeta(sectorsubdir);
2340         }
2341         catch(InvalidFilenameException &e)
2342         {
2343                 return false;
2344         }
2345         catch(FileNotGoodException &e)
2346         {
2347                 return false;
2348         }
2349         catch(std::exception &e)
2350         {
2351                 return false;
2352         }
2353
2354         if(ENABLE_BLOCK_LOADING)
2355         {
2356                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
2357                                 (m_savedir+"/sectors/"+sectorsubdir);
2358                 std::vector<fs::DirListNode>::iterator i2;
2359                 for(i2=list2.begin(); i2!=list2.end(); i2++)
2360                 {
2361                         // We want files
2362                         if(i2->dir)
2363                                 continue;
2364                         try{
2365                                 loadBlock(sectorsubdir, i2->name, sector);
2366                         }
2367                         catch(InvalidFilenameException &e)
2368                         {
2369                                 // This catches unknown crap in directory
2370                         }
2371                 }
2372         }
2373         return true;
2374 }
2375
2376 #if 0
2377 bool ServerMap::deFlushSector(v2s16 p2d)
2378 {
2379         DSTACK(__FUNCTION_NAME);
2380         // See if it already exists in memory
2381         try{
2382                 MapSector *sector = getSectorNoGenerate(p2d);
2383                 return true;
2384         }
2385         catch(InvalidPositionException &e)
2386         {
2387                 /*
2388                         Try to load the sector from disk.
2389                 */
2390                 if(loadSectorFull(p2d) == true)
2391                 {
2392                         return true;
2393                 }
2394         }
2395         return false;
2396 }
2397 #endif
2398
2399 void ServerMap::saveBlock(MapBlock *block)
2400 {
2401         DSTACK(__FUNCTION_NAME);
2402         /*
2403                 Dummy blocks are not written
2404         */
2405         if(block->isDummy())
2406         {
2407                 /*v3s16 p = block->getPos();
2408                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
2409                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2410                 return;
2411         }
2412
2413         // Format used for writing
2414         u8 version = SER_FMT_VER_HIGHEST;
2415         // Get destination
2416         v3s16 p3d = block->getPos();
2417         v2s16 p2d(p3d.X, p3d.Z);
2418         createDir(m_savedir);
2419         createDir(m_savedir+"/sectors");
2420         std::string dir = getSectorDir(p2d);
2421         createDir(dir);
2422         
2423         // Block file is map/sectors/xxxxxxxx/xxxx
2424         char cc[5];
2425         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
2426         std::string fullpath = dir + "/" + cc;
2427         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2428         if(o.good() == false)
2429                 throw FileNotGoodException("Cannot open block data");
2430
2431         /*
2432                 [0] u8 serialization version
2433                 [1] data
2434         */
2435         o.write((char*)&version, 1);
2436         
2437         block->serialize(o, version);
2438
2439         /*
2440                 Versions up from 9 have block objects.
2441         */
2442         if(version >= 9)
2443         {
2444                 block->serializeObjects(o, version);
2445         }
2446         
2447         // We just wrote it to the disk
2448         block->resetChangedFlag();
2449 }
2450
2451 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
2452 {
2453         DSTACK(__FUNCTION_NAME);
2454         // Block file is map/sectors/xxxxxxxx/xxxx
2455         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
2456         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2457         if(is.good() == false)
2458                 throw FileNotGoodException("Cannot open block file");
2459
2460         v3s16 p3d = getBlockPos(sectordir, blockfile);
2461         v2s16 p2d(p3d.X, p3d.Z);
2462         
2463         assert(sector->getPos() == p2d);
2464         
2465         u8 version = SER_FMT_VER_INVALID;
2466         is.read((char*)&version, 1);
2467
2468         /*u32 block_size = MapBlock::serializedLength(version);
2469         SharedBuffer<u8> data(block_size);
2470         is.read((char*)*data, block_size);*/
2471
2472         // This will always return a sector because we're the server
2473         //MapSector *sector = emergeSector(p2d);
2474
2475         MapBlock *block = NULL;
2476         bool created_new = false;
2477         try{
2478                 block = sector->getBlockNoCreate(p3d.Y);
2479         }
2480         catch(InvalidPositionException &e)
2481         {
2482                 block = sector->createBlankBlockNoInsert(p3d.Y);
2483                 created_new = true;
2484         }
2485
2486         block->deSerialize(is, version);
2487         
2488         /*
2489                 Versions up from 9 have block objects.
2490         */
2491         if(version >= 9)
2492         {
2493                 block->updateObjects(is, version, NULL);
2494         }
2495
2496         if(created_new)
2497                 sector->insertBlock(block);
2498         
2499         /*
2500                 Convert old formats to new and save
2501         */
2502
2503         // Save old format blocks in new format
2504         if(version < SER_FMT_VER_HIGHEST)
2505         {
2506                 saveBlock(block);
2507         }
2508         
2509         // We just loaded it from the disk, so it's up-to-date.
2510         block->resetChangedFlag();
2511 }
2512
2513 // Gets from master heightmap
2514 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
2515 {
2516         assert(m_heightmap != NULL);
2517         /*
2518                 Corner definition:
2519                 v2s16(0,0),
2520                 v2s16(1,0),
2521                 v2s16(1,1),
2522                 v2s16(0,1),
2523         */
2524         corners[0] = m_heightmap->getGroundHeight
2525                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
2526         corners[1] = m_heightmap->getGroundHeight
2527                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
2528         corners[2] = m_heightmap->getGroundHeight
2529                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
2530         corners[3] = m_heightmap->getGroundHeight
2531                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
2532 }
2533
2534 void ServerMap::PrintInfo(std::ostream &out)
2535 {
2536         out<<"ServerMap: ";
2537 }
2538
2539 /*
2540         ClientMap
2541 */
2542
2543 ClientMap::ClientMap(
2544                 Client *client,
2545                 video::SMaterial *materials,
2546                 scene::ISceneNode* parent,
2547                 scene::ISceneManager* mgr,
2548                 s32 id
2549 ):
2550         Map(dout_client),
2551         scene::ISceneNode(parent, mgr, id),
2552         m_client(client),
2553         m_materials(materials),
2554         mesh(NULL)
2555 {
2556         /*m_box = core::aabbox3d<f32>(0,0,0,
2557                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
2558         /*m_box = core::aabbox3d<f32>(0,0,0,
2559                         map->getSizeNodes().X * BS,
2560                         map->getSizeNodes().Y * BS,
2561                         map->getSizeNodes().Z * BS);*/
2562         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
2563                         BS*1000000,BS*1000000,BS*1000000);
2564
2565         mesh_mutex.Init();
2566 }
2567
2568 ClientMap::~ClientMap()
2569 {
2570         JMutexAutoLock lock(mesh_mutex);
2571         
2572         if(mesh != NULL)
2573         {
2574                 mesh->drop();
2575                 mesh = NULL;
2576         }
2577 }
2578
2579 MapSector * ClientMap::emergeSector(v2s16 p2d)
2580 {
2581         DSTACK(__FUNCTION_NAME);
2582         // Check that it doesn't exist already
2583         try{
2584                 return getSectorNoGenerate(p2d);
2585         }
2586         catch(InvalidPositionException &e)
2587         {
2588         }
2589         
2590         // Create a sector with no heightmaps
2591         ClientMapSector *sector = new ClientMapSector(this, p2d);
2592         
2593         {
2594                 JMutexAutoLock lock(m_sector_mutex);
2595                 m_sectors.insert(p2d, sector);
2596         }
2597         
2598         return sector;
2599 }
2600
2601 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
2602 {
2603         DSTACK(__FUNCTION_NAME);
2604         ClientMapSector *sector = NULL;
2605
2606         JMutexAutoLock lock(m_sector_mutex);
2607         
2608         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
2609
2610         if(n != NULL)
2611         {
2612                 sector = (ClientMapSector*)n->getValue();
2613                 assert(sector->getId() == MAPSECTOR_CLIENT);
2614         }
2615         else
2616         {
2617                 sector = new ClientMapSector(this, p2d);
2618                 {
2619                         JMutexAutoLock lock(m_sector_mutex);
2620                         m_sectors.insert(p2d, sector);
2621                 }
2622         }
2623
2624         sector->deSerialize(is);
2625 }
2626
2627 void ClientMap::renderMap(video::IVideoDriver* driver,
2628         video::SMaterial *materials, s32 pass)
2629 {
2630         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
2631         DSTACK(__FUNCTION_NAME);
2632
2633         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
2634 #if 0
2635         /*
2636                 Draw master heightmap mesh
2637         */
2638         
2639         {
2640                 JMutexAutoLock lock(mesh_mutex);
2641                 if(mesh != NULL)
2642                 {
2643                         u32 c = mesh->getMeshBufferCount();
2644
2645                         for(u32 i=0; i<c; i++)
2646                         {
2647                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
2648                                 const video::SMaterial& material = buf->getMaterial();
2649                                 video::IMaterialRenderer* rnd =
2650                                                 driver->getMaterialRenderer(material.MaterialType);
2651                                 bool transparent = (rnd && rnd->isTransparent());
2652                                 // Render transparent on transparent pass and likewise.
2653                                 if(transparent == is_transparent_pass)
2654                                 {
2655                                         driver->setMaterial(buf->getMaterial());
2656                                         driver->drawMeshBuffer(buf);
2657                                 }
2658                         }
2659                 }
2660         }
2661 #endif
2662
2663         /*
2664                 Get time for measuring timeout.
2665                 
2666                 Measuring time is very useful for long delays when the
2667                 machine is swapping a lot.
2668         */
2669         int time1 = time(0);
2670
2671         /*
2672                 Collect all blocks that are in the view range
2673
2674                 Should not optimize more here as we want to auto-update
2675                 all changed nodes in viewing range at the next step.
2676         */
2677
2678         s16 viewing_range_nodes;
2679         bool viewing_range_all;
2680         {
2681                 JMutexAutoLock lock(g_range_mutex);
2682                 viewing_range_nodes = g_viewing_range_nodes;
2683                 viewing_range_all = g_viewing_range_all;
2684         }
2685
2686         m_camera_mutex.Lock();
2687         v3f camera_position = m_camera_position;
2688         v3f camera_direction = m_camera_direction;
2689         m_camera_mutex.Unlock();
2690
2691         /*
2692                 Get all blocks and draw all visible ones
2693         */
2694
2695         v3s16 cam_pos_nodes(
2696                         camera_position.X / BS,
2697                         camera_position.Y / BS,
2698                         camera_position.Z / BS);
2699
2700         v3s16 box_nodes_d = viewing_range_nodes * v3s16(1,1,1);
2701
2702         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2703         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2704
2705         // Take a fair amount as we will be dropping more out later
2706         v3s16 p_blocks_min(
2707                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2708                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2709                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2710         v3s16 p_blocks_max(
2711                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2712                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2713                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2714         
2715         u32 vertex_count = 0;
2716         
2717         core::map<v2s16, MapSector*>::Iterator si;
2718
2719         //NOTE: The sectors map should be locked but we're not doing it
2720         // because it'd cause too much delays
2721
2722         si = m_sectors.getIterator();
2723         for(; si.atEnd() == false; si++)
2724         {
2725                 {
2726                         static int timecheck_counter = 0;
2727                         timecheck_counter++;
2728                         if(timecheck_counter > 50)
2729                         {
2730                                 int time2 = time(0);
2731                                 if(time2 > time1 + 4)
2732                                 {
2733                                         dstream<<"ClientMap::renderMap(): "
2734                                                 "Rendering takes ages, returning."
2735                                                 <<std::endl;
2736                                         return;
2737                                 }
2738                         }
2739                 }
2740
2741                 MapSector *sector = si.getNode()->getValue();
2742                 v2s16 sp = sector->getPos();
2743                 
2744                 if(viewing_range_all == false)
2745                 {
2746                         if(sp.X < p_blocks_min.X
2747                         || sp.X > p_blocks_max.X
2748                         || sp.Y < p_blocks_min.Z
2749                         || sp.Y > p_blocks_max.Z)
2750                                 continue;
2751                 }
2752
2753                 core::list< MapBlock * > sectorblocks;
2754                 sector->getBlocks(sectorblocks);
2755                 
2756                 /*
2757                         Draw blocks
2758                 */
2759
2760                 core::list< MapBlock * >::Iterator i;
2761                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
2762                 {
2763                         MapBlock *block = *i;
2764
2765                         /*
2766                                 Compare block position to camera position, skip
2767                                 if not seen on display
2768                         */
2769                         
2770                         v3s16 blockpos_nodes = block->getPosRelative();
2771                         
2772                         // Block center position
2773                         v3f blockpos(
2774                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
2775                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
2776                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
2777                         );
2778
2779                         // Block position relative to camera
2780                         v3f blockpos_relative = blockpos - camera_position;
2781
2782                         // Distance in camera direction (+=front, -=back)
2783                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
2784
2785                         // Total distance
2786                         f32 d = blockpos_relative.getLength();
2787                         
2788                         if(viewing_range_all == false)
2789                         {
2790                                 // If block is far away, don't draw it
2791                                 if(d > viewing_range_nodes * BS)
2792                                         continue;
2793                         }
2794                         
2795                         // Maximum radius of a block
2796                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
2797                         
2798                         // If block is (nearly) touching the camera, don't
2799                         // bother validating further (that is, render it anyway)
2800                         if(d > block_max_radius * 1.5)
2801                         {
2802                                 // Cosine of the angle between the camera direction
2803                                 // and the block direction (camera_direction is an unit vector)
2804                                 f32 cosangle = dforward / d;
2805                                 
2806                                 // Compensate for the size of the block
2807                                 // (as the block has to be shown even if it's a bit off FOV)
2808                                 // This is an estimate.
2809                                 cosangle += block_max_radius / dforward;
2810
2811                                 // If block is not in the field of view, skip it
2812                                 //if(cosangle < cos(FOV_ANGLE/2))
2813                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
2814                                         continue;
2815                         }
2816                         
2817                         /*
2818                                 Draw the faces of the block
2819                         */
2820                         
2821                         {
2822                                 JMutexAutoLock lock(block->mesh_mutex);
2823
2824                                 // Cancel if block has no mesh
2825                                 if(block->mesh == NULL)
2826                                         continue;
2827
2828                                 u32 c = block->mesh->getMeshBufferCount();
2829
2830                                 for(u32 i=0; i<c; i++)
2831                                 {
2832                                         scene::IMeshBuffer *buf = block->mesh->getMeshBuffer(i);
2833                                         const video::SMaterial& material = buf->getMaterial();
2834                                         video::IMaterialRenderer* rnd =
2835                                                         driver->getMaterialRenderer(material.MaterialType);
2836                                         bool transparent = (rnd && rnd->isTransparent());
2837                                         // Render transparent on transparent pass and likewise.
2838                                         if(transparent == is_transparent_pass)
2839                                         {
2840                                                 driver->setMaterial(buf->getMaterial());
2841                                                 driver->drawMeshBuffer(buf);
2842                                                 vertex_count += buf->getVertexCount();
2843                                         }
2844                                 }
2845                         }
2846                 } // foreach sectorblocks
2847         }
2848
2849         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
2850                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
2851 }
2852
2853 void ClientMap::updateMesh()
2854 {
2855 #if 0
2856         DSTACK(__FUNCTION_NAME);
2857         //TODO
2858         /*
2859                 Check what sectors don't draw anything useful at ground level
2860                 and create a mesh of the rough heightmap at those positions.
2861         */
2862
2863         m_camera_mutex.Lock();
2864         v3f camera_position = m_camera_position;
2865         v3f camera_direction = m_camera_direction;
2866         m_camera_mutex.Unlock();
2867
2868         v3s16 cam_pos_nodes(
2869                         camera_position.X / BS,
2870                         camera_position.Y / BS,
2871                         camera_position.Z / BS);
2872
2873         v3s16 box_nodes_d = HEIGHTMAP_RANGE_NODES * v3s16(1,1,1);
2874
2875         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2876         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2877
2878         // Take a fair amount as we will be dropping more out later
2879         v3s16 p_blocks_min(
2880                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2881                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2882                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2883         v3s16 p_blocks_max(
2884                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2885                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2886                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2887         
2888         /*
2889                 Initialize new mesh
2890         */
2891         
2892         scene::SMesh *mesh_new = new scene::SMesh();
2893         //scene::IMeshBuffer *buf = NULL;
2894         scene::SMeshBuffer *buf = NULL;
2895
2896         u8 material_in_use = 0;
2897
2898         /*
2899                 Loop through sectors
2900         */
2901         
2902         for(core::map<v2s16, MapSector*>::Iterator
2903                         si = m_sectors.getIterator();
2904                         si.atEnd() == false; si++)
2905         {
2906                 MapSector *sector = si.getNode()->getValue();
2907                 
2908                 if(sector->getId() != MAPSECTOR_CLIENT)
2909                 {
2910                         dstream<<"WARNING: Client has a non-client sector"
2911                                         <<std::endl;
2912                         continue;
2913                 }
2914                 
2915                 ClientMapSector *cs = (ClientMapSector*)sector;
2916
2917                 v2s16 sp = sector->getPos();
2918
2919                 if(sp.X < p_blocks_min.X
2920                 || sp.X > p_blocks_max.X
2921                 || sp.Y < p_blocks_min.Z
2922                 || sp.Y > p_blocks_max.Z)
2923                         continue;
2924                 
2925                 /*
2926                         Get some ground level info
2927                 */
2928                 
2929                 s16 a = -5;
2930
2931                 s16 cn[4] = 
2932                 {
2933                         cs->getCorner(0)+a,
2934                         cs->getCorner(1)+a,
2935                         cs->getCorner(2)+a,
2936                         cs->getCorner(3)+a,
2937                 };
2938                 s16 cn_avg = (cn[0]+cn[1]+cn[2]+cn[3])/4;
2939                 s16 cn_min = 32767;
2940                 s16 cn_max = -32768;
2941                 for(s16 i=0; i<4; i++)
2942                 {
2943                         if(cn[i] < cn_min)
2944                                 cn_min = cn[i];
2945                         if(cn[i] > cn_max)
2946                                 cn_max = cn[i];
2947                 }
2948                 s16 cn_slope = cn_max - cn_min;
2949                 
2950                 /*
2951                         Generate this part of the heightmap mesh
2952                 */
2953
2954                 u8 material;
2955                 if(cn_avg + MAP_BLOCKSIZE/4 <= WATER_LEVEL)
2956                         material = 0;
2957                 else if(cn_slope <= MAP_BLOCKSIZE)
2958                         material = 1;
2959                 else
2960                         material = 2;
2961
2962                 if(material != material_in_use || buf == NULL)
2963                 {
2964                         // Try to get a meshbuffer associated with the material
2965                         buf = (scene::SMeshBuffer*)mesh_new->getMeshBuffer
2966                                         (g_mesh_materials[material]);
2967                         // If not found, create one
2968                         if(buf == NULL)
2969                         {
2970                                 // This is a "Standard MeshBuffer",
2971                                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
2972                                 buf = new scene::SMeshBuffer();
2973
2974                                 // Set material
2975                                 buf->Material = g_mesh_materials[material];
2976                                 // Use VBO
2977                                 //buf->setHardwareMappingHint(scene::EHM_STATIC);
2978                                 // Add to mesh
2979                                 mesh_new->addMeshBuffer(buf);
2980                                 // Mesh grabbed it
2981                                 buf->drop();
2982                         }
2983                         material_in_use = material;
2984                 }
2985
2986                 // Sector side width in floating-point units
2987                 f32 sd = BS * MAP_BLOCKSIZE;
2988                 // Sector position in global floating-point units
2989                 v3f spf = v3f((f32)sp.X, 0, (f32)sp.Y) * sd;
2990
2991                 //video::SColor c(255,255,255,255);
2992                 u8 cc = 180;
2993                 video::SColor c(255,cc,cc,cc);
2994                 
2995                 video::S3DVertex vertices[4] =
2996                 {
2997                         video::S3DVertex(spf.X,   (f32)BS*cn[0],spf.Z,   0,0,0, c, 0,1),
2998                         video::S3DVertex(spf.X+sd,(f32)BS*cn[1],spf.Z,   0,0,0, c, 1,1),
2999                         video::S3DVertex(spf.X+sd,(f32)BS*cn[2],spf.Z+sd,0,0,0, c, 1,0),
3000                         video::S3DVertex(spf.X,   (f32)BS*cn[3],spf.Z+sd,0,0,0, c, 0,0),
3001                 };
3002                 u16 indices[] = {0,1,2,2,3,0};
3003                 
3004                 buf->append(vertices, 4, indices, 6);
3005         }
3006         
3007         // Set VBO on
3008         //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
3009
3010         /*
3011                 Replace the mesh
3012         */
3013
3014         mesh_mutex.Lock();
3015
3016         scene::SMesh *mesh_old = mesh;
3017
3018         //DEBUG
3019         /*mesh = NULL;
3020         mesh_new->drop();*/
3021         mesh = mesh_new;
3022         
3023         mesh_mutex.Unlock();
3024
3025         if(mesh_old != NULL)
3026         {
3027                 /*dstream<<"mesh_old refcount="<<mesh_old->getReferenceCount()
3028                                 <<std::endl;
3029                 scene::IMeshBuffer *buf = mesh_new->getMeshBuffer
3030                                 (g_materials[MATERIAL_GRASS]);
3031                 if(buf != NULL)
3032                         dstream<<"grass buf refcount="<<buf->getReferenceCount()
3033                                         <<std::endl;*/
3034
3035                 mesh_old->drop();
3036         }
3037         else
3038         {
3039                 dstream<<"WARNING: There was no old master heightmap mesh"<<std::endl;
3040         }
3041 #endif
3042 }
3043
3044 void ClientMap::PrintInfo(std::ostream &out)
3045 {
3046         out<<"ClientMap: ";
3047 }
3048
3049