commit before some radicallish changes to water behavior
[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.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
1824                                 }
1825                                 // else air
1826                                 else
1827                                         n.d = MATERIAL_AIR;
1828                         }
1829                         block->setNode(v3s16(x0,y0,z0), n);
1830                 }
1831         }
1832
1833         /*
1834                 Calculate is_underground
1835         */
1836         // Probably underground if the highest part of block is under lowest
1837         // ground height
1838         bool is_underground = (block_y+1) * MAP_BLOCKSIZE < lowest_ground_y;
1839         block->setIsUnderground(is_underground);
1840
1841         /*
1842                 Force lighting update if underground.
1843                 This is needed because of ravines.
1844         */
1845
1846         if(is_underground)
1847         {
1848                 lighting_invalidated_blocks[block->getPos()] = block;
1849         }
1850         
1851         /*
1852                 Add some minerals
1853         */
1854
1855         if(is_underground)
1856         {
1857                 s16 underground_level = lowest_ground_y/MAP_BLOCKSIZE - block_y;
1858                 for(s16 i=0; i<underground_level*3; i++)
1859                 {
1860                         if(rand()%2 == 0)
1861                         {
1862                                 v3s16 cp(
1863                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1864                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1865                                         (rand()%(MAP_BLOCKSIZE-2))+1
1866                                 );
1867
1868                                 MapNode n;
1869                                 n.d = MATERIAL_MESE;
1870                                 
1871                                 if(is_ground_material(block->getNode(cp).d))
1872                                         if(rand()%8 == 0)
1873                                                 block->setNode(cp, n);
1874
1875                                 for(u16 i=0; i<26; i++)
1876                                 {
1877                                         if(is_ground_material(block->getNode(cp+g_26dirs[i]).d))
1878                                                 if(rand()%8 == 0)
1879                                                         block->setNode(cp+g_26dirs[i], n);
1880                                 }
1881                         }
1882                 }
1883         }
1884         
1885         /*
1886                 Create a few rats in empty blocks underground
1887         */
1888         if(is_underground)
1889         {
1890                 //for(u16 i=0; i<2; i++)
1891                 {
1892                         v3s16 cp(
1893                                 (rand()%(MAP_BLOCKSIZE-2))+1,
1894                                 (rand()%(MAP_BLOCKSIZE-2))+1,
1895                                 (rand()%(MAP_BLOCKSIZE-2))+1
1896                         );
1897
1898                         // Check that the place is empty
1899                         //if(!is_ground_material(block->getNode(cp).d))
1900                         if(1)
1901                         {
1902                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
1903                                 block->addObject(obj);
1904                         }
1905                 }
1906         }
1907         
1908         /*
1909                 Add block to sector.
1910         */
1911         sector->insertBlock(block);
1912         
1913         /*
1914                 Do some interpolation for dungeons
1915         */
1916
1917 #if 0   
1918         {
1919         TimeTaker timer("interpolation", g_device);
1920         
1921         MapVoxelManipulator vmanip(this);
1922         
1923         v3s16 relpos = block->getPosRelative();
1924
1925         vmanip.interpolate(VoxelArea(relpos-v3s16(1,1,1),
1926                         relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE+1)));
1927         /*vmanip.interpolate(VoxelArea(relpos,
1928                         relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE-1)));*/
1929         
1930         core::map<v3s16, MapBlock*> modified_blocks;
1931         vmanip.blitBack(modified_blocks);
1932         dstream<<"blitBack modified "<<modified_blocks.size()
1933                         <<" blocks"<<std::endl;
1934
1935         // Add modified blocks to changed_blocks and lighting_invalidated_blocks
1936         for(core::map<v3s16, MapBlock*>::Iterator
1937                         i = modified_blocks.getIterator();
1938                         i.atEnd() == false; i++)
1939         {
1940                 MapBlock *block = i.getNode()->getValue();
1941
1942                 changed_blocks.insert(block->getPos(), block);
1943                 //lighting_invalidated_blocks.insert(block->getPos(), block);
1944         }
1945
1946         }
1947 #endif
1948
1949         /*
1950                 Sector object stuff
1951         */
1952                 
1953         // An y-wise container of changed blocks
1954         core::map<s16, MapBlock*> changed_blocks_sector;
1955
1956         /*
1957                 Check if any sector's objects can be placed now.
1958                 If so, place them.
1959         */
1960         core::map<v3s16, u8> *objects = sector->getObjects();
1961         core::list<v3s16> objects_to_remove;
1962         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
1963                         i.atEnd() == false; i++)
1964         {
1965                 v3s16 p = i.getNode()->getKey();
1966                 v2s16 p2d(p.X,p.Z);
1967                 u8 d = i.getNode()->getValue();
1968
1969                 //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
1970                 
1971                 try
1972                 {
1973
1974                 if(d == SECTOR_OBJECT_TEST)
1975                 {
1976                         if(sector->isValidArea(p + v3s16(0,0,0),
1977                                         p + v3s16(0,0,0), &changed_blocks_sector))
1978                         {
1979                                 MapNode n;
1980                                 n.d = MATERIAL_LIGHT;
1981                                 sector->setNode(p, n);
1982                                 objects_to_remove.push_back(p);
1983                         }
1984                 }
1985                 else if(d == SECTOR_OBJECT_TREE_1)
1986                 {
1987                         v3s16 p_min = p + v3s16(-1,0,-1);
1988                         v3s16 p_max = p + v3s16(1,4,1);
1989                         if(sector->isValidArea(p_min, p_max,
1990                                         &changed_blocks_sector))
1991                         {
1992                                 MapNode n;
1993                                 n.d = MATERIAL_TREE;
1994                                 sector->setNode(p+v3s16(0,0,0), n);
1995                                 sector->setNode(p+v3s16(0,1,0), n);
1996                                 sector->setNode(p+v3s16(0,2,0), n);
1997                                 sector->setNode(p+v3s16(0,3,0), n);
1998
1999                                 n.d = MATERIAL_LEAVES;
2000
2001                                 sector->setNode(p+v3s16(0,4,0), n);
2002                                 
2003                                 sector->setNode(p+v3s16(-1,4,0), n);
2004                                 sector->setNode(p+v3s16(1,4,0), n);
2005                                 sector->setNode(p+v3s16(0,4,-1), n);
2006                                 sector->setNode(p+v3s16(0,4,1), n);
2007                                 sector->setNode(p+v3s16(1,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
2012                                 sector->setNode(p+v3s16(-1,3,0), n);
2013                                 sector->setNode(p+v3s16(1,3,0), n);
2014                                 sector->setNode(p+v3s16(0,3,-1), n);
2015                                 sector->setNode(p+v3s16(0,3,1), n);
2016                                 sector->setNode(p+v3s16(1,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                                 
2021                                 objects_to_remove.push_back(p);
2022                                 
2023                                 // Lighting has to be recalculated for this one.
2024                                 sector->getBlocksInArea(p_min, p_max, 
2025                                                 lighting_invalidated_blocks);
2026                         }
2027                 }
2028                 else if(d == SECTOR_OBJECT_BUSH_1)
2029                 {
2030                         if(sector->isValidArea(p + v3s16(0,0,0),
2031                                         p + v3s16(0,0,0), &changed_blocks_sector))
2032                         {
2033                                 MapNode n;
2034                                 n.d = MATERIAL_LEAVES;
2035                                 sector->setNode(p+v3s16(0,0,0), n);
2036                                 
2037                                 objects_to_remove.push_back(p);
2038                         }
2039                 }
2040                 else if(d == SECTOR_OBJECT_RAVINE)
2041                 {
2042                         s16 maxdepth = -20;
2043                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
2044                         v3s16 p_max = p + v3s16(6,6,6);
2045                         if(sector->isValidArea(p_min, p_max,
2046                                         &changed_blocks_sector))
2047                         {
2048                                 MapNode n;
2049                                 n.d = MATERIAL_STONE;
2050                                 MapNode n2;
2051                                 n2.d = MATERIAL_AIR;
2052                                 s16 depth = maxdepth + (rand()%10);
2053                                 s16 z = 0;
2054                                 s16 minz = -6 - (-2);
2055                                 s16 maxz = 6 -1;
2056                                 for(s16 x=-6; x<=6; x++)
2057                                 {
2058                                         z += -1 + (rand()%3);
2059                                         if(z < minz)
2060                                                 z = minz;
2061                                         if(z > maxz)
2062                                                 z = maxz;
2063                                         for(s16 y=depth+(rand()%2); y<=6; y++)
2064                                         {
2065                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
2066                                                                 <<std::endl;*/
2067                                                 {
2068                                                         v3s16 p2 = p + v3s16(x,y,z-2);
2069                                                         if(is_ground_material(sector->getNode(p2).d))
2070                                                                 sector->setNode(p2, n);
2071                                                 }
2072                                                 {
2073                                                         v3s16 p2 = p + v3s16(x,y,z-1);
2074                                                         if(is_ground_material(sector->getNode(p2).d))
2075                                                                 sector->setNode(p2, n2);
2076                                                 }
2077                                                 {
2078                                                         v3s16 p2 = p + v3s16(x,y,z+0);
2079                                                         if(is_ground_material(sector->getNode(p2).d))
2080                                                                 sector->setNode(p2, n2);
2081                                                 }
2082                                                 {
2083                                                         v3s16 p2 = p + v3s16(x,y,z+1);
2084                                                         if(is_ground_material(sector->getNode(p2).d))
2085                                                                 sector->setNode(p2, n);
2086                                                 }
2087
2088                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
2089                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
2090                                         }
2091                                 }
2092                                 
2093                                 objects_to_remove.push_back(p);
2094                                 
2095                                 // Lighting has to be recalculated for this one.
2096                                 sector->getBlocksInArea(p_min, p_max, 
2097                                                 lighting_invalidated_blocks);
2098                         }
2099                 }
2100                 else
2101                 {
2102                         dstream<<"ServerMap::emergeBlock(): "
2103                                         "Invalid heightmap object"
2104                                         <<std::endl;
2105                 }
2106
2107                 }//try
2108                 catch(InvalidPositionException &e)
2109                 {
2110                         dstream<<"WARNING: "<<__FUNCTION_NAME
2111                                         <<": while inserting object "<<(int)d
2112                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
2113                                         <<" InvalidPositionException.what()="
2114                                         <<e.what()<<std::endl;
2115                         // This is not too fatal and seems to happen sometimes.
2116                         assert(0);
2117                 }
2118         }
2119
2120         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
2121                         i != objects_to_remove.end(); i++)
2122         {
2123                 objects->remove(*i);
2124         }
2125
2126         for(core::map<s16, MapBlock*>::Iterator
2127                         i = changed_blocks_sector.getIterator();
2128                         i.atEnd() == false; i++)
2129         {
2130                 MapBlock *block = i.getNode()->getValue();
2131
2132                 changed_blocks.insert(block->getPos(), block);
2133         }
2134
2135         return block;
2136 }
2137
2138 void ServerMap::createDir(std::string path)
2139 {
2140         if(fs::CreateDir(path) == false)
2141         {
2142                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2143                                 <<"\""<<path<<"\""<<std::endl;
2144                 throw BaseException("ServerMap failed to create directory");
2145         }
2146 }
2147
2148 std::string ServerMap::getSectorSubDir(v2s16 pos)
2149 {
2150         char cc[9];
2151         snprintf(cc, 9, "%.4x%.4x",
2152                         (unsigned int)pos.X&0xffff,
2153                         (unsigned int)pos.Y&0xffff);
2154
2155         return std::string(cc);
2156 }
2157
2158 std::string ServerMap::getSectorDir(v2s16 pos)
2159 {
2160         return m_savedir + "/sectors/" + getSectorSubDir(pos);
2161 }
2162
2163 v2s16 ServerMap::getSectorPos(std::string dirname)
2164 {
2165         if(dirname.size() != 8)
2166                 throw InvalidFilenameException("Invalid sector directory name");
2167         unsigned int x, y;
2168         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
2169         if(r != 2)
2170                 throw InvalidFilenameException("Invalid sector directory name");
2171         v2s16 pos((s16)x, (s16)y);
2172         return pos;
2173 }
2174
2175 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2176 {
2177         v2s16 p2d = getSectorPos(sectordir);
2178
2179         if(blockfile.size() != 4){
2180                 throw InvalidFilenameException("Invalid block filename");
2181         }
2182         unsigned int y;
2183         int r = sscanf(blockfile.c_str(), "%4x", &y);
2184         if(r != 1)
2185                 throw InvalidFilenameException("Invalid block filename");
2186         return v3s16(p2d.X, y, p2d.Y);
2187 }
2188
2189 // Debug helpers
2190 #define ENABLE_SECTOR_SAVING 1
2191 #define ENABLE_SECTOR_LOADING 1
2192 #define ENABLE_BLOCK_SAVING 1
2193 #define ENABLE_BLOCK_LOADING 1
2194
2195 void ServerMap::save(bool only_changed)
2196 {
2197         DSTACK(__FUNCTION_NAME);
2198         if(m_map_saving_enabled == false)
2199         {
2200                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2201                 return;
2202         }
2203         
2204         if(only_changed == false)
2205                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2206                                 <<std::endl;
2207         
2208         saveMasterHeightmap();
2209         
2210         u32 sector_meta_count = 0;
2211         u32 block_count = 0;
2212         
2213         { //sectorlock
2214         JMutexAutoLock lock(m_sector_mutex);
2215         
2216         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2217         for(; i.atEnd() == false; i++)
2218         {
2219                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2220                 assert(sector->getId() == MAPSECTOR_SERVER);
2221                 
2222                 if(ENABLE_SECTOR_SAVING)
2223                 {
2224                         if(sector->differs_from_disk || only_changed == false)
2225                         {
2226                                 saveSectorMeta(sector);
2227                                 sector_meta_count++;
2228                         }
2229                 }
2230                 if(ENABLE_BLOCK_SAVING)
2231                 {
2232                         core::list<MapBlock*> blocks;
2233                         sector->getBlocks(blocks);
2234                         core::list<MapBlock*>::Iterator j;
2235                         for(j=blocks.begin(); j!=blocks.end(); j++)
2236                         {
2237                                 MapBlock *block = *j;
2238                                 if(block->getChangedFlag() || only_changed == false)
2239                                 {
2240                                         saveBlock(block);
2241                                         block_count++;
2242                                 }
2243                         }
2244                 }
2245         }
2246
2247         }//sectorlock
2248         
2249         u32 deleted_count = 0;
2250         deleted_count = deleteUnusedSectors
2251                         (SERVERMAP_DELETE_UNUSED_SECTORS_TIMEOUT);
2252         
2253         /*
2254                 Only print if something happened or saved whole map
2255         */
2256         if(only_changed == false || sector_meta_count != 0
2257                         || block_count != 0 || deleted_count != 0)
2258         {
2259                 dstream<<DTIME<<"ServerMap: Written: "
2260                                 <<sector_meta_count<<" sector metadata files, "
2261                                 <<block_count<<" block files, "
2262                                 <<deleted_count<<" sectors unloaded from memory."
2263                                 <<std::endl;
2264         }
2265 }
2266
2267 void ServerMap::loadAll()
2268 {
2269         DSTACK(__FUNCTION_NAME);
2270         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
2271
2272         loadMasterHeightmap();
2273
2274         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
2275
2276         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
2277         
2278         JMutexAutoLock lock(m_sector_mutex);
2279         
2280         s32 counter = 0;
2281         s32 printed_counter = -100000;
2282         s32 count = list.size();
2283
2284         std::vector<fs::DirListNode>::iterator i;
2285         for(i=list.begin(); i!=list.end(); i++)
2286         {
2287                 if(counter > printed_counter + 10)
2288                 {
2289                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
2290                         printed_counter = counter;
2291                 }
2292                 counter++;
2293
2294                 MapSector *sector = NULL;
2295
2296                 // We want directories
2297                 if(i->dir == false)
2298                         continue;
2299                 try{
2300                         sector = loadSectorMeta(i->name);
2301                 }
2302                 catch(InvalidFilenameException &e)
2303                 {
2304                         // This catches unknown crap in directory
2305                 }
2306                 
2307                 if(ENABLE_BLOCK_LOADING)
2308                 {
2309                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2310                                         (m_savedir+"/sectors/"+i->name);
2311                         std::vector<fs::DirListNode>::iterator i2;
2312                         for(i2=list2.begin(); i2!=list2.end(); i2++)
2313                         {
2314                                 // We want files
2315                                 if(i2->dir)
2316                                         continue;
2317                                 try{
2318                                         loadBlock(i->name, i2->name, sector);
2319                                 }
2320                                 catch(InvalidFilenameException &e)
2321                                 {
2322                                         // This catches unknown crap in directory
2323                                 }
2324                         }
2325                 }
2326         }
2327         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
2328 }
2329
2330 void ServerMap::saveMasterHeightmap()
2331 {
2332         DSTACK(__FUNCTION_NAME);
2333         createDir(m_savedir);
2334         
2335         std::string fullpath = m_savedir + "/master_heightmap";
2336         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2337         if(o.good() == false)
2338                 throw FileNotGoodException("Cannot open master heightmap");
2339         
2340         // Format used for writing
2341         u8 version = SER_FMT_VER_HIGHEST;
2342
2343 #if 0
2344         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
2345         /*
2346                 [0] u8 serialization version
2347                 [1] X master heightmap
2348         */
2349         u32 fullsize = 1 + hmdata.getSize();
2350         SharedBuffer<u8> data(fullsize);
2351
2352         data[0] = version;
2353         memcpy(&data[1], *hmdata, hmdata.getSize());
2354
2355         o.write((const char*)*data, fullsize);
2356 #endif
2357         
2358         m_heightmap->serialize(o, version);
2359 }
2360
2361 void ServerMap::loadMasterHeightmap()
2362 {
2363         DSTACK(__FUNCTION_NAME);
2364         std::string fullpath = m_savedir + "/master_heightmap";
2365         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2366         if(is.good() == false)
2367                 throw FileNotGoodException("Cannot open master heightmap");
2368         
2369         if(m_heightmap != NULL)
2370                 delete m_heightmap;
2371                 
2372         m_heightmap = UnlimitedHeightmap::deSerialize(is);
2373 }
2374
2375 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2376 {
2377         DSTACK(__FUNCTION_NAME);
2378         // Format used for writing
2379         u8 version = SER_FMT_VER_HIGHEST;
2380         // Get destination
2381         v2s16 pos = sector->getPos();
2382         createDir(m_savedir);
2383         createDir(m_savedir+"/sectors");
2384         std::string dir = getSectorDir(pos);
2385         createDir(dir);
2386         
2387         std::string fullpath = dir + "/heightmap";
2388         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2389         if(o.good() == false)
2390                 throw FileNotGoodException("Cannot open master heightmap");
2391
2392         sector->serialize(o, version);
2393         
2394         sector->differs_from_disk = false;
2395 }
2396
2397 MapSector* ServerMap::loadSectorMeta(std::string dirname)
2398 {
2399         DSTACK(__FUNCTION_NAME);
2400         // Get destination
2401         v2s16 p2d = getSectorPos(dirname);
2402         std::string dir = m_savedir + "/sectors/" + dirname;
2403         
2404         std::string fullpath = dir + "/heightmap";
2405         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2406         if(is.good() == false)
2407                 throw FileNotGoodException("Cannot open sector heightmap");
2408
2409         ServerMapSector *sector = ServerMapSector::deSerialize
2410                         (is, this, p2d, &m_hwrapper, m_sectors);
2411         
2412         sector->differs_from_disk = false;
2413
2414         return sector;
2415 }
2416
2417 bool ServerMap::loadSectorFull(v2s16 p2d)
2418 {
2419         DSTACK(__FUNCTION_NAME);
2420         std::string sectorsubdir = getSectorSubDir(p2d);
2421
2422         MapSector *sector = NULL;
2423
2424         JMutexAutoLock lock(m_sector_mutex);
2425
2426         try{
2427                 sector = loadSectorMeta(sectorsubdir);
2428         }
2429         catch(InvalidFilenameException &e)
2430         {
2431                 return false;
2432         }
2433         catch(FileNotGoodException &e)
2434         {
2435                 return false;
2436         }
2437         catch(std::exception &e)
2438         {
2439                 return false;
2440         }
2441
2442         if(ENABLE_BLOCK_LOADING)
2443         {
2444                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
2445                                 (m_savedir+"/sectors/"+sectorsubdir);
2446                 std::vector<fs::DirListNode>::iterator i2;
2447                 for(i2=list2.begin(); i2!=list2.end(); i2++)
2448                 {
2449                         // We want files
2450                         if(i2->dir)
2451                                 continue;
2452                         try{
2453                                 loadBlock(sectorsubdir, i2->name, sector);
2454                         }
2455                         catch(InvalidFilenameException &e)
2456                         {
2457                                 // This catches unknown crap in directory
2458                         }
2459                 }
2460         }
2461         return true;
2462 }
2463
2464 #if 0
2465 bool ServerMap::deFlushSector(v2s16 p2d)
2466 {
2467         DSTACK(__FUNCTION_NAME);
2468         // See if it already exists in memory
2469         try{
2470                 MapSector *sector = getSectorNoGenerate(p2d);
2471                 return true;
2472         }
2473         catch(InvalidPositionException &e)
2474         {
2475                 /*
2476                         Try to load the sector from disk.
2477                 */
2478                 if(loadSectorFull(p2d) == true)
2479                 {
2480                         return true;
2481                 }
2482         }
2483         return false;
2484 }
2485 #endif
2486
2487 void ServerMap::saveBlock(MapBlock *block)
2488 {
2489         DSTACK(__FUNCTION_NAME);
2490         /*
2491                 Dummy blocks are not written
2492         */
2493         if(block->isDummy())
2494         {
2495                 /*v3s16 p = block->getPos();
2496                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
2497                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2498                 return;
2499         }
2500
2501         // Format used for writing
2502         u8 version = SER_FMT_VER_HIGHEST;
2503         // Get destination
2504         v3s16 p3d = block->getPos();
2505         v2s16 p2d(p3d.X, p3d.Z);
2506         createDir(m_savedir);
2507         createDir(m_savedir+"/sectors");
2508         std::string dir = getSectorDir(p2d);
2509         createDir(dir);
2510         
2511         // Block file is map/sectors/xxxxxxxx/xxxx
2512         char cc[5];
2513         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
2514         std::string fullpath = dir + "/" + cc;
2515         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2516         if(o.good() == false)
2517                 throw FileNotGoodException("Cannot open block data");
2518
2519         /*
2520                 [0] u8 serialization version
2521                 [1] data
2522         */
2523         o.write((char*)&version, 1);
2524         
2525         block->serialize(o, version);
2526
2527         /*
2528                 Versions up from 9 have block objects.
2529         */
2530         if(version >= 9)
2531         {
2532                 block->serializeObjects(o, version);
2533         }
2534         
2535         // We just wrote it to the disk
2536         block->resetChangedFlag();
2537 }
2538
2539 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
2540 {
2541         DSTACK(__FUNCTION_NAME);
2542
2543         try{
2544
2545         // Block file is map/sectors/xxxxxxxx/xxxx
2546         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
2547         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2548         if(is.good() == false)
2549                 throw FileNotGoodException("Cannot open block file");
2550
2551         v3s16 p3d = getBlockPos(sectordir, blockfile);
2552         v2s16 p2d(p3d.X, p3d.Z);
2553         
2554         assert(sector->getPos() == p2d);
2555         
2556         u8 version = SER_FMT_VER_INVALID;
2557         is.read((char*)&version, 1);
2558
2559         /*u32 block_size = MapBlock::serializedLength(version);
2560         SharedBuffer<u8> data(block_size);
2561         is.read((char*)*data, block_size);*/
2562
2563         // This will always return a sector because we're the server
2564         //MapSector *sector = emergeSector(p2d);
2565
2566         MapBlock *block = NULL;
2567         bool created_new = false;
2568         try{
2569                 block = sector->getBlockNoCreate(p3d.Y);
2570         }
2571         catch(InvalidPositionException &e)
2572         {
2573                 block = sector->createBlankBlockNoInsert(p3d.Y);
2574                 created_new = true;
2575         }
2576         
2577         // deserialize block data
2578         block->deSerialize(is, version);
2579         
2580         /*
2581                 Versions up from 9 have block objects.
2582         */
2583         if(version >= 9)
2584         {
2585                 block->updateObjects(is, version, NULL);
2586         }
2587
2588         if(created_new)
2589                 sector->insertBlock(block);
2590         
2591         /*
2592                 Convert old formats to new and save
2593         */
2594
2595         // Save old format blocks in new format
2596         if(version < SER_FMT_VER_HIGHEST)
2597         {
2598                 saveBlock(block);
2599         }
2600         
2601         // We just loaded it from the disk, so it's up-to-date.
2602         block->resetChangedFlag();
2603
2604         }
2605         catch(SerializationError &e)
2606         {
2607                 dstream<<"WARNING: Invalid block data on disk "
2608                                 "(SerializationError). Ignoring."
2609                                 <<std::endl;
2610         }
2611 }
2612
2613 // Gets from master heightmap
2614 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
2615 {
2616         assert(m_heightmap != NULL);
2617         /*
2618                 Corner definition:
2619                 v2s16(0,0),
2620                 v2s16(1,0),
2621                 v2s16(1,1),
2622                 v2s16(0,1),
2623         */
2624         corners[0] = m_heightmap->getGroundHeight
2625                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
2626         corners[1] = m_heightmap->getGroundHeight
2627                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
2628         corners[2] = m_heightmap->getGroundHeight
2629                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
2630         corners[3] = m_heightmap->getGroundHeight
2631                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
2632 }
2633
2634 void ServerMap::PrintInfo(std::ostream &out)
2635 {
2636         out<<"ServerMap: ";
2637 }
2638
2639 /*
2640         ClientMap
2641 */
2642
2643 ClientMap::ClientMap(
2644                 Client *client,
2645                 video::SMaterial *materials,
2646                 scene::ISceneNode* parent,
2647                 scene::ISceneManager* mgr,
2648                 s32 id
2649 ):
2650         Map(dout_client),
2651         scene::ISceneNode(parent, mgr, id),
2652         m_client(client),
2653         m_materials(materials),
2654         mesh(NULL)
2655 {
2656         /*m_box = core::aabbox3d<f32>(0,0,0,
2657                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
2658         /*m_box = core::aabbox3d<f32>(0,0,0,
2659                         map->getSizeNodes().X * BS,
2660                         map->getSizeNodes().Y * BS,
2661                         map->getSizeNodes().Z * BS);*/
2662         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
2663                         BS*1000000,BS*1000000,BS*1000000);
2664
2665         mesh_mutex.Init();
2666 }
2667
2668 ClientMap::~ClientMap()
2669 {
2670         JMutexAutoLock lock(mesh_mutex);
2671         
2672         if(mesh != NULL)
2673         {
2674                 mesh->drop();
2675                 mesh = NULL;
2676         }
2677 }
2678
2679 MapSector * ClientMap::emergeSector(v2s16 p2d)
2680 {
2681         DSTACK(__FUNCTION_NAME);
2682         // Check that it doesn't exist already
2683         try{
2684                 return getSectorNoGenerate(p2d);
2685         }
2686         catch(InvalidPositionException &e)
2687         {
2688         }
2689         
2690         // Create a sector with no heightmaps
2691         ClientMapSector *sector = new ClientMapSector(this, p2d);
2692         
2693         {
2694                 JMutexAutoLock lock(m_sector_mutex);
2695                 m_sectors.insert(p2d, sector);
2696         }
2697         
2698         return sector;
2699 }
2700
2701 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
2702 {
2703         DSTACK(__FUNCTION_NAME);
2704         ClientMapSector *sector = NULL;
2705
2706         JMutexAutoLock lock(m_sector_mutex);
2707         
2708         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
2709
2710         if(n != NULL)
2711         {
2712                 sector = (ClientMapSector*)n->getValue();
2713                 assert(sector->getId() == MAPSECTOR_CLIENT);
2714         }
2715         else
2716         {
2717                 sector = new ClientMapSector(this, p2d);
2718                 {
2719                         JMutexAutoLock lock(m_sector_mutex);
2720                         m_sectors.insert(p2d, sector);
2721                 }
2722         }
2723
2724         sector->deSerialize(is);
2725 }
2726
2727 void ClientMap::renderMap(video::IVideoDriver* driver,
2728         video::SMaterial *materials, s32 pass)
2729 {
2730         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
2731         DSTACK(__FUNCTION_NAME);
2732
2733         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
2734 #if 0
2735         /*
2736                 Draw master heightmap mesh
2737         */
2738         
2739         {
2740                 JMutexAutoLock lock(mesh_mutex);
2741                 if(mesh != NULL)
2742                 {
2743                         u32 c = mesh->getMeshBufferCount();
2744
2745                         for(u32 i=0; i<c; i++)
2746                         {
2747                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
2748                                 const video::SMaterial& material = buf->getMaterial();
2749                                 video::IMaterialRenderer* rnd =
2750                                                 driver->getMaterialRenderer(material.MaterialType);
2751                                 bool transparent = (rnd && rnd->isTransparent());
2752                                 // Render transparent on transparent pass and likewise.
2753                                 if(transparent == is_transparent_pass)
2754                                 {
2755                                         driver->setMaterial(buf->getMaterial());
2756                                         driver->drawMeshBuffer(buf);
2757                                 }
2758                         }
2759                 }
2760         }
2761 #endif
2762
2763         /*
2764                 Get time for measuring timeout.
2765                 
2766                 Measuring time is very useful for long delays when the
2767                 machine is swapping a lot.
2768         */
2769         int time1 = time(0);
2770
2771         /*
2772                 Collect all blocks that are in the view range
2773
2774                 Should not optimize more here as we want to auto-update
2775                 all changed nodes in viewing range at the next step.
2776         */
2777
2778         s16 viewing_range_nodes;
2779         bool viewing_range_all;
2780         {
2781                 JMutexAutoLock lock(g_range_mutex);
2782                 viewing_range_nodes = g_viewing_range_nodes;
2783                 viewing_range_all = g_viewing_range_all;
2784         }
2785
2786         m_camera_mutex.Lock();
2787         v3f camera_position = m_camera_position;
2788         v3f camera_direction = m_camera_direction;
2789         m_camera_mutex.Unlock();
2790
2791         /*
2792                 Get all blocks and draw all visible ones
2793         */
2794
2795         v3s16 cam_pos_nodes(
2796                         camera_position.X / BS,
2797                         camera_position.Y / BS,
2798                         camera_position.Z / BS);
2799
2800         v3s16 box_nodes_d = viewing_range_nodes * v3s16(1,1,1);
2801
2802         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2803         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2804
2805         // Take a fair amount as we will be dropping more out later
2806         v3s16 p_blocks_min(
2807                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2808                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2809                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2810         v3s16 p_blocks_max(
2811                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2812                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2813                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2814         
2815         u32 vertex_count = 0;
2816         
2817         core::map<v2s16, MapSector*>::Iterator si;
2818
2819         //NOTE: The sectors map should be locked but we're not doing it
2820         // because it'd cause too much delays
2821
2822         si = m_sectors.getIterator();
2823         for(; si.atEnd() == false; si++)
2824         {
2825                 {
2826                         static int timecheck_counter = 0;
2827                         timecheck_counter++;
2828                         if(timecheck_counter > 50)
2829                         {
2830                                 int time2 = time(0);
2831                                 if(time2 > time1 + 4)
2832                                 {
2833                                         dstream<<"ClientMap::renderMap(): "
2834                                                 "Rendering takes ages, returning."
2835                                                 <<std::endl;
2836                                         return;
2837                                 }
2838                         }
2839                 }
2840
2841                 MapSector *sector = si.getNode()->getValue();
2842                 v2s16 sp = sector->getPos();
2843                 
2844                 if(viewing_range_all == false)
2845                 {
2846                         if(sp.X < p_blocks_min.X
2847                         || sp.X > p_blocks_max.X
2848                         || sp.Y < p_blocks_min.Z
2849                         || sp.Y > p_blocks_max.Z)
2850                                 continue;
2851                 }
2852
2853                 core::list< MapBlock * > sectorblocks;
2854                 sector->getBlocks(sectorblocks);
2855                 
2856                 /*
2857                         Draw blocks
2858                 */
2859
2860                 core::list< MapBlock * >::Iterator i;
2861                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
2862                 {
2863                         MapBlock *block = *i;
2864
2865                         /*
2866                                 Compare block position to camera position, skip
2867                                 if not seen on display
2868                         */
2869                         
2870                         v3s16 blockpos_nodes = block->getPosRelative();
2871                         
2872                         // Block center position
2873                         v3f blockpos(
2874                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
2875                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
2876                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
2877                         );
2878
2879                         // Block position relative to camera
2880                         v3f blockpos_relative = blockpos - camera_position;
2881
2882                         // Distance in camera direction (+=front, -=back)
2883                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
2884
2885                         // Total distance
2886                         f32 d = blockpos_relative.getLength();
2887                         
2888                         if(viewing_range_all == false)
2889                         {
2890                                 // If block is far away, don't draw it
2891                                 if(d > viewing_range_nodes * BS)
2892                                         continue;
2893                         }
2894                         
2895                         // Maximum radius of a block
2896                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
2897                         
2898                         // If block is (nearly) touching the camera, don't
2899                         // bother validating further (that is, render it anyway)
2900                         if(d > block_max_radius * 1.5)
2901                         {
2902                                 // Cosine of the angle between the camera direction
2903                                 // and the block direction (camera_direction is an unit vector)
2904                                 f32 cosangle = dforward / d;
2905                                 
2906                                 // Compensate for the size of the block
2907                                 // (as the block has to be shown even if it's a bit off FOV)
2908                                 // This is an estimate.
2909                                 cosangle += block_max_radius / dforward;
2910
2911                                 // If block is not in the field of view, skip it
2912                                 //if(cosangle < cos(FOV_ANGLE/2))
2913                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
2914                                         continue;
2915                         }
2916                         
2917                         /*
2918                                 Draw the faces of the block
2919                         */
2920                         
2921                         {
2922                                 JMutexAutoLock lock(block->mesh_mutex);
2923
2924                                 // Cancel if block has no mesh
2925                                 if(block->mesh == NULL)
2926                                         continue;
2927
2928                                 u32 c = block->mesh->getMeshBufferCount();
2929
2930                                 for(u32 i=0; i<c; i++)
2931                                 {
2932                                         scene::IMeshBuffer *buf = block->mesh->getMeshBuffer(i);
2933                                         const video::SMaterial& material = buf->getMaterial();
2934                                         video::IMaterialRenderer* rnd =
2935                                                         driver->getMaterialRenderer(material.MaterialType);
2936                                         bool transparent = (rnd && rnd->isTransparent());
2937                                         // Render transparent on transparent pass and likewise.
2938                                         if(transparent == is_transparent_pass)
2939                                         {
2940                                                 driver->setMaterial(buf->getMaterial());
2941                                                 driver->drawMeshBuffer(buf);
2942                                                 vertex_count += buf->getVertexCount();
2943                                         }
2944                                 }
2945                         }
2946                 } // foreach sectorblocks
2947         }
2948
2949         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
2950                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
2951 }
2952
2953 void ClientMap::updateMesh()
2954 {
2955 #if 0
2956         DSTACK(__FUNCTION_NAME);
2957         //TODO
2958         /*
2959                 Check what sectors don't draw anything useful at ground level
2960                 and create a mesh of the rough heightmap at those positions.
2961         */
2962
2963         m_camera_mutex.Lock();
2964         v3f camera_position = m_camera_position;
2965         v3f camera_direction = m_camera_direction;
2966         m_camera_mutex.Unlock();
2967
2968         v3s16 cam_pos_nodes(
2969                         camera_position.X / BS,
2970                         camera_position.Y / BS,
2971                         camera_position.Z / BS);
2972
2973         v3s16 box_nodes_d = HEIGHTMAP_RANGE_NODES * v3s16(1,1,1);
2974
2975         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2976         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2977
2978         // Take a fair amount as we will be dropping more out later
2979         v3s16 p_blocks_min(
2980                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2981                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2982                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2983         v3s16 p_blocks_max(
2984                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2985                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2986                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2987         
2988         /*
2989                 Initialize new mesh
2990         */
2991         
2992         scene::SMesh *mesh_new = new scene::SMesh();
2993         //scene::IMeshBuffer *buf = NULL;
2994         scene::SMeshBuffer *buf = NULL;
2995
2996         u8 material_in_use = 0;
2997
2998         /*
2999                 Loop through sectors
3000         */
3001         
3002         for(core::map<v2s16, MapSector*>::Iterator
3003                         si = m_sectors.getIterator();
3004                         si.atEnd() == false; si++)
3005         {
3006                 MapSector *sector = si.getNode()->getValue();
3007                 
3008                 if(sector->getId() != MAPSECTOR_CLIENT)
3009                 {
3010                         dstream<<"WARNING: Client has a non-client sector"
3011                                         <<std::endl;
3012                         continue;
3013                 }
3014                 
3015                 ClientMapSector *cs = (ClientMapSector*)sector;
3016
3017                 v2s16 sp = sector->getPos();
3018
3019                 if(sp.X < p_blocks_min.X
3020                 || sp.X > p_blocks_max.X
3021                 || sp.Y < p_blocks_min.Z
3022                 || sp.Y > p_blocks_max.Z)
3023                         continue;
3024                 
3025                 /*
3026                         Get some ground level info
3027                 */
3028                 
3029                 s16 a = -5;
3030
3031                 s16 cn[4] = 
3032                 {
3033                         cs->getCorner(0)+a,
3034                         cs->getCorner(1)+a,
3035                         cs->getCorner(2)+a,
3036                         cs->getCorner(3)+a,
3037                 };
3038                 s16 cn_avg = (cn[0]+cn[1]+cn[2]+cn[3])/4;
3039                 s16 cn_min = 32767;
3040                 s16 cn_max = -32768;
3041                 for(s16 i=0; i<4; i++)
3042                 {
3043                         if(cn[i] < cn_min)
3044                                 cn_min = cn[i];
3045                         if(cn[i] > cn_max)
3046                                 cn_max = cn[i];
3047                 }
3048                 s16 cn_slope = cn_max - cn_min;
3049                 
3050                 /*
3051                         Generate this part of the heightmap mesh
3052                 */
3053
3054                 u8 material;
3055                 if(cn_avg + MAP_BLOCKSIZE/4 <= WATER_LEVEL)
3056                         material = 0;
3057                 else if(cn_slope <= MAP_BLOCKSIZE)
3058                         material = 1;
3059                 else
3060                         material = 2;
3061
3062                 if(material != material_in_use || buf == NULL)
3063                 {
3064                         // Try to get a meshbuffer associated with the material
3065                         buf = (scene::SMeshBuffer*)mesh_new->getMeshBuffer
3066                                         (g_mesh_materials[material]);
3067                         // If not found, create one
3068                         if(buf == NULL)
3069                         {
3070                                 // This is a "Standard MeshBuffer",
3071                                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
3072                                 buf = new scene::SMeshBuffer();
3073
3074                                 // Set material
3075                                 buf->Material = g_mesh_materials[material];
3076                                 // Use VBO
3077                                 //buf->setHardwareMappingHint(scene::EHM_STATIC);
3078                                 // Add to mesh
3079                                 mesh_new->addMeshBuffer(buf);
3080                                 // Mesh grabbed it
3081                                 buf->drop();
3082                         }
3083                         material_in_use = material;
3084                 }
3085
3086                 // Sector side width in floating-point units
3087                 f32 sd = BS * MAP_BLOCKSIZE;
3088                 // Sector position in global floating-point units
3089                 v3f spf = v3f((f32)sp.X, 0, (f32)sp.Y) * sd;
3090
3091                 //video::SColor c(255,255,255,255);
3092                 u8 cc = 180;
3093                 video::SColor c(255,cc,cc,cc);
3094                 
3095                 video::S3DVertex vertices[4] =
3096                 {
3097                         video::S3DVertex(spf.X,   (f32)BS*cn[0],spf.Z,   0,0,0, c, 0,1),
3098                         video::S3DVertex(spf.X+sd,(f32)BS*cn[1],spf.Z,   0,0,0, c, 1,1),
3099                         video::S3DVertex(spf.X+sd,(f32)BS*cn[2],spf.Z+sd,0,0,0, c, 1,0),
3100                         video::S3DVertex(spf.X,   (f32)BS*cn[3],spf.Z+sd,0,0,0, c, 0,0),
3101                 };
3102                 u16 indices[] = {0,1,2,2,3,0};
3103                 
3104                 buf->append(vertices, 4, indices, 6);
3105         }
3106         
3107         // Set VBO on
3108         //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
3109
3110         /*
3111                 Replace the mesh
3112         */
3113
3114         mesh_mutex.Lock();
3115
3116         scene::SMesh *mesh_old = mesh;
3117
3118         //DEBUG
3119         /*mesh = NULL;
3120         mesh_new->drop();*/
3121         mesh = mesh_new;
3122         
3123         mesh_mutex.Unlock();
3124
3125         if(mesh_old != NULL)
3126         {
3127                 /*dstream<<"mesh_old refcount="<<mesh_old->getReferenceCount()
3128                                 <<std::endl;
3129                 scene::IMeshBuffer *buf = mesh_new->getMeshBuffer
3130                                 (g_materials[MATERIAL_GRASS]);
3131                 if(buf != NULL)
3132                         dstream<<"grass buf refcount="<<buf->getReferenceCount()
3133                                         <<std::endl;*/
3134
3135                 mesh_old->drop();
3136         }
3137         else
3138         {
3139                 dstream<<"WARNING: There was no old master heightmap mesh"<<std::endl;
3140         }
3141 #endif
3142 }
3143
3144 void ClientMap::PrintInfo(std::ostream &out)
3145 {
3146         out<<"ClientMap: ";
3147 }
3148
3149
3150 /*
3151         MapVoxelManipulator
3152 */
3153
3154 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3155 {
3156         m_map = map;
3157 }
3158
3159 MapVoxelManipulator::~MapVoxelManipulator()
3160 {
3161         dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3162                         <<std::endl;
3163 }
3164
3165 void MapVoxelManipulator::emerge(VoxelArea a)
3166 {
3167         TimeTaker timer1("emerge", g_device, &emerge_time);
3168
3169         // Units of these are MapBlocks
3170         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3171         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3172
3173         VoxelArea block_area_nodes
3174                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3175
3176         addArea(block_area_nodes);
3177
3178         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3179         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3180         for(s32 x=p_min.X; x<=p_max.X; x++)
3181         {
3182                 v3s16 p(x,y,z);
3183                 core::map<v3s16, bool>::Node *n;
3184                 n = m_loaded_blocks.find(p);
3185                 if(n != NULL)
3186                         continue;
3187                 
3188                 bool block_data_inexistent = false;
3189                 try
3190                 {
3191                         TimeTaker timer1("emerge load", g_device, &emerge_load_time);
3192
3193                         dstream<<"Loading block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3194                                         <<std::endl;
3195                         
3196                         MapBlock *block = m_map->getBlockNoCreate(p);
3197                         if(block->isDummy())
3198                                 block_data_inexistent = true;
3199                         else
3200                                 block->copyTo(*this);
3201                 }
3202                 catch(InvalidPositionException &e)
3203                 {
3204                         block_data_inexistent = true;
3205                 }
3206
3207                 if(block_data_inexistent)
3208                 {
3209                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3210                         // Fill with VOXELFLAG_INEXISTENT
3211                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3212                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3213                         {
3214                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3215                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3216                         }
3217                 }
3218
3219                 m_loaded_blocks.insert(p, true);
3220         }
3221
3222         //dstream<<"emerge done"<<std::endl;
3223 }
3224
3225 /*
3226         TODO: Add an option to only update eg. water and air nodes.
3227               This will make it interfere less with important stuff if
3228                   run on background.
3229 */
3230 void MapVoxelManipulator::blitBack
3231                 (core::map<v3s16, MapBlock*> & modified_blocks)
3232 {
3233         TimeTaker timer1("blitBack", g_device);
3234         
3235         /*
3236                 Initialize block cache
3237         */
3238         v3s16 blockpos_last;
3239         MapBlock *block = NULL;
3240         bool block_checked_in_modified = false;
3241
3242         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3243         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3244         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3245         {
3246                 v3s16 p(x,y,z);
3247
3248                 u8 f = m_flags[m_area.index(p)];
3249                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3250                         continue;
3251
3252                 MapNode &n = m_data[m_area.index(p)];
3253                         
3254                 v3s16 blockpos = getNodeBlockPos(p);
3255                 
3256                 try
3257                 {
3258                         // Get block
3259                         if(block == NULL || blockpos != blockpos_last){
3260                                 block = m_map->getBlockNoCreate(blockpos);
3261                                 blockpos_last = blockpos;
3262                                 block_checked_in_modified = false;
3263                         }
3264                         
3265                         // Calculate relative position in block
3266                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3267
3268                         // Don't continue if nothing has changed here
3269                         if(block->getNode(relpos) == n)
3270                                 continue;
3271
3272                         //m_map->setNode(m_area.MinEdge + p, n);
3273                         block->setNode(relpos, n);
3274                         
3275                         /*
3276                                 Make sure block is in modified_blocks
3277                         */
3278                         if(block_checked_in_modified == false)
3279                         {
3280                                 modified_blocks[blockpos] = block;
3281                                 block_checked_in_modified = true;
3282                         }
3283                 }
3284                 catch(InvalidPositionException &e)
3285                 {
3286                 }
3287         }
3288 }
3289
3290 //END