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