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