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