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