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