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