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