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