8bc914cfd82221f172a53c7be1fc881805727287
[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(1.0, 0.2, corners);
1508                 //hm->generateContinued(2.0, 0.2, corners);
1509
1510                 //hm->print();
1511                 
1512         }
1513
1514         /*
1515                 Generate objects
1516         */
1517         
1518         core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
1519         sector->setObjects(objects);
1520         
1521         v2s16 mhm_p = p2d * hm_split;
1522         f32 corners[4] = {
1523                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split),
1524                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split),
1525                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split),
1526                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split),
1527         };
1528         
1529         float avgheight = (corners[0]+corners[1]+corners[2]+corners[3])/4.0;
1530         float avgslope = 0.0;
1531         avgslope += fabs(avgheight - corners[0]);
1532         avgslope += fabs(avgheight - corners[1]);
1533         avgslope += fabs(avgheight - corners[2]);
1534         avgslope += fabs(avgheight - corners[3]);
1535         avgslope /= 4.0;
1536         avgslope /= MAP_BLOCKSIZE;
1537         //dstream<<"avgslope="<<avgslope<<std::endl;
1538
1539         float pitness = 0.0;
1540         v2f32 a;
1541         a = m_heightmap->getSlope(p2d+v2s16(0,0));
1542         pitness += -a.X;
1543         pitness += -a.Y;
1544         a = m_heightmap->getSlope(p2d+v2s16(0,1));
1545         pitness += -a.X;
1546         pitness += a.Y;
1547         a = m_heightmap->getSlope(p2d+v2s16(1,1));
1548         pitness += a.X;
1549         pitness += a.Y;
1550         a = m_heightmap->getSlope(p2d+v2s16(1,0));
1551         pitness += a.X;
1552         pitness += -a.Y;
1553         pitness /= 4.0;
1554         pitness /= MAP_BLOCKSIZE;
1555         //dstream<<"pitness="<<pitness<<std::endl;
1556         
1557         /*
1558                 Plant some trees if there is not much slope
1559         */
1560         {
1561                 // Avgslope is the derivative of a hill
1562                 float t = avgslope * avgslope;
1563                 float a = MAP_BLOCKSIZE * m_params.plants_amount;
1564                 u32 tree_max;
1565                 if(t > 0.03)
1566                         tree_max = a / (t/0.03);
1567                 else
1568                         tree_max = a;
1569                 u32 count = (rand()%(tree_max+1));
1570                 //u32 count = tree_max;
1571                 for(u32 i=0; i<count; i++)
1572                 {
1573                         s16 x = (rand()%(MAP_BLOCKSIZE-2))+1;
1574                         s16 z = (rand()%(MAP_BLOCKSIZE-2))+1;
1575                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1576                         if(y < WATER_LEVEL)
1577                                 continue;
1578                         objects->insert(v3s16(x, y, z),
1579                                         SECTOR_OBJECT_TREE_1);
1580                 }
1581         }
1582         /*
1583                 Plant some bushes if sector is pit-like
1584         */
1585         {
1586                 // Pitness usually goes at around -0.5...0.5
1587                 u32 bush_max = 0;
1588                 u32 a = MAP_BLOCKSIZE * 3.0 * m_params.plants_amount;
1589                 if(pitness > 0)
1590                         bush_max = (pitness*a*4);
1591                 if(bush_max > a)
1592                         bush_max = a;
1593                 u32 count = (rand()%(bush_max+1));
1594                 for(u32 i=0; i<count; i++)
1595                 {
1596                         s16 x = rand()%(MAP_BLOCKSIZE-0)+0;
1597                         s16 z = rand()%(MAP_BLOCKSIZE-0)+0;
1598                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1599                         if(y < WATER_LEVEL)
1600                                 continue;
1601                         objects->insert(v3s16(x, y, z),
1602                                         SECTOR_OBJECT_BUSH_1);
1603                 }
1604         }
1605         /*
1606                 Add ravine (randomly)
1607         */
1608         if(m_params.ravines_amount != 0)
1609         {
1610                 if(rand()%(s32)(20.0 / m_params.ravines_amount) == 0)
1611                 {
1612                         s16 s = 6;
1613                         s16 x = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
1614                         s16 z = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
1615                         /*s16 x = 8;
1616                         s16 z = 8;*/
1617                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1618                         objects->insert(v3s16(x, y, z),
1619                                         SECTOR_OBJECT_RAVINE);
1620                 }
1621         }
1622
1623         /*
1624                 Insert to container
1625         */
1626         JMutexAutoLock lock(m_sector_mutex);
1627         m_sectors.insert(p2d, sector);
1628         
1629         return sector;
1630 }
1631
1632 MapBlock * ServerMap::emergeBlock(
1633                 v3s16 p,
1634                 bool only_from_disk,
1635                 core::map<v3s16, MapBlock*> &changed_blocks,
1636                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
1637 )
1638 {
1639         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
1640                         __FUNCTION_NAME,
1641                         p.X, p.Y, p.Z, only_from_disk);
1642                         
1643         /*dstream<<"ServerMap::emergeBlock(): "
1644                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1645                         <<", only_from_disk="<<only_from_disk<<std::endl;*/
1646         v2s16 p2d(p.X, p.Z);
1647         s16 block_y = p.Y;
1648         /*
1649                 This will create or load a sector if not found in memory.
1650                 If block exists on disk, it will be loaded.
1651
1652                 NOTE: On old save formats, this will be slow, as it generates
1653                       lighting on blocks for them.
1654         */
1655         ServerMapSector *sector = (ServerMapSector*)emergeSector(p2d);
1656         assert(sector->getId() == MAPSECTOR_SERVER);
1657
1658         // Try to get a block from the sector
1659         MapBlock *block = NULL;
1660         bool not_on_disk = false;
1661         try{
1662                 block = sector->getBlockNoCreate(block_y);
1663                 if(block->isDummy() == true)
1664                         not_on_disk = true;
1665                 else
1666                         return block;
1667         }
1668         catch(InvalidPositionException &e)
1669         {
1670                 not_on_disk = true;
1671         }
1672         
1673         /*
1674                 If block was not found on disk and not going to generate a
1675                 new one, make sure there is a dummy block in place.
1676         */
1677         if(not_on_disk && only_from_disk)
1678         {
1679                 if(block == NULL)
1680                 {
1681                         // Create dummy block
1682                         block = new MapBlock(this, p, true);
1683
1684                         // Add block to sector
1685                         sector->insertBlock(block);
1686                 }
1687                 // Done.
1688                 return block;
1689         }
1690
1691         //dstream<<"Not found on disk, generating."<<std::endl;
1692
1693         /*
1694                 Do not generate over-limit
1695         */
1696         if(blockpos_over_limit(p))
1697                 throw InvalidPositionException("emergeBlock(): pos. over limit");
1698
1699         /*
1700                 OK; Not found.
1701
1702                 Go on generating the block.
1703
1704                 TODO: If a dungeon gets generated so that it's side gets
1705                       revealed to the outside air, the lighting should be
1706                           recalculated.
1707         */
1708         
1709         /*
1710                 If block doesn't exist, create one.
1711                 If it exists, it is a dummy. In that case unDummify() it.
1712         */
1713         if(block == NULL)
1714         {
1715                 block = sector->createBlankBlockNoInsert(block_y);
1716         }
1717         else
1718         {
1719                 // Remove the block so that nobody can get a half-generated one.
1720                 sector->removeBlock(block);
1721                 // Allocate the block to be a proper one.
1722                 block->unDummify();
1723         }
1724
1725         // Randomize a bit. This makes dungeons.
1726         /*bool low_block_is_empty = false;
1727         if(rand() % 4 == 0)
1728                 low_block_is_empty = true;*/
1729         
1730         const s32 ued = 4;
1731         //const s32 ued = 8;
1732         bool underground_emptiness[ued*ued*ued];
1733         for(s32 i=0; i<ued*ued*ued; i++)
1734         {
1735                 underground_emptiness[i] = ((rand() % 5) == 0);
1736         }
1737
1738 #if 0
1739         /*
1740                 This is a messy hack to sort the emptiness a bit
1741         */
1742         for(s32 j=0; j<2; j++)
1743         for(s32 y0=0; y0<ued; y0++)
1744         for(s32 z0=0; z0<ued; z0++)
1745         for(s32 x0=0; x0<ued; x0++)
1746         {
1747                 v3s16 p0(x0,y0,z0);
1748                 bool &e0 = underground_emptiness[
1749                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1750                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1751                                 +(x0*ued/MAP_BLOCKSIZE)];
1752                                 
1753                 v3s16 dirs[6] = {
1754                         v3s16(0,0,1), // back
1755                         v3s16(1,0,0), // right
1756                         v3s16(0,0,-1), // front
1757                         v3s16(-1,0,0), // left
1758                         /*v3s16(0,1,0), // top
1759                         v3s16(0,-1,0), // bottom*/
1760                 };
1761                 for(s32 i=0; i<4; i++)
1762                 {
1763                         v3s16 p1 = p0 + dirs[i];
1764                         if(isInArea(p1, ued) == false)
1765                                 continue;
1766                         bool &e1 = underground_emptiness[
1767                                         ued*ued*(p1.Z*ued/MAP_BLOCKSIZE)
1768                                         +ued*(p1.Y*ued/MAP_BLOCKSIZE)
1769                                         +(p1.X*ued/MAP_BLOCKSIZE)];
1770                         if(e0 == e1)
1771                                 continue;
1772                                 
1773                         v3s16 dirs[6] = {
1774                                 v3s16(0,1,0), // top
1775                                 v3s16(0,-1,0), // bottom
1776                                 /*v3s16(0,0,1), // back
1777                                 v3s16(1,0,0), // right
1778                                 v3s16(0,0,-1), // front
1779                                 v3s16(-1,0,0), // left*/
1780                         };
1781                         for(s32 i=0; i<2; i++)
1782                         {
1783                                 v3s16 p2 = p1 + dirs[i];
1784                                 if(p2 == p0)
1785                                         continue;
1786                                 if(isInArea(p2, ued) == false)
1787                                         continue;
1788                                 bool &e2 = underground_emptiness[
1789                                                 ued*ued*(p2.Z*ued/MAP_BLOCKSIZE)
1790                                                 +ued*(p2.Y*ued/MAP_BLOCKSIZE)
1791                                                 +(p2.X*ued/MAP_BLOCKSIZE)];
1792                                 if(e2 != e0)
1793                                         continue;
1794                                 
1795                                 bool t = e1;
1796                                 e1 = e2;
1797                                 e2 = t;
1798
1799                                 break;
1800                         }
1801                         //break;
1802                 }
1803         }
1804 #endif
1805         
1806         // This is the basic material of what the visible flat ground
1807         // will consist of
1808         u8 material = CONTENT_GRASS;
1809
1810         u8 water_material = CONTENT_WATER;
1811         if(g_settings.getBool("endless_water"))
1812                 water_material = CONTENT_OCEAN;
1813         
1814         s32 lowest_ground_y = 32767;
1815         s32 highest_ground_y = -32768;
1816         
1817         // DEBUG
1818         //sector->printHeightmaps();
1819
1820         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1821         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1822         {
1823                 //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
1824
1825                 float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
1826                 //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
1827                 if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE)
1828                 {
1829                         dstream<<"WARNING: Surface height not found in sector "
1830                                         "for block that is being emerged"<<std::endl;
1831                         surface_y_f = 0.0;
1832                 }
1833
1834                 s16 surface_y = surface_y_f;
1835                 //avg_ground_y += surface_y;
1836                 if(surface_y < lowest_ground_y)
1837                         lowest_ground_y = surface_y;
1838                 if(surface_y > highest_ground_y)
1839                         highest_ground_y = surface_y;
1840
1841                 s32 surface_depth = 0;
1842                 
1843                 float slope = sector->getSlope(v2s16(x0,z0)).getLength();
1844                 
1845                 //float min_slope = 0.45;
1846                 //float max_slope = 0.85;
1847                 float min_slope = 0.70;
1848                 float max_slope = 1.20;
1849                 float min_slope_depth = 4.0;
1850                 //float min_slope_depth = 5.0;
1851                 float max_slope_depth = 0;
1852                 if(slope < min_slope)
1853                         surface_depth = min_slope_depth;
1854                 else if(slope > max_slope)
1855                         surface_depth = max_slope_depth;
1856                 else
1857                         surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
1858
1859                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1860                 {
1861                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
1862                         MapNode n;
1863                         /*
1864                                 Calculate lighting
1865                                 
1866                                 NOTE: If there are some man-made structures above the
1867                                 newly created block, they won't be taken into account.
1868                         */
1869                         if(real_y > surface_y)
1870                                 n.setLight(LIGHT_SUN);
1871
1872                         /*
1873                                 Calculate material
1874                         */
1875
1876                         // If node is very low
1877                         /*if(real_y <= surface_y - 7)
1878                         {
1879                                 // Create dungeons
1880                                 if(underground_emptiness[
1881                                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1882                                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1883                                                 +(x0*ued/MAP_BLOCKSIZE)])
1884                                 {
1885                                         n.d = CONTENT_AIR;
1886                                 }
1887                                 else
1888                                 {
1889                                         n.d = CONTENT_STONE;
1890                                 }
1891                         }
1892                         // If node is under surface level
1893                         else if(real_y <= surface_y - surface_depth)
1894                                 n.d = CONTENT_STONE;
1895                         */
1896                         if(real_y <= surface_y - surface_depth)
1897                         {
1898                                 // Create dungeons
1899                                 if(underground_emptiness[
1900                                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1901                                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1902                                                 +(x0*ued/MAP_BLOCKSIZE)])
1903                                 {
1904                                         n.d = CONTENT_AIR;
1905                                 }
1906                                 else
1907                                 {
1908                                         n.d = CONTENT_STONE;
1909                                 }
1910                         }
1911                         // If node is at or under heightmap y
1912                         else if(real_y <= surface_y)
1913                         {
1914                                 // If under water level, it's mud
1915                                 if(real_y < WATER_LEVEL)
1916                                         n.d = CONTENT_MUD;
1917                                 // Only the topmost node is grass
1918                                 else if(real_y <= surface_y - 1)
1919                                         n.d = CONTENT_MUD;
1920                                 // Else it's the main material
1921                                 else
1922                                         n.d = material;
1923                         }
1924                         // If node is over heightmap y
1925                         else{
1926                                 // If under water level, it's water
1927                                 if(real_y < WATER_LEVEL)
1928                                 {
1929                                         n.d = water_material;
1930                                         n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
1931                                 }
1932                                 // else air
1933                                 else
1934                                         n.d = CONTENT_AIR;
1935                         }
1936                         block->setNode(v3s16(x0,y0,z0), n);
1937                 }
1938         }
1939
1940         /*
1941                 Calculate is_underground
1942         */
1943         // Probably underground if the highest part of block is under lowest
1944         // ground height
1945         bool is_underground = (block_y+1) * MAP_BLOCKSIZE <= lowest_ground_y;
1946         block->setIsUnderground(is_underground);
1947
1948         /*
1949                 Force lighting update if some part of block is underground
1950                 This is needed because of caves.
1951         */
1952         
1953         bool some_part_underground = (block_y+0) * MAP_BLOCKSIZE < highest_ground_y;
1954         if(some_part_underground)
1955         //if(is_underground)
1956         {
1957                 lighting_invalidated_blocks[block->getPos()] = block;
1958         }
1959         
1960         /*
1961                 Add some minerals
1962         */
1963
1964         //if(is_underground)
1965         if(some_part_underground)
1966         {
1967                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
1968                 for(s16 i=0; i<underground_level*3; i++)
1969                 {
1970                         if(rand()%2 == 0)
1971                         {
1972                                 v3s16 cp(
1973                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1974                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1975                                         (rand()%(MAP_BLOCKSIZE-2))+1
1976                                 );
1977
1978                                 MapNode n;
1979                                 n.d = CONTENT_MESE;
1980                                 
1981                                 //if(is_ground_content(block->getNode(cp).d))
1982                                 if(block->getNode(cp).d == CONTENT_STONE)
1983                                         if(rand()%8 == 0)
1984                                                 block->setNode(cp, n);
1985
1986                                 for(u16 i=0; i<26; i++)
1987                                 {
1988                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
1989                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
1990                                                 if(rand()%8 == 0)
1991                                                         block->setNode(cp+g_26dirs[i], n);
1992                                 }
1993                         }
1994                 }
1995         }
1996         
1997         /*
1998                 Create a few rats in empty blocks underground
1999         */
2000         if(is_underground)
2001         {
2002                 //for(u16 i=0; i<2; i++)
2003                 {
2004                         v3s16 cp(
2005                                 (rand()%(MAP_BLOCKSIZE-2))+1,
2006                                 (rand()%(MAP_BLOCKSIZE-2))+1,
2007                                 (rand()%(MAP_BLOCKSIZE-2))+1
2008                         );
2009
2010                         // Check that the place is empty
2011                         //if(!is_ground_content(block->getNode(cp).d))
2012                         if(1)
2013                         {
2014                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
2015                                 block->addObject(obj);
2016                         }
2017                 }
2018         }
2019         
2020         /*
2021                 Add block to sector.
2022         */
2023         sector->insertBlock(block);
2024         
2025         /*
2026                 Do some interpolation for dungeons
2027         */
2028
2029 #if 0   
2030         {
2031         TimeTaker timer("interpolation", g_device);
2032         
2033         MapVoxelManipulator vmanip(this);
2034         
2035         v3s16 relpos = block->getPosRelative();
2036
2037         vmanip.interpolate(VoxelArea(relpos-v3s16(1,1,1),
2038                         relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE+1)));
2039         /*vmanip.interpolate(VoxelArea(relpos,
2040                         relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE-1)));*/
2041         
2042         core::map<v3s16, MapBlock*> modified_blocks;
2043         vmanip.blitBack(modified_blocks);
2044         dstream<<"blitBack modified "<<modified_blocks.size()
2045                         <<" blocks"<<std::endl;
2046
2047         // Add modified blocks to changed_blocks and lighting_invalidated_blocks
2048         for(core::map<v3s16, MapBlock*>::Iterator
2049                         i = modified_blocks.getIterator();
2050                         i.atEnd() == false; i++)
2051         {
2052                 MapBlock *block = i.getNode()->getValue();
2053
2054                 changed_blocks.insert(block->getPos(), block);
2055                 //lighting_invalidated_blocks.insert(block->getPos(), block);
2056         }
2057
2058         }
2059 #endif
2060
2061         /*
2062                 Sector object stuff
2063         */
2064                 
2065         // An y-wise container of changed blocks
2066         core::map<s16, MapBlock*> changed_blocks_sector;
2067
2068         /*
2069                 Check if any sector's objects can be placed now.
2070                 If so, place them.
2071         */
2072         core::map<v3s16, u8> *objects = sector->getObjects();
2073         core::list<v3s16> objects_to_remove;
2074         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
2075                         i.atEnd() == false; i++)
2076         {
2077                 v3s16 p = i.getNode()->getKey();
2078                 v2s16 p2d(p.X,p.Z);
2079                 u8 d = i.getNode()->getValue();
2080
2081                 //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
2082                 
2083                 try
2084                 {
2085
2086                 if(d == SECTOR_OBJECT_TEST)
2087                 {
2088                         if(sector->isValidArea(p + v3s16(0,0,0),
2089                                         p + v3s16(0,0,0), &changed_blocks_sector))
2090                         {
2091                                 MapNode n;
2092                                 n.d = CONTENT_LIGHT;
2093                                 sector->setNode(p, n);
2094                                 objects_to_remove.push_back(p);
2095                         }
2096                 }
2097                 else if(d == SECTOR_OBJECT_TREE_1)
2098                 {
2099                         v3s16 p_min = p + v3s16(-1,0,-1);
2100                         v3s16 p_max = p + v3s16(1,4,1);
2101                         if(sector->isValidArea(p_min, p_max,
2102                                         &changed_blocks_sector))
2103                         {
2104                                 MapNode n;
2105                                 n.d = CONTENT_TREE;
2106                                 sector->setNode(p+v3s16(0,0,0), n);
2107                                 sector->setNode(p+v3s16(0,1,0), n);
2108                                 sector->setNode(p+v3s16(0,2,0), n);
2109                                 sector->setNode(p+v3s16(0,3,0), n);
2110
2111                                 n.d = CONTENT_LEAVES;
2112
2113                                 sector->setNode(p+v3s16(0,4,0), n);
2114                                 
2115                                 sector->setNode(p+v3s16(-1,4,0), n);
2116                                 sector->setNode(p+v3s16(1,4,0), n);
2117                                 sector->setNode(p+v3s16(0,4,-1), n);
2118                                 sector->setNode(p+v3s16(0,4,1), n);
2119                                 sector->setNode(p+v3s16(1,4,1), n);
2120                                 sector->setNode(p+v3s16(-1,4,1), n);
2121                                 sector->setNode(p+v3s16(-1,4,-1), n);
2122                                 sector->setNode(p+v3s16(1,4,-1), n);
2123
2124                                 sector->setNode(p+v3s16(-1,3,0), n);
2125                                 sector->setNode(p+v3s16(1,3,0), n);
2126                                 sector->setNode(p+v3s16(0,3,-1), n);
2127                                 sector->setNode(p+v3s16(0,3,1), n);
2128                                 sector->setNode(p+v3s16(1,3,1), n);
2129                                 sector->setNode(p+v3s16(-1,3,1), n);
2130                                 sector->setNode(p+v3s16(-1,3,-1), n);
2131                                 sector->setNode(p+v3s16(1,3,-1), n);
2132                                 
2133                                 objects_to_remove.push_back(p);
2134                                 
2135                                 // Lighting has to be recalculated for this one.
2136                                 sector->getBlocksInArea(p_min, p_max, 
2137                                                 lighting_invalidated_blocks);
2138                         }
2139                 }
2140                 else if(d == SECTOR_OBJECT_BUSH_1)
2141                 {
2142                         if(sector->isValidArea(p + v3s16(0,0,0),
2143                                         p + v3s16(0,0,0), &changed_blocks_sector))
2144                         {
2145                                 MapNode n;
2146                                 n.d = CONTENT_LEAVES;
2147                                 sector->setNode(p+v3s16(0,0,0), n);
2148                                 
2149                                 objects_to_remove.push_back(p);
2150                         }
2151                 }
2152                 else if(d == SECTOR_OBJECT_RAVINE)
2153                 {
2154                         s16 maxdepth = -20;
2155                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
2156                         v3s16 p_max = p + v3s16(6,6,6);
2157                         if(sector->isValidArea(p_min, p_max,
2158                                         &changed_blocks_sector))
2159                         {
2160                                 MapNode n;
2161                                 n.d = CONTENT_STONE;
2162                                 MapNode n2;
2163                                 n2.d = CONTENT_AIR;
2164                                 s16 depth = maxdepth + (rand()%10);
2165                                 s16 z = 0;
2166                                 s16 minz = -6 - (-2);
2167                                 s16 maxz = 6 -1;
2168                                 for(s16 x=-6; x<=6; x++)
2169                                 {
2170                                         z += -1 + (rand()%3);
2171                                         if(z < minz)
2172                                                 z = minz;
2173                                         if(z > maxz)
2174                                                 z = maxz;
2175                                         for(s16 y=depth+(rand()%2); y<=6; y++)
2176                                         {
2177                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
2178                                                                 <<std::endl;*/
2179                                                 {
2180                                                         v3s16 p2 = p + v3s16(x,y,z-2);
2181                                                         if(is_ground_content(sector->getNode(p2).d))
2182                                                                 sector->setNode(p2, n);
2183                                                 }
2184                                                 {
2185                                                         v3s16 p2 = p + v3s16(x,y,z-1);
2186                                                         if(is_ground_content(sector->getNode(p2).d))
2187                                                                 sector->setNode(p2, n2);
2188                                                 }
2189                                                 {
2190                                                         v3s16 p2 = p + v3s16(x,y,z+0);
2191                                                         if(is_ground_content(sector->getNode(p2).d))
2192                                                                 sector->setNode(p2, n2);
2193                                                 }
2194                                                 {
2195                                                         v3s16 p2 = p + v3s16(x,y,z+1);
2196                                                         if(is_ground_content(sector->getNode(p2).d))
2197                                                                 sector->setNode(p2, n);
2198                                                 }
2199
2200                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
2201                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
2202                                         }
2203                                 }
2204                                 
2205                                 objects_to_remove.push_back(p);
2206                                 
2207                                 // Lighting has to be recalculated for this one.
2208                                 sector->getBlocksInArea(p_min, p_max, 
2209                                                 lighting_invalidated_blocks);
2210                         }
2211                 }
2212                 else
2213                 {
2214                         dstream<<"ServerMap::emergeBlock(): "
2215                                         "Invalid heightmap object"
2216                                         <<std::endl;
2217                 }
2218
2219                 }//try
2220                 catch(InvalidPositionException &e)
2221                 {
2222                         dstream<<"WARNING: "<<__FUNCTION_NAME
2223                                         <<": while inserting object "<<(int)d
2224                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
2225                                         <<" InvalidPositionException.what()="
2226                                         <<e.what()<<std::endl;
2227                         // This is not too fatal and seems to happen sometimes.
2228                         assert(0);
2229                 }
2230         }
2231
2232         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
2233                         i != objects_to_remove.end(); i++)
2234         {
2235                 objects->remove(*i);
2236         }
2237
2238         for(core::map<s16, MapBlock*>::Iterator
2239                         i = changed_blocks_sector.getIterator();
2240                         i.atEnd() == false; i++)
2241         {
2242                 MapBlock *block = i.getNode()->getValue();
2243
2244                 changed_blocks.insert(block->getPos(), block);
2245         }
2246
2247         return block;
2248 }
2249
2250 void ServerMap::createDir(std::string path)
2251 {
2252         if(fs::CreateDir(path) == false)
2253         {
2254                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2255                                 <<"\""<<path<<"\""<<std::endl;
2256                 throw BaseException("ServerMap failed to create directory");
2257         }
2258 }
2259
2260 std::string ServerMap::getSectorSubDir(v2s16 pos)
2261 {
2262         char cc[9];
2263         snprintf(cc, 9, "%.4x%.4x",
2264                         (unsigned int)pos.X&0xffff,
2265                         (unsigned int)pos.Y&0xffff);
2266
2267         return std::string(cc);
2268 }
2269
2270 std::string ServerMap::getSectorDir(v2s16 pos)
2271 {
2272         return m_savedir + "/sectors/" + getSectorSubDir(pos);
2273 }
2274
2275 v2s16 ServerMap::getSectorPos(std::string dirname)
2276 {
2277         if(dirname.size() != 8)
2278                 throw InvalidFilenameException("Invalid sector directory name");
2279         unsigned int x, y;
2280         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
2281         if(r != 2)
2282                 throw InvalidFilenameException("Invalid sector directory name");
2283         v2s16 pos((s16)x, (s16)y);
2284         return pos;
2285 }
2286
2287 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2288 {
2289         v2s16 p2d = getSectorPos(sectordir);
2290
2291         if(blockfile.size() != 4){
2292                 throw InvalidFilenameException("Invalid block filename");
2293         }
2294         unsigned int y;
2295         int r = sscanf(blockfile.c_str(), "%4x", &y);
2296         if(r != 1)
2297                 throw InvalidFilenameException("Invalid block filename");
2298         return v3s16(p2d.X, y, p2d.Y);
2299 }
2300
2301 // Debug helpers
2302 #define ENABLE_SECTOR_SAVING 1
2303 #define ENABLE_SECTOR_LOADING 1
2304 #define ENABLE_BLOCK_SAVING 1
2305 #define ENABLE_BLOCK_LOADING 1
2306
2307 void ServerMap::save(bool only_changed)
2308 {
2309         DSTACK(__FUNCTION_NAME);
2310         if(m_map_saving_enabled == false)
2311         {
2312                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2313                 return;
2314         }
2315         
2316         if(only_changed == false)
2317                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2318                                 <<std::endl;
2319         
2320         saveMasterHeightmap();
2321         
2322         u32 sector_meta_count = 0;
2323         u32 block_count = 0;
2324         
2325         { //sectorlock
2326         JMutexAutoLock lock(m_sector_mutex);
2327         
2328         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2329         for(; i.atEnd() == false; i++)
2330         {
2331                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2332                 assert(sector->getId() == MAPSECTOR_SERVER);
2333                 
2334                 if(ENABLE_SECTOR_SAVING)
2335                 {
2336                         if(sector->differs_from_disk || only_changed == false)
2337                         {
2338                                 saveSectorMeta(sector);
2339                                 sector_meta_count++;
2340                         }
2341                 }
2342                 if(ENABLE_BLOCK_SAVING)
2343                 {
2344                         core::list<MapBlock*> blocks;
2345                         sector->getBlocks(blocks);
2346                         core::list<MapBlock*>::Iterator j;
2347                         for(j=blocks.begin(); j!=blocks.end(); j++)
2348                         {
2349                                 MapBlock *block = *j;
2350                                 if(block->getChangedFlag() || only_changed == false)
2351                                 {
2352                                         saveBlock(block);
2353                                         block_count++;
2354                                 }
2355                         }
2356                 }
2357         }
2358
2359         }//sectorlock
2360         
2361         u32 deleted_count = 0;
2362         deleted_count = deleteUnusedSectors
2363                         (SERVERMAP_DELETE_UNUSED_SECTORS_TIMEOUT);
2364         
2365         /*
2366                 Only print if something happened or saved whole map
2367         */
2368         if(only_changed == false || sector_meta_count != 0
2369                         || block_count != 0 || deleted_count != 0)
2370         {
2371                 dstream<<DTIME<<"ServerMap: Written: "
2372                                 <<sector_meta_count<<" sector metadata files, "
2373                                 <<block_count<<" block files, "
2374                                 <<deleted_count<<" sectors unloaded from memory."
2375                                 <<std::endl;
2376         }
2377 }
2378
2379 void ServerMap::loadAll()
2380 {
2381         DSTACK(__FUNCTION_NAME);
2382         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
2383
2384         loadMasterHeightmap();
2385
2386         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
2387
2388         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
2389         
2390         JMutexAutoLock lock(m_sector_mutex);
2391         
2392         s32 counter = 0;
2393         s32 printed_counter = -100000;
2394         s32 count = list.size();
2395
2396         std::vector<fs::DirListNode>::iterator i;
2397         for(i=list.begin(); i!=list.end(); i++)
2398         {
2399                 if(counter > printed_counter + 10)
2400                 {
2401                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
2402                         printed_counter = counter;
2403                 }
2404                 counter++;
2405
2406                 MapSector *sector = NULL;
2407
2408                 // We want directories
2409                 if(i->dir == false)
2410                         continue;
2411                 try{
2412                         sector = loadSectorMeta(i->name);
2413                 }
2414                 catch(InvalidFilenameException &e)
2415                 {
2416                         // This catches unknown crap in directory
2417                 }
2418                 
2419                 if(ENABLE_BLOCK_LOADING)
2420                 {
2421                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2422                                         (m_savedir+"/sectors/"+i->name);
2423                         std::vector<fs::DirListNode>::iterator i2;
2424                         for(i2=list2.begin(); i2!=list2.end(); i2++)
2425                         {
2426                                 // We want files
2427                                 if(i2->dir)
2428                                         continue;
2429                                 try{
2430                                         loadBlock(i->name, i2->name, sector);
2431                                 }
2432                                 catch(InvalidFilenameException &e)
2433                                 {
2434                                         // This catches unknown crap in directory
2435                                 }
2436                         }
2437                 }
2438         }
2439         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
2440 }
2441
2442 void ServerMap::saveMasterHeightmap()
2443 {
2444         DSTACK(__FUNCTION_NAME);
2445         createDir(m_savedir);
2446         
2447         std::string fullpath = m_savedir + "/master_heightmap";
2448         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2449         if(o.good() == false)
2450                 throw FileNotGoodException("Cannot open master heightmap");
2451         
2452         // Format used for writing
2453         u8 version = SER_FMT_VER_HIGHEST;
2454
2455 #if 0
2456         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
2457         /*
2458                 [0] u8 serialization version
2459                 [1] X master heightmap
2460         */
2461         u32 fullsize = 1 + hmdata.getSize();
2462         SharedBuffer<u8> data(fullsize);
2463
2464         data[0] = version;
2465         memcpy(&data[1], *hmdata, hmdata.getSize());
2466
2467         o.write((const char*)*data, fullsize);
2468 #endif
2469         
2470         m_heightmap->serialize(o, version);
2471 }
2472
2473 void ServerMap::loadMasterHeightmap()
2474 {
2475         DSTACK(__FUNCTION_NAME);
2476         std::string fullpath = m_savedir + "/master_heightmap";
2477         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2478         if(is.good() == false)
2479                 throw FileNotGoodException("Cannot open master heightmap");
2480         
2481         if(m_heightmap != NULL)
2482                 delete m_heightmap;
2483                 
2484         m_heightmap = UnlimitedHeightmap::deSerialize(is);
2485 }
2486
2487 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2488 {
2489         DSTACK(__FUNCTION_NAME);
2490         // Format used for writing
2491         u8 version = SER_FMT_VER_HIGHEST;
2492         // Get destination
2493         v2s16 pos = sector->getPos();
2494         createDir(m_savedir);
2495         createDir(m_savedir+"/sectors");
2496         std::string dir = getSectorDir(pos);
2497         createDir(dir);
2498         
2499         std::string fullpath = dir + "/heightmap";
2500         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2501         if(o.good() == false)
2502                 throw FileNotGoodException("Cannot open master heightmap");
2503
2504         sector->serialize(o, version);
2505         
2506         sector->differs_from_disk = false;
2507 }
2508
2509 MapSector* ServerMap::loadSectorMeta(std::string dirname)
2510 {
2511         DSTACK(__FUNCTION_NAME);
2512         // Get destination
2513         v2s16 p2d = getSectorPos(dirname);
2514         std::string dir = m_savedir + "/sectors/" + dirname;
2515         
2516         std::string fullpath = dir + "/heightmap";
2517         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2518         if(is.good() == false)
2519                 throw FileNotGoodException("Cannot open sector heightmap");
2520
2521         ServerMapSector *sector = ServerMapSector::deSerialize
2522                         (is, this, p2d, &m_hwrapper, m_sectors);
2523         
2524         sector->differs_from_disk = false;
2525
2526         return sector;
2527 }
2528
2529 bool ServerMap::loadSectorFull(v2s16 p2d)
2530 {
2531         DSTACK(__FUNCTION_NAME);
2532         std::string sectorsubdir = getSectorSubDir(p2d);
2533
2534         MapSector *sector = NULL;
2535
2536         JMutexAutoLock lock(m_sector_mutex);
2537
2538         try{
2539                 sector = loadSectorMeta(sectorsubdir);
2540         }
2541         catch(InvalidFilenameException &e)
2542         {
2543                 return false;
2544         }
2545         catch(FileNotGoodException &e)
2546         {
2547                 return false;
2548         }
2549         catch(std::exception &e)
2550         {
2551                 return false;
2552         }
2553
2554         if(ENABLE_BLOCK_LOADING)
2555         {
2556                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
2557                                 (m_savedir+"/sectors/"+sectorsubdir);
2558                 std::vector<fs::DirListNode>::iterator i2;
2559                 for(i2=list2.begin(); i2!=list2.end(); i2++)
2560                 {
2561                         // We want files
2562                         if(i2->dir)
2563                                 continue;
2564                         try{
2565                                 loadBlock(sectorsubdir, i2->name, sector);
2566                         }
2567                         catch(InvalidFilenameException &e)
2568                         {
2569                                 // This catches unknown crap in directory
2570                         }
2571                 }
2572         }
2573         return true;
2574 }
2575
2576 #if 0
2577 bool ServerMap::deFlushSector(v2s16 p2d)
2578 {
2579         DSTACK(__FUNCTION_NAME);
2580         // See if it already exists in memory
2581         try{
2582                 MapSector *sector = getSectorNoGenerate(p2d);
2583                 return true;
2584         }
2585         catch(InvalidPositionException &e)
2586         {
2587                 /*
2588                         Try to load the sector from disk.
2589                 */
2590                 if(loadSectorFull(p2d) == true)
2591                 {
2592                         return true;
2593                 }
2594         }
2595         return false;
2596 }
2597 #endif
2598
2599 void ServerMap::saveBlock(MapBlock *block)
2600 {
2601         DSTACK(__FUNCTION_NAME);
2602         /*
2603                 Dummy blocks are not written
2604         */
2605         if(block->isDummy())
2606         {
2607                 /*v3s16 p = block->getPos();
2608                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
2609                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2610                 return;
2611         }
2612
2613         // Format used for writing
2614         u8 version = SER_FMT_VER_HIGHEST;
2615         // Get destination
2616         v3s16 p3d = block->getPos();
2617         v2s16 p2d(p3d.X, p3d.Z);
2618         createDir(m_savedir);
2619         createDir(m_savedir+"/sectors");
2620         std::string dir = getSectorDir(p2d);
2621         createDir(dir);
2622         
2623         // Block file is map/sectors/xxxxxxxx/xxxx
2624         char cc[5];
2625         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
2626         std::string fullpath = dir + "/" + cc;
2627         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2628         if(o.good() == false)
2629                 throw FileNotGoodException("Cannot open block data");
2630
2631         /*
2632                 [0] u8 serialization version
2633                 [1] data
2634         */
2635         o.write((char*)&version, 1);
2636         
2637         block->serialize(o, version);
2638
2639         /*
2640                 Versions up from 9 have block objects.
2641         */
2642         if(version >= 9)
2643         {
2644                 block->serializeObjects(o, version);
2645         }
2646         
2647         // We just wrote it to the disk
2648         block->resetChangedFlag();
2649 }
2650
2651 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
2652 {
2653         DSTACK(__FUNCTION_NAME);
2654
2655         try{
2656
2657         // Block file is map/sectors/xxxxxxxx/xxxx
2658         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
2659         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2660         if(is.good() == false)
2661                 throw FileNotGoodException("Cannot open block file");
2662
2663         v3s16 p3d = getBlockPos(sectordir, blockfile);
2664         v2s16 p2d(p3d.X, p3d.Z);
2665         
2666         assert(sector->getPos() == p2d);
2667         
2668         u8 version = SER_FMT_VER_INVALID;
2669         is.read((char*)&version, 1);
2670
2671         /*u32 block_size = MapBlock::serializedLength(version);
2672         SharedBuffer<u8> data(block_size);
2673         is.read((char*)*data, block_size);*/
2674
2675         // This will always return a sector because we're the server
2676         //MapSector *sector = emergeSector(p2d);
2677
2678         MapBlock *block = NULL;
2679         bool created_new = false;
2680         try{
2681                 block = sector->getBlockNoCreate(p3d.Y);
2682         }
2683         catch(InvalidPositionException &e)
2684         {
2685                 block = sector->createBlankBlockNoInsert(p3d.Y);
2686                 created_new = true;
2687         }
2688         
2689         // deserialize block data
2690         block->deSerialize(is, version);
2691         
2692         /*
2693                 Versions up from 9 have block objects.
2694         */
2695         if(version >= 9)
2696         {
2697                 block->updateObjects(is, version, NULL);
2698         }
2699
2700         if(created_new)
2701                 sector->insertBlock(block);
2702         
2703         /*
2704                 Convert old formats to new and save
2705         */
2706
2707         // Save old format blocks in new format
2708         if(version < SER_FMT_VER_HIGHEST)
2709         {
2710                 saveBlock(block);
2711         }
2712         
2713         // We just loaded it from the disk, so it's up-to-date.
2714         block->resetChangedFlag();
2715
2716         }
2717         catch(SerializationError &e)
2718         {
2719                 dstream<<"WARNING: Invalid block data on disk "
2720                                 "(SerializationError). Ignoring."
2721                                 <<std::endl;
2722         }
2723 }
2724
2725 // Gets from master heightmap
2726 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
2727 {
2728         assert(m_heightmap != NULL);
2729         /*
2730                 Corner definition:
2731                 v2s16(0,0),
2732                 v2s16(1,0),
2733                 v2s16(1,1),
2734                 v2s16(0,1),
2735         */
2736         corners[0] = m_heightmap->getGroundHeight
2737                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
2738         corners[1] = m_heightmap->getGroundHeight
2739                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
2740         corners[2] = m_heightmap->getGroundHeight
2741                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
2742         corners[3] = m_heightmap->getGroundHeight
2743                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
2744 }
2745
2746 void ServerMap::PrintInfo(std::ostream &out)
2747 {
2748         out<<"ServerMap: ";
2749 }
2750
2751 /*
2752         ClientMap
2753 */
2754
2755 ClientMap::ClientMap(
2756                 Client *client,
2757                 video::SMaterial *materials,
2758                 scene::ISceneNode* parent,
2759                 scene::ISceneManager* mgr,
2760                 s32 id
2761 ):
2762         Map(dout_client),
2763         scene::ISceneNode(parent, mgr, id),
2764         m_client(client),
2765         m_materials(materials),
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,
2840         video::SMaterial *materials, s32 pass)
2841 {
2842         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
2843         DSTACK(__FUNCTION_NAME);
2844
2845         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
2846
2847         /*
2848                 Get time for measuring timeout.
2849                 
2850                 Measuring time is very useful for long delays when the
2851                 machine is swapping a lot.
2852         */
2853         int time1 = time(0);
2854
2855         /*
2856                 Collect all blocks that are in the view range
2857
2858                 Should not optimize more here as we want to auto-update
2859                 all changed nodes in viewing range at the next step.
2860         */
2861
2862         s16 viewing_range_nodes;
2863         bool viewing_range_all;
2864         {
2865                 JMutexAutoLock lock(g_range_mutex);
2866                 viewing_range_nodes = g_viewing_range_nodes;
2867                 viewing_range_all = g_viewing_range_all;
2868         }
2869
2870         m_camera_mutex.Lock();
2871         v3f camera_position = m_camera_position;
2872         v3f camera_direction = m_camera_direction;
2873         m_camera_mutex.Unlock();
2874
2875         /*
2876                 Get all blocks and draw all visible ones
2877         */
2878
2879         v3s16 cam_pos_nodes(
2880                         camera_position.X / BS,
2881                         camera_position.Y / BS,
2882                         camera_position.Z / BS);
2883
2884         v3s16 box_nodes_d = viewing_range_nodes * v3s16(1,1,1);
2885
2886         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2887         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2888
2889         // Take a fair amount as we will be dropping more out later
2890         v3s16 p_blocks_min(
2891                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2892                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2893                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2894         v3s16 p_blocks_max(
2895                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2896                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2897                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2898         
2899         u32 vertex_count = 0;
2900         
2901         core::map<v2s16, MapSector*>::Iterator si;
2902
2903         //NOTE: The sectors map should be locked but we're not doing it
2904         // because it'd cause too much delays
2905
2906         si = m_sectors.getIterator();
2907         for(; si.atEnd() == false; si++)
2908         {
2909                 {
2910                         static int timecheck_counter = 0;
2911                         timecheck_counter++;
2912                         if(timecheck_counter > 50)
2913                         {
2914                                 int time2 = time(0);
2915                                 if(time2 > time1 + 4)
2916                                 {
2917                                         dstream<<"ClientMap::renderMap(): "
2918                                                 "Rendering takes ages, returning."
2919                                                 <<std::endl;
2920                                         return;
2921                                 }
2922                         }
2923                 }
2924
2925                 MapSector *sector = si.getNode()->getValue();
2926                 v2s16 sp = sector->getPos();
2927                 
2928                 if(viewing_range_all == false)
2929                 {
2930                         if(sp.X < p_blocks_min.X
2931                         || sp.X > p_blocks_max.X
2932                         || sp.Y < p_blocks_min.Z
2933                         || sp.Y > p_blocks_max.Z)
2934                                 continue;
2935                 }
2936
2937                 core::list< MapBlock * > sectorblocks;
2938                 sector->getBlocks(sectorblocks);
2939                 
2940                 /*
2941                         Draw blocks
2942                 */
2943
2944                 core::list< MapBlock * >::Iterator i;
2945                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
2946                 {
2947                         MapBlock *block = *i;
2948
2949                         /*
2950                                 Compare block position to camera position, skip
2951                                 if not seen on display
2952                         */
2953                         
2954                         v3s16 blockpos_nodes = block->getPosRelative();
2955                         
2956                         // Block center position
2957                         v3f blockpos(
2958                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
2959                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
2960                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
2961                         );
2962
2963                         // Block position relative to camera
2964                         v3f blockpos_relative = blockpos - camera_position;
2965
2966                         // Distance in camera direction (+=front, -=back)
2967                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
2968
2969                         // Total distance
2970                         f32 d = blockpos_relative.getLength();
2971                         
2972                         if(viewing_range_all == false)
2973                         {
2974                                 // If block is far away, don't draw it
2975                                 if(d > viewing_range_nodes * BS)
2976                                         continue;
2977                         }
2978                         
2979                         // Maximum radius of a block
2980                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
2981                         
2982                         // If block is (nearly) touching the camera, don't
2983                         // bother validating further (that is, render it anyway)
2984                         if(d > block_max_radius * 1.5)
2985                         {
2986                                 // Cosine of the angle between the camera direction
2987                                 // and the block direction (camera_direction is an unit vector)
2988                                 f32 cosangle = dforward / d;
2989                                 
2990                                 // Compensate for the size of the block
2991                                 // (as the block has to be shown even if it's a bit off FOV)
2992                                 // This is an estimate.
2993                                 cosangle += block_max_radius / dforward;
2994
2995                                 // If block is not in the field of view, skip it
2996                                 //if(cosangle < cos(FOV_ANGLE/2))
2997                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
2998                                         continue;
2999                         }
3000                         
3001                         /*
3002                                 Draw the faces of the block
3003                         */
3004                         
3005                         {
3006                                 JMutexAutoLock lock(block->mesh_mutex);
3007
3008                                 // Cancel if block has no mesh
3009                                 if(block->mesh == NULL)
3010                                         continue;
3011
3012                                 u32 c = block->mesh->getMeshBufferCount();
3013
3014                                 for(u32 i=0; i<c; i++)
3015                                 {
3016                                         scene::IMeshBuffer *buf = block->mesh->getMeshBuffer(i);
3017                                         const video::SMaterial& material = buf->getMaterial();
3018                                         video::IMaterialRenderer* rnd =
3019                                                         driver->getMaterialRenderer(material.MaterialType);
3020                                         bool transparent = (rnd && rnd->isTransparent());
3021                                         // Render transparent on transparent pass and likewise.
3022                                         if(transparent == is_transparent_pass)
3023                                         {
3024                                                 driver->setMaterial(buf->getMaterial());
3025                                                 driver->drawMeshBuffer(buf);
3026                                                 vertex_count += buf->getVertexCount();
3027                                         }
3028                                 }
3029                         }
3030                 } // foreach sectorblocks
3031         }
3032
3033         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3034                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3035 }
3036
3037 void ClientMap::updateMesh()
3038 {
3039 #if 0
3040         DSTACK(__FUNCTION_NAME);
3041         //TODO
3042         /*
3043                 Check what sectors don't draw anything useful at ground level
3044                 and create a mesh of the rough heightmap at those positions.
3045         */
3046
3047         m_camera_mutex.Lock();
3048         v3f camera_position = m_camera_position;
3049         v3f camera_direction = m_camera_direction;
3050         m_camera_mutex.Unlock();
3051
3052         v3s16 cam_pos_nodes(
3053                         camera_position.X / BS,
3054                         camera_position.Y / BS,
3055                         camera_position.Z / BS);
3056
3057         v3s16 box_nodes_d = HEIGHTMAP_RANGE_NODES * v3s16(1,1,1);
3058
3059         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3060         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3061
3062         // Take a fair amount as we will be dropping more out later
3063         v3s16 p_blocks_min(
3064                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
3065                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
3066                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
3067         v3s16 p_blocks_max(
3068                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3069                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3070                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3071         
3072         /*
3073                 Initialize new mesh
3074         */
3075         
3076         scene::SMesh *mesh_new = new scene::SMesh();
3077         //scene::IMeshBuffer *buf = NULL;
3078         scene::SMeshBuffer *buf = NULL;
3079
3080         u8 material_in_use = 0;
3081
3082         /*
3083                 Loop through sectors
3084         */
3085         
3086         for(core::map<v2s16, MapSector*>::Iterator
3087                         si = m_sectors.getIterator();
3088                         si.atEnd() == false; si++)
3089         {
3090                 MapSector *sector = si.getNode()->getValue();
3091                 
3092                 if(sector->getId() != MAPSECTOR_CLIENT)
3093                 {
3094                         dstream<<"WARNING: Client has a non-client sector"
3095                                         <<std::endl;
3096                         continue;
3097                 }
3098                 
3099                 ClientMapSector *cs = (ClientMapSector*)sector;
3100
3101                 v2s16 sp = sector->getPos();
3102
3103                 if(sp.X < p_blocks_min.X
3104                 || sp.X > p_blocks_max.X
3105                 || sp.Y < p_blocks_min.Z
3106                 || sp.Y > p_blocks_max.Z)
3107                         continue;
3108                 
3109                 /*
3110                         Get some ground level info
3111                 */
3112                 
3113                 s16 a = -5;
3114
3115                 s16 cn[4] = 
3116                 {
3117                         cs->getCorner(0)+a,
3118                         cs->getCorner(1)+a,
3119                         cs->getCorner(2)+a,
3120                         cs->getCorner(3)+a,
3121                 };
3122                 s16 cn_avg = (cn[0]+cn[1]+cn[2]+cn[3])/4;
3123                 s16 cn_min = 32767;
3124                 s16 cn_max = -32768;
3125                 for(s16 i=0; i<4; i++)
3126                 {
3127                         if(cn[i] < cn_min)
3128                                 cn_min = cn[i];
3129                         if(cn[i] > cn_max)
3130                                 cn_max = cn[i];
3131                 }
3132                 s16 cn_slope = cn_max - cn_min;
3133                 
3134                 /*
3135                         Generate this part of the heightmap mesh
3136                 */
3137
3138                 u8 material;
3139                 if(cn_avg + MAP_BLOCKSIZE/4 <= WATER_LEVEL)
3140                         material = 0;
3141                 else if(cn_slope <= MAP_BLOCKSIZE)
3142                         material = 1;
3143                 else
3144                         material = 2;
3145
3146                 if(material != material_in_use || buf == NULL)
3147                 {
3148                         // Try to get a meshbuffer associated with the material
3149                         buf = (scene::SMeshBuffer*)mesh_new->getMeshBuffer
3150                                         (g_mesh_materials[material]);
3151                         // If not found, create one
3152                         if(buf == NULL)
3153                         {
3154                                 // This is a "Standard MeshBuffer",
3155                                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
3156                                 buf = new scene::SMeshBuffer();
3157
3158                                 // Set material
3159                                 buf->Material = g_mesh_materials[material];
3160                                 // Use VBO
3161                                 //buf->setHardwareMappingHint(scene::EHM_STATIC);
3162                                 // Add to mesh
3163                                 mesh_new->addMeshBuffer(buf);
3164                                 // Mesh grabbed it
3165                                 buf->drop();
3166                         }
3167                         material_in_use = material;
3168                 }
3169
3170                 // Sector side width in floating-point units
3171                 f32 sd = BS * MAP_BLOCKSIZE;
3172                 // Sector position in global floating-point units
3173                 v3f spf = v3f((f32)sp.X, 0, (f32)sp.Y) * sd;
3174
3175                 //video::SColor c(255,255,255,255);
3176                 u8 cc = 180;
3177                 video::SColor c(255,cc,cc,cc);
3178                 
3179                 video::S3DVertex vertices[4] =
3180                 {
3181                         video::S3DVertex(spf.X,   (f32)BS*cn[0],spf.Z,   0,0,0, c, 0,1),
3182                         video::S3DVertex(spf.X+sd,(f32)BS*cn[1],spf.Z,   0,0,0, c, 1,1),
3183                         video::S3DVertex(spf.X+sd,(f32)BS*cn[2],spf.Z+sd,0,0,0, c, 1,0),
3184                         video::S3DVertex(spf.X,   (f32)BS*cn[3],spf.Z+sd,0,0,0, c, 0,0),
3185                 };
3186                 u16 indices[] = {0,1,2,2,3,0};
3187                 
3188                 buf->append(vertices, 4, indices, 6);
3189         }
3190         
3191         // Set VBO on
3192         //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
3193
3194         /*
3195                 Replace the mesh
3196         */
3197
3198         mesh_mutex.Lock();
3199
3200         scene::SMesh *mesh_old = mesh;
3201
3202         //DEBUG
3203         /*mesh = NULL;
3204         mesh_new->drop();*/
3205         mesh = mesh_new;
3206         
3207         mesh_mutex.Unlock();
3208
3209         if(mesh_old != NULL)
3210         {
3211                 /*dstream<<"mesh_old refcount="<<mesh_old->getReferenceCount()
3212                                 <<std::endl;
3213                 scene::IMeshBuffer *buf = mesh_new->getMeshBuffer
3214                                 (g_materials[CONTENT_GRASS]);
3215                 if(buf != NULL)
3216                         dstream<<"grass buf refcount="<<buf->getReferenceCount()
3217                                         <<std::endl;*/
3218
3219                 mesh_old->drop();
3220         }
3221         else
3222         {
3223                 dstream<<"WARNING: There was no old master heightmap mesh"<<std::endl;
3224         }
3225 #endif
3226 }
3227
3228 void ClientMap::PrintInfo(std::ostream &out)
3229 {
3230         out<<"ClientMap: ";
3231 }
3232
3233
3234 /*
3235         MapVoxelManipulator
3236 */
3237
3238 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3239 {
3240         m_map = map;
3241 }
3242
3243 MapVoxelManipulator::~MapVoxelManipulator()
3244 {
3245         dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3246                         <<std::endl;
3247 }
3248
3249 #if 1
3250 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3251 {
3252         TimeTaker timer1("emerge", g_device, &emerge_time);
3253
3254         // Units of these are MapBlocks
3255         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3256         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3257
3258         VoxelArea block_area_nodes
3259                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3260
3261         addArea(block_area_nodes);
3262
3263         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3264         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3265         for(s32 x=p_min.X; x<=p_max.X; x++)
3266         {
3267                 v3s16 p(x,y,z);
3268                 core::map<v3s16, bool>::Node *n;
3269                 n = m_loaded_blocks.find(p);
3270                 if(n != NULL)
3271                         continue;
3272                 
3273                 bool block_data_inexistent = false;
3274                 try
3275                 {
3276                         TimeTaker timer1("emerge load", g_device, &emerge_load_time);
3277
3278                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3279                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3280                                         <<" wanted area: ";
3281                         a.print(dstream);
3282                         dstream<<std::endl;*/
3283                         
3284                         MapBlock *block = m_map->getBlockNoCreate(p);
3285                         if(block->isDummy())
3286                                 block_data_inexistent = true;
3287                         else
3288                                 block->copyTo(*this);
3289                 }
3290                 catch(InvalidPositionException &e)
3291                 {
3292                         block_data_inexistent = true;
3293                 }
3294
3295                 if(block_data_inexistent)
3296                 {
3297                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3298                         // Fill with VOXELFLAG_INEXISTENT
3299                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3300                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3301                         {
3302                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3303                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3304                         }
3305                 }
3306
3307                 m_loaded_blocks.insert(p, true);
3308         }
3309
3310         //dstream<<"emerge done"<<std::endl;
3311 }
3312 #endif
3313
3314 #if 0
3315 void MapVoxelManipulator::emerge(VoxelArea a)
3316 {
3317         TimeTaker timer1("emerge", g_device, &emerge_time);
3318         
3319         v3s16 size = a.getExtent();
3320         
3321         VoxelArea padded = a;
3322         padded.pad(m_area.getExtent() / 4);
3323         addArea(padded);
3324
3325         for(s16 z=0; z<size.Z; z++)
3326         for(s16 y=0; y<size.Y; y++)
3327         for(s16 x=0; x<size.X; x++)
3328         {
3329                 v3s16 p(x,y,z);
3330                 s32 i = m_area.index(a.MinEdge + p);
3331                 // Don't touch nodes that have already been loaded
3332                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
3333                         continue;
3334                 try
3335                 {
3336                         TimeTaker timer1("emerge load", g_device, &emerge_load_time);
3337                         MapNode n = m_map->getNode(a.MinEdge + p);
3338                         m_data[i] = n;
3339                         m_flags[i] = 0;
3340                 }
3341                 catch(InvalidPositionException &e)
3342                 {
3343                         m_flags[i] = VOXELFLAG_INEXISTENT;
3344                 }
3345         }
3346 }
3347 #endif
3348
3349
3350 /*
3351         TODO: Add an option to only update eg. water and air nodes.
3352               This will make it interfere less with important stuff if
3353                   run on background.
3354 */
3355 void MapVoxelManipulator::blitBack
3356                 (core::map<v3s16, MapBlock*> & modified_blocks)
3357 {
3358         if(m_area.getExtent() == v3s16(0,0,0))
3359                 return;
3360         
3361         TimeTaker timer1("blitBack", g_device);
3362         
3363         /*
3364                 Initialize block cache
3365         */
3366         v3s16 blockpos_last;
3367         MapBlock *block = NULL;
3368         bool block_checked_in_modified = false;
3369
3370         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3371         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3372         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3373         {
3374                 v3s16 p(x,y,z);
3375
3376                 u8 f = m_flags[m_area.index(p)];
3377                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3378                         continue;
3379
3380                 MapNode &n = m_data[m_area.index(p)];
3381                         
3382                 v3s16 blockpos = getNodeBlockPos(p);
3383                 
3384                 try
3385                 {
3386                         // Get block
3387                         if(block == NULL || blockpos != blockpos_last){
3388                                 block = m_map->getBlockNoCreate(blockpos);
3389                                 blockpos_last = blockpos;
3390                                 block_checked_in_modified = false;
3391                         }
3392                         
3393                         // Calculate relative position in block
3394                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3395
3396                         // Don't continue if nothing has changed here
3397                         if(block->getNode(relpos) == n)
3398                                 continue;
3399
3400                         //m_map->setNode(m_area.MinEdge + p, n);
3401                         block->setNode(relpos, n);
3402                         
3403                         /*
3404                                 Make sure block is in modified_blocks
3405                         */
3406                         if(block_checked_in_modified == false)
3407                         {
3408                                 modified_blocks[blockpos] = block;
3409                                 block_checked_in_modified = true;
3410                         }
3411                 }
3412                 catch(InvalidPositionException &e)
3413                 {
3414                 }
3415         }
3416 }
3417
3418 //END