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