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