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