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