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