server starting on port 0 on invalid settings
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "main.h"
22 #include "jmutexautolock.h"
23 #include "client.h"
24 #include "filesys.h"
25 #include "utility.h"
26 #include "voxel.h"
27 #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                         for(s16 i=0; i<coal_amount; i++)
1995                         {
1996                                 v3s16 cp(
1997                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1998                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1999                                         (rand()%(MAP_BLOCKSIZE-2))+1
2000                                 );
2001
2002                                 MapNode n;
2003                                 n.d = CONTENT_COALSTONE;
2004
2005                                 //dstream<<"Adding coalstone"<<std::endl;
2006                                 
2007                                 //if(is_ground_content(block->getNode(cp).d))
2008                                 if(block->getNode(cp).d == CONTENT_STONE)
2009                                         if(rand()%8 == 0)
2010                                                 block->setNode(cp, n);
2011
2012                                 for(u16 i=0; i<26; i++)
2013                                 {
2014                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
2015                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
2016                                                 if(rand()%8 == 0)
2017                                                         block->setNode(cp+g_26dirs[i], n);
2018                                 }
2019                         }
2020                 }
2021         }
2022         
2023         /*
2024                 Create a few rats in empty blocks underground
2025         */
2026         if(is_underground)
2027         {
2028                 //for(u16 i=0; i<2; i++)
2029                 {
2030                         v3s16 cp(
2031                                 (rand()%(MAP_BLOCKSIZE-2))+1,
2032                                 (rand()%(MAP_BLOCKSIZE-2))+1,
2033                                 (rand()%(MAP_BLOCKSIZE-2))+1
2034                         );
2035
2036                         // Check that the place is empty
2037                         //if(!is_ground_content(block->getNode(cp).d))
2038                         if(1)
2039                         {
2040                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
2041                                 block->addObject(obj);
2042                         }
2043                 }
2044         }
2045         
2046         /*
2047                 Add block to sector.
2048         */
2049         sector->insertBlock(block);
2050         
2051         /*
2052                 Sector object stuff
2053         */
2054                 
2055         // An y-wise container of changed blocks
2056         core::map<s16, MapBlock*> changed_blocks_sector;
2057
2058         /*
2059                 Check if any sector's objects can be placed now.
2060                 If so, place them.
2061         */
2062         core::map<v3s16, u8> *objects = sector->getObjects();
2063         core::list<v3s16> objects_to_remove;
2064         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
2065                         i.atEnd() == false; i++)
2066         {
2067                 v3s16 p = i.getNode()->getKey();
2068                 v2s16 p2d(p.X,p.Z);
2069                 u8 d = i.getNode()->getValue();
2070
2071                 //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
2072                 
2073                 try
2074                 {
2075
2076                 if(d == SECTOR_OBJECT_TEST)
2077                 {
2078                         if(sector->isValidArea(p + v3s16(0,0,0),
2079                                         p + v3s16(0,0,0), &changed_blocks_sector))
2080                         {
2081                                 MapNode n;
2082                                 n.d = CONTENT_TORCH;
2083                                 sector->setNode(p, n);
2084                                 objects_to_remove.push_back(p);
2085                         }
2086                 }
2087                 else if(d == SECTOR_OBJECT_TREE_1)
2088                 {
2089                         v3s16 p_min = p + v3s16(-1,0,-1);
2090                         v3s16 p_max = p + v3s16(1,4,1);
2091                         if(sector->isValidArea(p_min, p_max,
2092                                         &changed_blocks_sector))
2093                         {
2094                                 MapNode n;
2095                                 n.d = CONTENT_TREE;
2096                                 sector->setNode(p+v3s16(0,0,0), n);
2097                                 sector->setNode(p+v3s16(0,1,0), n);
2098                                 sector->setNode(p+v3s16(0,2,0), n);
2099                                 sector->setNode(p+v3s16(0,3,0), n);
2100
2101                                 n.d = CONTENT_LEAVES;
2102
2103                                 sector->setNode(p+v3s16(0,4,0), n);
2104                                 
2105                                 sector->setNode(p+v3s16(-1,4,0), n);
2106                                 sector->setNode(p+v3s16(1,4,0), n);
2107                                 sector->setNode(p+v3s16(0,4,-1), n);
2108                                 sector->setNode(p+v3s16(0,4,1), n);
2109                                 sector->setNode(p+v3s16(1,4,1), n);
2110                                 sector->setNode(p+v3s16(-1,4,1), n);
2111                                 sector->setNode(p+v3s16(-1,4,-1), n);
2112                                 sector->setNode(p+v3s16(1,4,-1), n);
2113
2114                                 sector->setNode(p+v3s16(-1,3,0), n);
2115                                 sector->setNode(p+v3s16(1,3,0), n);
2116                                 sector->setNode(p+v3s16(0,3,-1), n);
2117                                 sector->setNode(p+v3s16(0,3,1), n);
2118                                 sector->setNode(p+v3s16(1,3,1), n);
2119                                 sector->setNode(p+v3s16(-1,3,1), n);
2120                                 sector->setNode(p+v3s16(-1,3,-1), n);
2121                                 sector->setNode(p+v3s16(1,3,-1), n);
2122                                 
2123                                 objects_to_remove.push_back(p);
2124                                 
2125                                 // Lighting has to be recalculated for this one.
2126                                 sector->getBlocksInArea(p_min, p_max, 
2127                                                 lighting_invalidated_blocks);
2128                         }
2129                 }
2130                 else if(d == SECTOR_OBJECT_BUSH_1)
2131                 {
2132                         if(sector->isValidArea(p + v3s16(0,0,0),
2133                                         p + v3s16(0,0,0), &changed_blocks_sector))
2134                         {
2135                                 MapNode n;
2136                                 n.d = CONTENT_LEAVES;
2137                                 sector->setNode(p+v3s16(0,0,0), n);
2138                                 
2139                                 objects_to_remove.push_back(p);
2140                         }
2141                 }
2142                 else if(d == SECTOR_OBJECT_RAVINE)
2143                 {
2144                         s16 maxdepth = -20;
2145                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
2146                         v3s16 p_max = p + v3s16(6,6,6);
2147                         if(sector->isValidArea(p_min, p_max,
2148                                         &changed_blocks_sector))
2149                         {
2150                                 MapNode n;
2151                                 n.d = CONTENT_STONE;
2152                                 MapNode n2;
2153                                 n2.d = CONTENT_AIR;
2154                                 s16 depth = maxdepth + (rand()%10);
2155                                 s16 z = 0;
2156                                 s16 minz = -6 - (-2);
2157                                 s16 maxz = 6 -1;
2158                                 for(s16 x=-6; x<=6; x++)
2159                                 {
2160                                         z += -1 + (rand()%3);
2161                                         if(z < minz)
2162                                                 z = minz;
2163                                         if(z > maxz)
2164                                                 z = maxz;
2165                                         for(s16 y=depth+(rand()%2); y<=6; y++)
2166                                         {
2167                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
2168                                                                 <<std::endl;*/
2169                                                 {
2170                                                         v3s16 p2 = p + v3s16(x,y,z-2);
2171                                                         if(is_ground_content(sector->getNode(p2).d)
2172                                                                         && !is_mineral(sector->getNode(p2).d))
2173                                                                 sector->setNode(p2, n);
2174                                                 }
2175                                                 {
2176                                                         v3s16 p2 = p + v3s16(x,y,z-1);
2177                                                         if(is_ground_content(sector->getNode(p2).d)
2178                                                                         && !is_mineral(sector->getNode(p2).d))
2179                                                                 sector->setNode(p2, n2);
2180                                                 }
2181                                                 {
2182                                                         v3s16 p2 = p + v3s16(x,y,z+0);
2183                                                         if(is_ground_content(sector->getNode(p2).d)
2184                                                                         && !is_mineral(sector->getNode(p2).d))
2185                                                                 sector->setNode(p2, n2);
2186                                                 }
2187                                                 {
2188                                                         v3s16 p2 = p + v3s16(x,y,z+1);
2189                                                         if(is_ground_content(sector->getNode(p2).d)
2190                                                                         && !is_mineral(sector->getNode(p2).d))
2191                                                                 sector->setNode(p2, n);
2192                                                 }
2193
2194                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
2195                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
2196                                         }
2197                                 }
2198                                 
2199                                 objects_to_remove.push_back(p);
2200                                 
2201                                 // Lighting has to be recalculated for this one.
2202                                 sector->getBlocksInArea(p_min, p_max, 
2203                                                 lighting_invalidated_blocks);
2204                         }
2205                 }
2206                 else
2207                 {
2208                         dstream<<"ServerMap::emergeBlock(): "
2209                                         "Invalid heightmap object"
2210                                         <<std::endl;
2211                 }
2212
2213                 }//try
2214                 catch(InvalidPositionException &e)
2215                 {
2216                         dstream<<"WARNING: "<<__FUNCTION_NAME
2217                                         <<": while inserting object "<<(int)d
2218                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
2219                                         <<" InvalidPositionException.what()="
2220                                         <<e.what()<<std::endl;
2221                         // This is not too fatal and seems to happen sometimes.
2222                         assert(0);
2223                 }
2224         }
2225
2226         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
2227                         i != objects_to_remove.end(); i++)
2228         {
2229                 objects->remove(*i);
2230         }
2231
2232         for(core::map<s16, MapBlock*>::Iterator
2233                         i = changed_blocks_sector.getIterator();
2234                         i.atEnd() == false; i++)
2235         {
2236                 MapBlock *block = i.getNode()->getValue();
2237
2238                 changed_blocks.insert(block->getPos(), block);
2239         }
2240
2241         return block;
2242 }
2243
2244 void ServerMap::createDir(std::string path)
2245 {
2246         if(fs::CreateDir(path) == false)
2247         {
2248                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2249                                 <<"\""<<path<<"\""<<std::endl;
2250                 throw BaseException("ServerMap failed to create directory");
2251         }
2252 }
2253
2254 std::string ServerMap::getSectorSubDir(v2s16 pos)
2255 {
2256         char cc[9];
2257         snprintf(cc, 9, "%.4x%.4x",
2258                         (unsigned int)pos.X&0xffff,
2259                         (unsigned int)pos.Y&0xffff);
2260
2261         return std::string(cc);
2262 }
2263
2264 std::string ServerMap::getSectorDir(v2s16 pos)
2265 {
2266         return m_savedir + "/sectors/" + getSectorSubDir(pos);
2267 }
2268
2269 v2s16 ServerMap::getSectorPos(std::string dirname)
2270 {
2271         if(dirname.size() != 8)
2272                 throw InvalidFilenameException("Invalid sector directory name");
2273         unsigned int x, y;
2274         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
2275         if(r != 2)
2276                 throw InvalidFilenameException("Invalid sector directory name");
2277         v2s16 pos((s16)x, (s16)y);
2278         return pos;
2279 }
2280
2281 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2282 {
2283         v2s16 p2d = getSectorPos(sectordir);
2284
2285         if(blockfile.size() != 4){
2286                 throw InvalidFilenameException("Invalid block filename");
2287         }
2288         unsigned int y;
2289         int r = sscanf(blockfile.c_str(), "%4x", &y);
2290         if(r != 1)
2291                 throw InvalidFilenameException("Invalid block filename");
2292         return v3s16(p2d.X, y, p2d.Y);
2293 }
2294
2295 // Debug helpers
2296 #define ENABLE_SECTOR_SAVING 1
2297 #define ENABLE_SECTOR_LOADING 1
2298 #define ENABLE_BLOCK_SAVING 1
2299 #define ENABLE_BLOCK_LOADING 1
2300
2301 void ServerMap::save(bool only_changed)
2302 {
2303         DSTACK(__FUNCTION_NAME);
2304         if(m_map_saving_enabled == false)
2305         {
2306                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2307                 return;
2308         }
2309         
2310         if(only_changed == false)
2311                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2312                                 <<std::endl;
2313         
2314         saveMasterHeightmap();
2315         
2316         u32 sector_meta_count = 0;
2317         u32 block_count = 0;
2318         
2319         { //sectorlock
2320         JMutexAutoLock lock(m_sector_mutex);
2321         
2322         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2323         for(; i.atEnd() == false; i++)
2324         {
2325                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2326                 assert(sector->getId() == MAPSECTOR_SERVER);
2327                 
2328                 if(ENABLE_SECTOR_SAVING)
2329                 {
2330                         if(sector->differs_from_disk || only_changed == false)
2331                         {
2332                                 saveSectorMeta(sector);
2333                                 sector_meta_count++;
2334                         }
2335                 }
2336                 if(ENABLE_BLOCK_SAVING)
2337                 {
2338                         core::list<MapBlock*> blocks;
2339                         sector->getBlocks(blocks);
2340                         core::list<MapBlock*>::Iterator j;
2341                         for(j=blocks.begin(); j!=blocks.end(); j++)
2342                         {
2343                                 MapBlock *block = *j;
2344                                 if(block->getChangedFlag() || only_changed == false)
2345                                 {
2346                                         saveBlock(block);
2347                                         block_count++;
2348                                 }
2349                         }
2350                 }
2351         }
2352
2353         }//sectorlock
2354         
2355         /*
2356                 Only print if something happened or saved whole map
2357         */
2358         if(only_changed == false || sector_meta_count != 0
2359                         || block_count != 0)
2360         {
2361                 dstream<<DTIME<<"ServerMap: Written: "
2362                                 <<sector_meta_count<<" sector metadata files, "
2363                                 <<block_count<<" block files"
2364                                 <<std::endl;
2365         }
2366 }
2367
2368 void ServerMap::loadAll()
2369 {
2370         DSTACK(__FUNCTION_NAME);
2371         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
2372
2373         loadMasterHeightmap();
2374
2375         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
2376
2377         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
2378         
2379         JMutexAutoLock lock(m_sector_mutex);
2380         
2381         s32 counter = 0;
2382         s32 printed_counter = -100000;
2383         s32 count = list.size();
2384
2385         std::vector<fs::DirListNode>::iterator i;
2386         for(i=list.begin(); i!=list.end(); i++)
2387         {
2388                 if(counter > printed_counter + 10)
2389                 {
2390                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
2391                         printed_counter = counter;
2392                 }
2393                 counter++;
2394
2395                 MapSector *sector = NULL;
2396
2397                 // We want directories
2398                 if(i->dir == false)
2399                         continue;
2400                 try{
2401                         sector = loadSectorMeta(i->name);
2402                 }
2403                 catch(InvalidFilenameException &e)
2404                 {
2405                         // This catches unknown crap in directory
2406                 }
2407                 
2408                 if(ENABLE_BLOCK_LOADING)
2409                 {
2410                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2411                                         (m_savedir+"/sectors/"+i->name);
2412                         std::vector<fs::DirListNode>::iterator i2;
2413                         for(i2=list2.begin(); i2!=list2.end(); i2++)
2414                         {
2415                                 // We want files
2416                                 if(i2->dir)
2417                                         continue;
2418                                 try{
2419                                         loadBlock(i->name, i2->name, sector);
2420                                 }
2421                                 catch(InvalidFilenameException &e)
2422                                 {
2423                                         // This catches unknown crap in directory
2424                                 }
2425                         }
2426                 }
2427         }
2428         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
2429 }
2430
2431 void ServerMap::saveMasterHeightmap()
2432 {
2433         DSTACK(__FUNCTION_NAME);
2434         createDir(m_savedir);
2435         
2436         std::string fullpath = m_savedir + "/master_heightmap";
2437         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2438         if(o.good() == false)
2439                 throw FileNotGoodException("Cannot open master heightmap");
2440         
2441         // Format used for writing
2442         u8 version = SER_FMT_VER_HIGHEST;
2443
2444 #if 0
2445         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
2446         /*
2447                 [0] u8 serialization version
2448                 [1] X master heightmap
2449         */
2450         u32 fullsize = 1 + hmdata.getSize();
2451         SharedBuffer<u8> data(fullsize);
2452
2453         data[0] = version;
2454         memcpy(&data[1], *hmdata, hmdata.getSize());
2455
2456         o.write((const char*)*data, fullsize);
2457 #endif
2458         
2459         m_heightmap->serialize(o, version);
2460 }
2461
2462 void ServerMap::loadMasterHeightmap()
2463 {
2464         DSTACK(__FUNCTION_NAME);
2465         std::string fullpath = m_savedir + "/master_heightmap";
2466         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2467         if(is.good() == false)
2468                 throw FileNotGoodException("Cannot open master heightmap");
2469         
2470         if(m_heightmap != NULL)
2471                 delete m_heightmap;
2472                 
2473         m_heightmap = UnlimitedHeightmap::deSerialize(is);
2474 }
2475
2476 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2477 {
2478         DSTACK(__FUNCTION_NAME);
2479         // Format used for writing
2480         u8 version = SER_FMT_VER_HIGHEST;
2481         // Get destination
2482         v2s16 pos = sector->getPos();
2483         createDir(m_savedir);
2484         createDir(m_savedir+"/sectors");
2485         std::string dir = getSectorDir(pos);
2486         createDir(dir);
2487         
2488         std::string fullpath = dir + "/heightmap";
2489         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2490         if(o.good() == false)
2491                 throw FileNotGoodException("Cannot open master heightmap");
2492
2493         sector->serialize(o, version);
2494         
2495         sector->differs_from_disk = false;
2496 }
2497
2498 MapSector* ServerMap::loadSectorMeta(std::string dirname)
2499 {
2500         DSTACK(__FUNCTION_NAME);
2501         // Get destination
2502         v2s16 p2d = getSectorPos(dirname);
2503         std::string dir = m_savedir + "/sectors/" + dirname;
2504         
2505         std::string fullpath = dir + "/heightmap";
2506         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2507         if(is.good() == false)
2508                 throw FileNotGoodException("Cannot open sector heightmap");
2509
2510         ServerMapSector *sector = ServerMapSector::deSerialize
2511                         (is, this, p2d, &m_hwrapper, m_sectors);
2512         
2513         sector->differs_from_disk = false;
2514
2515         return sector;
2516 }
2517
2518 bool ServerMap::loadSectorFull(v2s16 p2d)
2519 {
2520         DSTACK(__FUNCTION_NAME);
2521         std::string sectorsubdir = getSectorSubDir(p2d);
2522
2523         MapSector *sector = NULL;
2524
2525         JMutexAutoLock lock(m_sector_mutex);
2526
2527         try{
2528                 sector = loadSectorMeta(sectorsubdir);
2529         }
2530         catch(InvalidFilenameException &e)
2531         {
2532                 return false;
2533         }
2534         catch(FileNotGoodException &e)
2535         {
2536                 return false;
2537         }
2538         catch(std::exception &e)
2539         {
2540                 return false;
2541         }
2542
2543         if(ENABLE_BLOCK_LOADING)
2544         {
2545                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
2546                                 (m_savedir+"/sectors/"+sectorsubdir);
2547                 std::vector<fs::DirListNode>::iterator i2;
2548                 for(i2=list2.begin(); i2!=list2.end(); i2++)
2549                 {
2550                         // We want files
2551                         if(i2->dir)
2552                                 continue;
2553                         try{
2554                                 loadBlock(sectorsubdir, i2->name, sector);
2555                         }
2556                         catch(InvalidFilenameException &e)
2557                         {
2558                                 // This catches unknown crap in directory
2559                         }
2560                 }
2561         }
2562         return true;
2563 }
2564
2565 #if 0
2566 bool ServerMap::deFlushSector(v2s16 p2d)
2567 {
2568         DSTACK(__FUNCTION_NAME);
2569         // See if it already exists in memory
2570         try{
2571                 MapSector *sector = getSectorNoGenerate(p2d);
2572                 return true;
2573         }
2574         catch(InvalidPositionException &e)
2575         {
2576                 /*
2577                         Try to load the sector from disk.
2578                 */
2579                 if(loadSectorFull(p2d) == true)
2580                 {
2581                         return true;
2582                 }
2583         }
2584         return false;
2585 }
2586 #endif
2587
2588 void ServerMap::saveBlock(MapBlock *block)
2589 {
2590         DSTACK(__FUNCTION_NAME);
2591         /*
2592                 Dummy blocks are not written
2593         */
2594         if(block->isDummy())
2595         {
2596                 /*v3s16 p = block->getPos();
2597                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
2598                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2599                 return;
2600         }
2601
2602         // Format used for writing
2603         u8 version = SER_FMT_VER_HIGHEST;
2604         // Get destination
2605         v3s16 p3d = block->getPos();
2606         v2s16 p2d(p3d.X, p3d.Z);
2607         createDir(m_savedir);
2608         createDir(m_savedir+"/sectors");
2609         std::string dir = getSectorDir(p2d);
2610         createDir(dir);
2611         
2612         // Block file is map/sectors/xxxxxxxx/xxxx
2613         char cc[5];
2614         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
2615         std::string fullpath = dir + "/" + cc;
2616         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2617         if(o.good() == false)
2618                 throw FileNotGoodException("Cannot open block data");
2619
2620         /*
2621                 [0] u8 serialization version
2622                 [1] data
2623         */
2624         o.write((char*)&version, 1);
2625         
2626         block->serialize(o, version);
2627
2628         /*
2629                 Versions up from 9 have block objects.
2630         */
2631         if(version >= 9)
2632         {
2633                 block->serializeObjects(o, version);
2634         }
2635         
2636         // We just wrote it to the disk
2637         block->resetChangedFlag();
2638 }
2639
2640 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
2641 {
2642         DSTACK(__FUNCTION_NAME);
2643
2644         try{
2645
2646         // Block file is map/sectors/xxxxxxxx/xxxx
2647         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
2648         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2649         if(is.good() == false)
2650                 throw FileNotGoodException("Cannot open block file");
2651
2652         v3s16 p3d = getBlockPos(sectordir, blockfile);
2653         v2s16 p2d(p3d.X, p3d.Z);
2654         
2655         assert(sector->getPos() == p2d);
2656         
2657         u8 version = SER_FMT_VER_INVALID;
2658         is.read((char*)&version, 1);
2659
2660         /*u32 block_size = MapBlock::serializedLength(version);
2661         SharedBuffer<u8> data(block_size);
2662         is.read((char*)*data, block_size);*/
2663
2664         // This will always return a sector because we're the server
2665         //MapSector *sector = emergeSector(p2d);
2666
2667         MapBlock *block = NULL;
2668         bool created_new = false;
2669         try{
2670                 block = sector->getBlockNoCreate(p3d.Y);
2671         }
2672         catch(InvalidPositionException &e)
2673         {
2674                 block = sector->createBlankBlockNoInsert(p3d.Y);
2675                 created_new = true;
2676         }
2677         
2678         // deserialize block data
2679         block->deSerialize(is, version);
2680         
2681         /*
2682                 Versions up from 9 have block objects.
2683         */
2684         if(version >= 9)
2685         {
2686                 block->updateObjects(is, version, NULL, 0);
2687         }
2688
2689         if(created_new)
2690                 sector->insertBlock(block);
2691         
2692         /*
2693                 Convert old formats to new and save
2694         */
2695
2696         // Save old format blocks in new format
2697         if(version < SER_FMT_VER_HIGHEST)
2698         {
2699                 saveBlock(block);
2700         }
2701         
2702         // We just loaded it from the disk, so it's up-to-date.
2703         block->resetChangedFlag();
2704
2705         }
2706         catch(SerializationError &e)
2707         {
2708                 dstream<<"WARNING: Invalid block data on disk "
2709                                 "(SerializationError). Ignoring."
2710                                 <<std::endl;
2711         }
2712 }
2713
2714 // Gets from master heightmap
2715 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
2716 {
2717         assert(m_heightmap != NULL);
2718         /*
2719                 Corner definition:
2720                 v2s16(0,0),
2721                 v2s16(1,0),
2722                 v2s16(1,1),
2723                 v2s16(0,1),
2724         */
2725         corners[0] = m_heightmap->getGroundHeight
2726                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
2727         corners[1] = m_heightmap->getGroundHeight
2728                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
2729         corners[2] = m_heightmap->getGroundHeight
2730                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
2731         corners[3] = m_heightmap->getGroundHeight
2732                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
2733 }
2734
2735 void ServerMap::PrintInfo(std::ostream &out)
2736 {
2737         out<<"ServerMap: ";
2738 }
2739
2740 #ifndef SERVER
2741
2742 /*
2743         ClientMap
2744 */
2745
2746 ClientMap::ClientMap(
2747                 Client *client,
2748                 JMutex &range_mutex,
2749                 s16 &viewing_range_nodes,
2750                 bool &viewing_range_all,
2751                 scene::ISceneNode* parent,
2752                 scene::ISceneManager* mgr,
2753                 s32 id
2754 ):
2755         Map(dout_client),
2756         scene::ISceneNode(parent, mgr, id),
2757         m_client(client),
2758         mesh(NULL),
2759         m_range_mutex(range_mutex),
2760         m_viewing_range_nodes(viewing_range_nodes),
2761         m_viewing_range_all(viewing_range_all)
2762 {
2763         mesh_mutex.Init();
2764
2765         /*m_box = core::aabbox3d<f32>(0,0,0,
2766                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
2767         /*m_box = core::aabbox3d<f32>(0,0,0,
2768                         map->getSizeNodes().X * BS,
2769                         map->getSizeNodes().Y * BS,
2770                         map->getSizeNodes().Z * BS);*/
2771         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
2772                         BS*1000000,BS*1000000,BS*1000000);
2773         
2774         //setPosition(v3f(BS,BS,BS));
2775 }
2776
2777 ClientMap::~ClientMap()
2778 {
2779         JMutexAutoLock lock(mesh_mutex);
2780         
2781         if(mesh != NULL)
2782         {
2783                 mesh->drop();
2784                 mesh = NULL;
2785         }
2786 }
2787
2788 MapSector * ClientMap::emergeSector(v2s16 p2d)
2789 {
2790         DSTACK(__FUNCTION_NAME);
2791         // Check that it doesn't exist already
2792         try{
2793                 return getSectorNoGenerate(p2d);
2794         }
2795         catch(InvalidPositionException &e)
2796         {
2797         }
2798         
2799         // Create a sector with no heightmaps
2800         ClientMapSector *sector = new ClientMapSector(this, p2d);
2801         
2802         {
2803                 JMutexAutoLock lock(m_sector_mutex);
2804                 m_sectors.insert(p2d, sector);
2805         }
2806         
2807         return sector;
2808 }
2809
2810 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
2811 {
2812         DSTACK(__FUNCTION_NAME);
2813         ClientMapSector *sector = NULL;
2814
2815         JMutexAutoLock lock(m_sector_mutex);
2816         
2817         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
2818
2819         if(n != NULL)
2820         {
2821                 sector = (ClientMapSector*)n->getValue();
2822                 assert(sector->getId() == MAPSECTOR_CLIENT);
2823         }
2824         else
2825         {
2826                 sector = new ClientMapSector(this, p2d);
2827                 {
2828                         JMutexAutoLock lock(m_sector_mutex);
2829                         m_sectors.insert(p2d, sector);
2830                 }
2831         }
2832
2833         sector->deSerialize(is);
2834 }
2835
2836 void ClientMap::OnRegisterSceneNode()
2837 {
2838         if(IsVisible)
2839         {
2840                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
2841                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
2842         }
2843
2844         ISceneNode::OnRegisterSceneNode();
2845 }
2846
2847 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
2848 {
2849         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
2850         DSTACK(__FUNCTION_NAME);
2851
2852         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
2853
2854         /*
2855                 Get time for measuring timeout.
2856                 
2857                 Measuring time is very useful for long delays when the
2858                 machine is swapping a lot.
2859         */
2860         int time1 = time(0);
2861
2862         //s32 daynight_i = m_client->getDayNightIndex();
2863         u32 daynight_ratio = m_client->getDayNightRatio();
2864
2865         /*
2866                 Collect all blocks that are in the view range
2867
2868                 Should not optimize more here as we want to auto-update
2869                 all changed nodes in viewing range at the next step.
2870         */
2871
2872         s16 viewing_range_nodes;
2873         bool viewing_range_all;
2874         {
2875                 JMutexAutoLock lock(m_range_mutex);
2876                 viewing_range_nodes = m_viewing_range_nodes;
2877                 viewing_range_all = m_viewing_range_all;
2878         }
2879
2880         m_camera_mutex.Lock();
2881         v3f camera_position = m_camera_position;
2882         v3f camera_direction = m_camera_direction;
2883         m_camera_mutex.Unlock();
2884
2885         /*
2886                 Get all blocks and draw all visible ones
2887         */
2888
2889         v3s16 cam_pos_nodes(
2890                         camera_position.X / BS,
2891                         camera_position.Y / BS,
2892                         camera_position.Z / BS);
2893
2894         v3s16 box_nodes_d = viewing_range_nodes * v3s16(1,1,1);
2895
2896         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2897         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2898
2899         // Take a fair amount as we will be dropping more out later
2900         v3s16 p_blocks_min(
2901                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2902                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2903                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2904         v3s16 p_blocks_max(
2905                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2906                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2907                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2908         
2909         u32 vertex_count = 0;
2910         
2911         // For limiting number of mesh updates per frame
2912         u32 mesh_update_count = 0;
2913
2914         //NOTE: The sectors map should be locked but we're not doing it
2915         // because it'd cause too much delays
2916
2917         int timecheck_counter = 0;
2918
2919         core::map<v2s16, MapSector*>::Iterator si;
2920         si = m_sectors.getIterator();
2921         for(; si.atEnd() == false; si++)
2922         {
2923                 {
2924                         timecheck_counter++;
2925                         if(timecheck_counter > 50)
2926                         {
2927                                 int time2 = time(0);
2928                                 if(time2 > time1 + 4)
2929                                 {
2930                                         dstream<<"ClientMap::renderMap(): "
2931                                                 "Rendering takes ages, returning."
2932                                                 <<std::endl;
2933                                         return;
2934                                 }
2935                         }
2936                 }
2937
2938                 MapSector *sector = si.getNode()->getValue();
2939                 v2s16 sp = sector->getPos();
2940                 
2941                 if(viewing_range_all == false)
2942                 {
2943                         if(sp.X < p_blocks_min.X
2944                         || sp.X > p_blocks_max.X
2945                         || sp.Y < p_blocks_min.Z
2946                         || sp.Y > p_blocks_max.Z)
2947                                 continue;
2948                 }
2949
2950                 core::list< MapBlock * > sectorblocks;
2951                 sector->getBlocks(sectorblocks);
2952                 
2953                 /*
2954                         Draw blocks
2955                 */
2956
2957                 core::list< MapBlock * >::Iterator i;
2958                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
2959                 {
2960                         MapBlock *block = *i;
2961
2962                         /*
2963                                 Compare block position to camera position, skip
2964                                 if not seen on display
2965                         */
2966                         
2967                         v3s16 blockpos_nodes = block->getPosRelative();
2968                         
2969                         // Block center position
2970                         v3f blockpos(
2971                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
2972                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
2973                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
2974                         );
2975
2976                         // Block position relative to camera
2977                         v3f blockpos_relative = blockpos - camera_position;
2978
2979                         // Distance in camera direction (+=front, -=back)
2980                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
2981
2982                         // Total distance
2983                         f32 d = blockpos_relative.getLength();
2984                         
2985                         if(viewing_range_all == false)
2986                         {
2987                                 // If block is far away, don't draw it
2988                                 if(d > viewing_range_nodes * BS)
2989                                 // This is nicer when fog is used
2990                                 //if((dforward+d)/2 > viewing_range_nodes * BS)
2991                                         continue;
2992                         }
2993                         
2994                         // Maximum radius of a block
2995                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
2996                         
2997                         // If block is (nearly) touching the camera, don't
2998                         // bother validating further (that is, render it anyway)
2999                         if(d > block_max_radius * 1.5)
3000                         {
3001                                 // Cosine of the angle between the camera direction
3002                                 // and the block direction (camera_direction is an unit vector)
3003                                 f32 cosangle = dforward / d;
3004                                 
3005                                 // Compensate for the size of the block
3006                                 // (as the block has to be shown even if it's a bit off FOV)
3007                                 // This is an estimate.
3008                                 cosangle += block_max_radius / dforward;
3009
3010                                 // If block is not in the field of view, skip it
3011                                 //if(cosangle < cos(FOV_ANGLE/2))
3012                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
3013                                         continue;
3014                         }
3015                         
3016                         /*
3017                                 Draw the faces of the block
3018                         */
3019 #if 1
3020                         bool mesh_expired = false;
3021                         
3022                         {
3023                                 JMutexAutoLock lock(block->mesh_mutex);
3024
3025                                 mesh_expired = block->getMeshExpired();
3026
3027                                 // Mesh has not been expired and there is no mesh:
3028                                 // block has no content
3029                                 if(block->mesh == NULL && mesh_expired == false)
3030                                         continue;
3031                         }
3032
3033                         f32 faraway = BS*50;
3034                         //f32 faraway = viewing_range_nodes * BS;
3035                         
3036                         /*
3037                                 This has to be done with the mesh_mutex unlocked
3038                         */
3039                         if(mesh_expired && mesh_update_count < 6
3040                                         && (d < faraway || mesh_update_count < 3))
3041                         //if(mesh_expired && mesh_update_count < 4)
3042                         {
3043                                 mesh_update_count++;
3044
3045                                 // Mesh has been expired: generate new mesh
3046                                 //block->updateMeshes(daynight_i);
3047                                 block->updateMesh(daynight_ratio);
3048
3049                                 mesh_expired = false;
3050                         }
3051                         
3052                         /*
3053                                 Don't draw an expired mesh that is far away
3054                         */
3055                         /*if(mesh_expired && d >= faraway)
3056                         //if(mesh_expired)
3057                         {
3058                                 // Instead, delete it
3059                                 JMutexAutoLock lock(block->mesh_mutex);
3060                                 if(block->mesh)
3061                                 {
3062                                         block->mesh->drop();
3063                                         block->mesh = NULL;
3064                                 }
3065                                 // And continue to next block
3066                                 continue;
3067                         }*/
3068 #endif
3069                         {
3070                                 JMutexAutoLock lock(block->mesh_mutex);
3071
3072                                 scene::SMesh *mesh = block->mesh;
3073
3074                                 if(mesh == NULL)
3075                                         continue;
3076
3077                                 u32 c = mesh->getMeshBufferCount();
3078
3079                                 for(u32 i=0; i<c; i++)
3080                                 {
3081                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3082                                         const video::SMaterial& material = buf->getMaterial();
3083                                         video::IMaterialRenderer* rnd =
3084                                                         driver->getMaterialRenderer(material.MaterialType);
3085                                         bool transparent = (rnd && rnd->isTransparent());
3086                                         // Render transparent on transparent pass and likewise.
3087                                         if(transparent == is_transparent_pass)
3088                                         {
3089                                                 driver->setMaterial(buf->getMaterial());
3090                                                 driver->drawMeshBuffer(buf);
3091                                                 vertex_count += buf->getVertexCount();
3092                                         }
3093                                 }
3094                         }
3095                 } // foreach sectorblocks
3096         }
3097
3098         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3099                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3100 }
3101
3102 v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod)
3103 {
3104         /*
3105                 Add it to all blocks touching it
3106         */
3107         v3s16 dirs[7] = {
3108                 v3s16(0,0,0), // this
3109                 v3s16(0,0,1), // back
3110                 v3s16(0,1,0), // top
3111                 v3s16(1,0,0), // right
3112                 v3s16(0,0,-1), // front
3113                 v3s16(0,-1,0), // bottom
3114                 v3s16(-1,0,0), // left
3115         };
3116         for(u16 i=0; i<7; i++)
3117         {
3118                 v3s16 p2 = p + dirs[i];
3119                 // Block position of neighbor (or requested) node
3120                 v3s16 blockpos = getNodeBlockPos(p2);
3121                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3122                 if(blockref == NULL)
3123                         continue;
3124                 // Relative position of requested node
3125                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3126                 blockref->setTempMod(relpos, mod);
3127         }
3128         return getNodeBlockPos(p);
3129 }
3130 v3s16 ClientMap::clearTempMod(v3s16 p)
3131 {
3132         v3s16 dirs[7] = {
3133                 v3s16(0,0,0), // this
3134                 v3s16(0,0,1), // back
3135                 v3s16(0,1,0), // top
3136                 v3s16(1,0,0), // right
3137                 v3s16(0,0,-1), // front
3138                 v3s16(0,-1,0), // bottom
3139                 v3s16(-1,0,0), // left
3140         };
3141         for(u16 i=0; i<7; i++)
3142         {
3143                 v3s16 p2 = p + dirs[i];
3144                 // Block position of neighbor (or requested) node
3145                 v3s16 blockpos = getNodeBlockPos(p2);
3146                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3147                 if(blockref == NULL)
3148                         continue;
3149                 // Relative position of requested node
3150                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3151                 blockref->clearTempMod(relpos);
3152         }
3153         return getNodeBlockPos(p);
3154 }
3155
3156 void ClientMap::PrintInfo(std::ostream &out)
3157 {
3158         out<<"ClientMap: ";
3159 }
3160
3161 #endif // !SERVER
3162
3163 /*
3164         MapVoxelManipulator
3165 */
3166
3167 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3168 {
3169         m_map = map;
3170 }
3171
3172 MapVoxelManipulator::~MapVoxelManipulator()
3173 {
3174         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3175                         <<std::endl;*/
3176 }
3177
3178 #if 1
3179 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3180 {
3181         TimeTaker timer1("emerge", &emerge_time);
3182
3183         // Units of these are MapBlocks
3184         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3185         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3186
3187         VoxelArea block_area_nodes
3188                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3189
3190         addArea(block_area_nodes);
3191
3192         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3193         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3194         for(s32 x=p_min.X; x<=p_max.X; x++)
3195         {
3196                 v3s16 p(x,y,z);
3197                 core::map<v3s16, bool>::Node *n;
3198                 n = m_loaded_blocks.find(p);
3199                 if(n != NULL)
3200                         continue;
3201                 
3202                 bool block_data_inexistent = false;
3203                 try
3204                 {
3205                         TimeTaker timer1("emerge load", &emerge_load_time);
3206
3207                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3208                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3209                                         <<" wanted area: ";
3210                         a.print(dstream);
3211                         dstream<<std::endl;*/
3212                         
3213                         MapBlock *block = m_map->getBlockNoCreate(p);
3214                         if(block->isDummy())
3215                                 block_data_inexistent = true;
3216                         else
3217                                 block->copyTo(*this);
3218                 }
3219                 catch(InvalidPositionException &e)
3220                 {
3221                         block_data_inexistent = true;
3222                 }
3223
3224                 if(block_data_inexistent)
3225                 {
3226                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3227                         // Fill with VOXELFLAG_INEXISTENT
3228                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3229                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3230                         {
3231                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3232                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3233                         }
3234                 }
3235
3236                 m_loaded_blocks.insert(p, true);
3237         }
3238
3239         //dstream<<"emerge done"<<std::endl;
3240 }
3241 #endif
3242
3243 #if 0
3244 void MapVoxelManipulator::emerge(VoxelArea a)
3245 {
3246         TimeTaker timer1("emerge", &emerge_time);
3247         
3248         v3s16 size = a.getExtent();
3249         
3250         VoxelArea padded = a;
3251         padded.pad(m_area.getExtent() / 4);
3252         addArea(padded);
3253
3254         for(s16 z=0; z<size.Z; z++)
3255         for(s16 y=0; y<size.Y; y++)
3256         for(s16 x=0; x<size.X; x++)
3257         {
3258                 v3s16 p(x,y,z);
3259                 s32 i = m_area.index(a.MinEdge + p);
3260                 // Don't touch nodes that have already been loaded
3261                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
3262                         continue;
3263                 try
3264                 {
3265                         TimeTaker timer1("emerge load", &emerge_load_time);
3266                         MapNode n = m_map->getNode(a.MinEdge + p);
3267                         m_data[i] = n;
3268                         m_flags[i] = 0;
3269                 }
3270                 catch(InvalidPositionException &e)
3271                 {
3272                         m_flags[i] = VOXELFLAG_INEXISTENT;
3273                 }
3274         }
3275 }
3276 #endif
3277
3278
3279 /*
3280         TODO: Add an option to only update eg. water and air nodes.
3281               This will make it interfere less with important stuff if
3282                   run on background.
3283 */
3284 void MapVoxelManipulator::blitBack
3285                 (core::map<v3s16, MapBlock*> & modified_blocks)
3286 {
3287         if(m_area.getExtent() == v3s16(0,0,0))
3288                 return;
3289         
3290         //TimeTaker timer1("blitBack");
3291         
3292         /*
3293                 Initialize block cache
3294         */
3295         v3s16 blockpos_last;
3296         MapBlock *block = NULL;
3297         bool block_checked_in_modified = false;
3298
3299         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3300         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3301         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3302         {
3303                 v3s16 p(x,y,z);
3304
3305                 u8 f = m_flags[m_area.index(p)];
3306                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3307                         continue;
3308
3309                 MapNode &n = m_data[m_area.index(p)];
3310                         
3311                 v3s16 blockpos = getNodeBlockPos(p);
3312                 
3313                 try
3314                 {
3315                         // Get block
3316                         if(block == NULL || blockpos != blockpos_last){
3317                                 block = m_map->getBlockNoCreate(blockpos);
3318                                 blockpos_last = blockpos;
3319                                 block_checked_in_modified = false;
3320                         }
3321                         
3322                         // Calculate relative position in block
3323                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3324
3325                         // Don't continue if nothing has changed here
3326                         if(block->getNode(relpos) == n)
3327                                 continue;
3328
3329                         //m_map->setNode(m_area.MinEdge + p, n);
3330                         block->setNode(relpos, n);
3331                         
3332                         /*
3333                                 Make sure block is in modified_blocks
3334                         */
3335                         if(block_checked_in_modified == false)
3336                         {
3337                                 modified_blocks[blockpos] = block;
3338                                 block_checked_in_modified = true;
3339                         }
3340                 }
3341                 catch(InvalidPositionException &e)
3342                 {
3343                 }
3344         }
3345 }
3346
3347 //END