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