Initial commit of mapgen v.2. Lacks configuration and saving to disk.
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "main.h"
22 #include "jmutexautolock.h"
23 #include "client.h"
24 #include "filesys.h"
25 #include "utility.h"
26 #include "voxel.h"
27 #include "porting.h"
28
29 /*
30         Map
31 */
32
33 Map::Map(std::ostream &dout):
34         m_dout(dout),
35         m_camera_position(0,0,0),
36         m_camera_direction(0,0,1),
37         m_sector_cache(NULL),
38         m_hwrapper(this),
39         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                 PointAttributeList *list_baseheight = m_padb.getList("hm_baseheight");
1321                 PointAttributeList *list_randmax = m_padb.getList("hm_randmax");
1322                 PointAttributeList *list_randfactor = m_padb.getList("hm_randfactor");
1323                 PointAttributeList *list_plants_amount = m_padb.getList("plants_amount");
1324                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
1325                 
1326                 for(u32 i=0; i<3000; i++)
1327                 {
1328                         u32 lim = MAP_GENERATION_LIMIT;
1329                         if(i < 200)
1330                                 lim = 1000;
1331
1332                         v3s16 p(
1333                                 -lim + myrand()%(lim*2),
1334                                 0,
1335                                 -lim + myrand()%(lim*2)
1336                         );
1337                         /*float plants_amount = (float)(myrand()%1050) / 1000.0;
1338                         plants_amount = pow(plants_amount, 5);
1339                         list_plants_amount->addPoint(p, Attribute(plants_amount));*/
1340                         
1341                         float plants_amount = 0;
1342                         if(myrand()%5 == 0)
1343                         {
1344                                 plants_amount = 1.5;
1345                         }
1346                         else if(myrand()%4 == 0)
1347                         {
1348                                 plants_amount = 0.5;
1349                         }
1350                         else if(myrand()%2 == 0)
1351                         {
1352                                 plants_amount = 0.03;
1353                         }
1354                         else
1355                         {
1356                                 plants_amount = 0.0;
1357                         }
1358
1359                         float caves_amount = 0;
1360                         if(myrand()%5 == 0)
1361                         {
1362                                 caves_amount = 1.0;
1363                         }
1364                         else if(myrand()%3 == 0)
1365                         {
1366                                 caves_amount = 0.3;
1367                         }
1368                         else
1369                         {
1370                                 caves_amount = 0.05;
1371                         }
1372
1373                         list_plants_amount->addPoint(p, Attribute(plants_amount));
1374                         list_caves_amount->addPoint(p, Attribute(caves_amount));
1375                 }
1376 #if 1
1377                 for(u32 i=0; i<3000; i++)
1378                 {
1379                         u32 lim = MAP_GENERATION_LIMIT;
1380                         if(i < 100)
1381                                 lim = 1000;
1382
1383                         v3s16 p(
1384                                 -lim + myrand()%(lim*2),
1385                                 0,
1386                                 -lim + myrand()%(lim*2)
1387                         );
1388                         
1389                         /*s32 bh_i = (myrand()%200) - 50;
1390                         float baseheight = (float)bh_i;
1391                         
1392                         float m = 100.;
1393                         float e = 3.;
1394                         float randmax = (float)(myrand()%(int)(10.*pow(m, 1./e)))/10.;
1395                         randmax = pow(randmax, e);
1396
1397                         //float randmax = (float)(myrand()%60);
1398                         float randfactor = (float)(myrand()%450) / 1000.0 + 0.4;*/
1399
1400                         float baseheight = 0;
1401                         float randmax = 0;
1402                         float randfactor = 0;
1403
1404                         if(myrand()%4 == 0)
1405                         {
1406                                 baseheight = 100;
1407                                 randmax = 100;
1408                                 randfactor = 0.63;
1409                         }
1410                         else if(myrand()%5 == 0)
1411                         {
1412                                 baseheight = 200;
1413                                 randmax = 200;
1414                                 randfactor = 0.66;
1415                         }
1416                         else if(myrand()%4 == 0)
1417                         {
1418                                 baseheight = -3;
1419                                 randmax = 30;
1420                                 randfactor = 0.7;
1421                         }
1422                         else if(myrand()%3 == 0)
1423                         {
1424                                 baseheight = 0;
1425                                 randmax = 30;
1426                                 randfactor = 0.60;
1427                         }
1428                         else
1429                         {
1430                                 baseheight = -3;
1431                                 randmax = 20;
1432                                 randfactor = 0.5;
1433                         }
1434
1435                         list_baseheight->addPoint(p, Attribute(baseheight));
1436                         list_randmax->addPoint(p, Attribute(randmax));
1437                         list_randfactor->addPoint(p, Attribute(randfactor));
1438                 }
1439 #endif
1440
1441                 /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(5));
1442                 list_randmax->addPoint(v3s16(0,0,0), Attribute(20));
1443                 list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.6));*/
1444         }
1445
1446 #if 0
1447         {
1448                 PointAttributeList *palist = m_padb.getList("hm_baseheight");
1449
1450                 {
1451                         v3s16 p(0,0,0);
1452                         Attribute attr;
1453                         attr.set("5");
1454                         palist->addPoint(p, attr);
1455                 }
1456
1457                 /*{
1458                         v3s16 p(-50,-50,0);
1459                         Attribute attr;
1460                         attr.set("-10");
1461                         palist->addPoint(p, attr);
1462                 }
1463                 
1464                 {
1465                         v3s16 p(50,0,50);
1466                         Attribute attr;
1467                         attr.set("200");
1468                         palist->addPoint(p, attr);
1469                 }*/
1470         }
1471 #endif
1472 #if 0
1473         {
1474                 PointAttributeList *palist = m_padb.getList("plants_amount");
1475         
1476                 // Back
1477                 {
1478                         v3s16 p(0,0,-100);
1479                         Attribute attr;
1480                         attr.set("0");
1481                         palist->addPoint(p, attr);
1482                 }
1483                 
1484                 // Front right
1485                 {
1486                         v3s16 p(100,0,100);
1487                         Attribute attr;
1488                         attr.set("2.0");
1489                         palist->addPoint(p, attr);
1490                 }
1491                 
1492                 // Front left
1493                 {
1494                         v3s16 p(-100,0,100);
1495                         Attribute attr;
1496                         attr.set("0.2");
1497                         palist->addPoint(p, attr);
1498                 }
1499         }
1500 #endif
1501
1502         /*
1503                 Try to load map; if not found, create a new one.
1504         */
1505
1506         m_savedir = savedir;
1507         m_map_saving_enabled = false;
1508         
1509         try
1510         {
1511                 // If directory exists, check contents and load if possible
1512                 if(fs::PathExists(m_savedir))
1513                 {
1514                         // If directory is empty, it is safe to save into it.
1515                         if(fs::GetDirListing(m_savedir).size() == 0)
1516                         {
1517                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1518                                                 <<std::endl;
1519                                 m_map_saving_enabled = true;
1520                         }
1521                         else
1522                         {
1523                                 // Load master heightmap
1524                                 loadMasterHeightmap();
1525                                 
1526                                 // Load sector (0,0) and throw and exception on fail
1527                                 if(loadSectorFull(v2s16(0,0)) == false)
1528                                         throw LoadError("Failed to load sector (0,0)");
1529
1530                                 dstream<<DTIME<<"Server: Successfully loaded master "
1531                                                 "heightmap and sector (0,0) from "<<savedir<<
1532                                                 ", assuming valid save directory."
1533                                                 <<std::endl;
1534
1535                                 m_map_saving_enabled = true;
1536                                 // Map loaded, not creating new one
1537                                 return;
1538                         }
1539                 }
1540                 // If directory doesn't exist, it is safe to save to it
1541                 else{
1542                         m_map_saving_enabled = true;
1543                 }
1544         }
1545         catch(std::exception &e)
1546         {
1547                 dstream<<DTIME<<"Server: Failed to load map from "<<savedir
1548                                 <<", exception: "<<e.what()<<std::endl;
1549                 dstream<<DTIME<<"Please remove the map or fix it."<<std::endl;
1550                 dstream<<DTIME<<"WARNING: Map saving will be disabled."<<std::endl;
1551         }
1552
1553         dstream<<DTIME<<"Initializing new map."<<std::endl;
1554         
1555         // Create master heightmap
1556         /*ValueGenerator *maxgen =
1557                         ValueGenerator::deSerialize(hmp.randmax);
1558         ValueGenerator *factorgen =
1559                         ValueGenerator::deSerialize(hmp.randfactor);
1560         ValueGenerator *basegen =
1561                         ValueGenerator::deSerialize(hmp.base);
1562         m_heightmap = new UnlimitedHeightmap
1563                         (hmp.blocksize, maxgen, factorgen, basegen, &m_padb);*/
1564
1565         /*m_heightmap = new UnlimitedHeightmap
1566                         (hmp.blocksize, &m_padb);*/
1567
1568         m_heightmap = new UnlimitedHeightmap
1569                         (32, &m_padb);
1570         
1571         // Set map parameters
1572         m_params = mp;
1573         
1574         // Create zero sector
1575         emergeSector(v2s16(0,0));
1576
1577         // Initially write whole map
1578         save(false);
1579 }
1580
1581 ServerMap::~ServerMap()
1582 {
1583         try
1584         {
1585                 if(m_map_saving_enabled)
1586                 {
1587                         //save(false);
1588                         // Save only changed parts
1589                         save(true);
1590                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1591                 }
1592                 else
1593                 {
1594                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1595                 }
1596         }
1597         catch(std::exception &e)
1598         {
1599                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1600                                 <<", exception: "<<e.what()<<std::endl;
1601         }
1602         
1603         if(m_heightmap != NULL)
1604                 delete m_heightmap;
1605 }
1606
1607 MapSector * ServerMap::emergeSector(v2s16 p2d)
1608 {
1609         DSTACK("%s: p2d=(%d,%d)",
1610                         __FUNCTION_NAME,
1611                         p2d.X, p2d.Y);
1612         // Check that it doesn't exist already
1613         try{
1614                 return getSectorNoGenerate(p2d);
1615         }
1616         catch(InvalidPositionException &e)
1617         {
1618         }
1619         
1620         /*
1621                 Try to load the sector from disk.
1622         */
1623         if(loadSectorFull(p2d) == true)
1624         {
1625                 return getSectorNoGenerate(p2d);
1626         }
1627
1628         /*
1629                 If there is no master heightmap, throw.
1630         */
1631         if(m_heightmap == NULL)
1632         {
1633                 throw InvalidPositionException("emergeSector(): no heightmap");
1634         }
1635
1636         /*
1637                 Do not generate over-limit
1638         */
1639         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1640         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1641         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1642         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
1643                 throw InvalidPositionException("emergeSector(): pos. over limit");
1644
1645         /*
1646                 Generate sector and heightmaps
1647         */
1648         
1649         // Number of heightmaps in sector in each direction
1650         u16 hm_split = SECTOR_HEIGHTMAP_SPLIT;
1651
1652         // Heightmap side width
1653         s16 hm_d = MAP_BLOCKSIZE / hm_split;
1654
1655         ServerMapSector *sector = new ServerMapSector(this, p2d, hm_split);
1656         
1657         // Sector position on map in nodes
1658         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
1659
1660         /*dstream<<"Generating sector ("<<p2d.X<<","<<p2d.Y<<")"
1661                         " heightmaps and objects"<<std::endl;*/
1662         
1663         /*
1664                 Calculate some information about local properties
1665         */
1666         
1667         v2s16 mhm_p = p2d * hm_split;
1668         f32 corners[4] = {
1669                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split),
1670                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split),
1671                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split),
1672                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split),
1673         };
1674         
1675         float avgheight = (corners[0]+corners[1]+corners[2]+corners[3])/4.0;
1676         float avgslope = 0.0;
1677         avgslope += fabs(avgheight - corners[0]);
1678         avgslope += fabs(avgheight - corners[1]);
1679         avgslope += fabs(avgheight - corners[2]);
1680         avgslope += fabs(avgheight - corners[3]);
1681         avgslope /= 4.0;
1682         avgslope /= MAP_BLOCKSIZE;
1683         //dstream<<"avgslope="<<avgslope<<std::endl;
1684
1685         float pitness = 0.0;
1686         v2f32 a;
1687         a = m_heightmap->getSlope(p2d+v2s16(0,0));
1688         pitness += -a.X;
1689         pitness += -a.Y;
1690         a = m_heightmap->getSlope(p2d+v2s16(0,1));
1691         pitness += -a.X;
1692         pitness += a.Y;
1693         a = m_heightmap->getSlope(p2d+v2s16(1,1));
1694         pitness += a.X;
1695         pitness += a.Y;
1696         a = m_heightmap->getSlope(p2d+v2s16(1,0));
1697         pitness += a.X;
1698         pitness += -a.Y;
1699         pitness /= 4.0;
1700         pitness /= MAP_BLOCKSIZE;
1701         //dstream<<"pitness="<<pitness<<std::endl;
1702
1703         /*
1704                 Get local attributes
1705         */
1706         
1707         // Get plant amount from attributes
1708         PointAttributeList *palist = m_padb.getList("plants_amount");
1709         assert(palist);
1710         /*float local_plants_amount =
1711                         palist->getNearAttr(nodepos2d).getFloat();*/
1712         float local_plants_amount =
1713                         palist->getInterpolatedFloat(nodepos2d);
1714
1715         /*
1716                 Generate sector heightmap
1717         */
1718
1719         // Loop through sub-heightmaps
1720         for(s16 y=0; y<hm_split; y++)
1721         for(s16 x=0; x<hm_split; x++)
1722         {
1723                 v2s16 p_in_sector = v2s16(x,y);
1724                 v2s16 mhm_p = p2d * hm_split + p_in_sector;
1725                 f32 corners[4] = {
1726                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)),
1727                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)),
1728                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)),
1729                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)),
1730                 };
1731
1732                 /*dstream<<"p_in_sector=("<<p_in_sector.X<<","<<p_in_sector.Y<<")"
1733                                 <<" mhm_p=("<<mhm_p.X<<","<<mhm_p.Y<<")"
1734                                 <<std::endl;*/
1735
1736                 FixedHeightmap *hm = new FixedHeightmap(&m_hwrapper,
1737                                 mhm_p, hm_d);
1738                 sector->setHeightmap(p_in_sector, hm);
1739
1740                 //TODO: Make these values configurable
1741                 //hm->generateContinued(0.0, 0.0, corners);
1742                 //hm->generateContinued(0.25, 0.2, corners);
1743                 //hm->generateContinued(0.5, 0.2, corners);
1744                 //hm->generateContinued(1.0, 0.2, corners);
1745                 //hm->generateContinued(2.0, 0.2, corners);
1746                 hm->generateContinued(2.0 * avgslope, 0.5, corners);
1747
1748                 //hm->print();
1749         }
1750
1751         /*
1752                 Generate objects
1753         */
1754         
1755         core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
1756         sector->setObjects(objects);
1757
1758         /*
1759                 Plant some trees if there is not much slope
1760         */
1761         {
1762                 // Avgslope is the derivative of a hill
1763                 //float t = avgslope * avgslope;
1764                 float t = avgslope;
1765                 float a = MAP_BLOCKSIZE * m_params.plants_amount * local_plants_amount;
1766                 u32 tree_max;
1767                 //float something = 0.17*0.17;
1768                 float something = 0.3;
1769                 if(t > something)
1770                         tree_max = a / (t/something);
1771                 else
1772                         tree_max = a;
1773                 
1774                 u32 count = (myrand()%(tree_max+1));
1775                 //u32 count = tree_max;
1776                 for(u32 i=0; i<count; i++)
1777                 {
1778                         s16 x = (myrand()%(MAP_BLOCKSIZE-2))+1;
1779                         s16 z = (myrand()%(MAP_BLOCKSIZE-2))+1;
1780                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1781                         if(y < WATER_LEVEL)
1782                                 continue;
1783                         objects->insert(v3s16(x, y, z),
1784                                         SECTOR_OBJECT_TREE_1);
1785                 }
1786         }
1787         /*
1788                 Plant some bushes if sector is pit-like
1789         */
1790         {
1791                 // Pitness usually goes at around -0.5...0.5
1792                 u32 bush_max = 0;
1793                 u32 a = MAP_BLOCKSIZE * 3.0 * m_params.plants_amount * local_plants_amount;
1794                 if(pitness > 0)
1795                         bush_max = (pitness*a*4);
1796                 if(bush_max > a)
1797                         bush_max = a;
1798                 u32 count = (myrand()%(bush_max+1));
1799                 for(u32 i=0; i<count; i++)
1800                 {
1801                         s16 x = myrand()%(MAP_BLOCKSIZE-0)+0;
1802                         s16 z = myrand()%(MAP_BLOCKSIZE-0)+0;
1803                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1804                         if(y < WATER_LEVEL)
1805                                 continue;
1806                         objects->insert(v3s16(x, y, z),
1807                                         SECTOR_OBJECT_BUSH_1);
1808                 }
1809         }
1810         /*
1811                 Add ravine (randomly)
1812         */
1813         if(m_params.ravines_amount != 0)
1814         {
1815                 if(myrand()%(s32)(200.0 / m_params.ravines_amount) == 0)
1816                 {
1817                         s16 s = 6;
1818                         s16 x = myrand()%(MAP_BLOCKSIZE-s*2-1)+s;
1819                         s16 z = myrand()%(MAP_BLOCKSIZE-s*2-1)+s;
1820                         /*s16 x = 8;
1821                         s16 z = 8;*/
1822                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1823                         objects->insert(v3s16(x, y, z),
1824                                         SECTOR_OBJECT_RAVINE);
1825                 }
1826         }
1827
1828         /*
1829                 Insert to container
1830         */
1831         JMutexAutoLock lock(m_sector_mutex);
1832         m_sectors.insert(p2d, sector);
1833         
1834         return sector;
1835 }
1836
1837 MapBlock * ServerMap::emergeBlock(
1838                 v3s16 p,
1839                 bool only_from_disk,
1840                 core::map<v3s16, MapBlock*> &changed_blocks,
1841                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
1842 )
1843 {
1844         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
1845                         __FUNCTION_NAME,
1846                         p.X, p.Y, p.Z, only_from_disk);
1847                         
1848         /*dstream<<"ServerMap::emergeBlock(): "
1849                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1850                         <<", only_from_disk="<<only_from_disk<<std::endl;*/
1851         v2s16 p2d(p.X, p.Z);
1852         s16 block_y = p.Y;
1853         /*
1854                 This will create or load a sector if not found in memory.
1855                 If block exists on disk, it will be loaded.
1856
1857                 NOTE: On old save formats, this will be slow, as it generates
1858                       lighting on blocks for them.
1859         */
1860         ServerMapSector *sector = (ServerMapSector*)emergeSector(p2d);
1861         assert(sector->getId() == MAPSECTOR_SERVER);
1862
1863         // Try to get a block from the sector
1864         MapBlock *block = NULL;
1865         bool not_on_disk = false;
1866         try{
1867                 block = sector->getBlockNoCreate(block_y);
1868                 if(block->isDummy() == true)
1869                         not_on_disk = true;
1870                 else
1871                         return block;
1872         }
1873         catch(InvalidPositionException &e)
1874         {
1875                 not_on_disk = true;
1876         }
1877         
1878         /*
1879                 If block was not found on disk and not going to generate a
1880                 new one, make sure there is a dummy block in place.
1881         */
1882         if(not_on_disk && only_from_disk)
1883         {
1884                 if(block == NULL)
1885                 {
1886                         // Create dummy block
1887                         block = new MapBlock(this, p, true);
1888
1889                         // Add block to sector
1890                         sector->insertBlock(block);
1891                 }
1892                 // Done.
1893                 return block;
1894         }
1895
1896         //dstream<<"Not found on disk, generating."<<std::endl;
1897         //TimeTaker("emergeBlock()", g_irrlicht);
1898
1899         /*
1900                 Do not generate over-limit
1901         */
1902         if(blockpos_over_limit(p))
1903                 throw InvalidPositionException("emergeBlock(): pos. over limit");
1904
1905         /*
1906                 OK; Not found.
1907
1908                 Go on generating the block.
1909
1910                 TODO: If a dungeon gets generated so that it's side gets
1911                       revealed to the outside air, the lighting should be
1912                           recalculated.
1913         */
1914         
1915         /*
1916                 If block doesn't exist, create one.
1917                 If it exists, it is a dummy. In that case unDummify() it.
1918
1919                 NOTE: This already sets the map as the parent of the block
1920         */
1921         if(block == NULL)
1922         {
1923                 block = sector->createBlankBlockNoInsert(block_y);
1924         }
1925         else
1926         {
1927                 // Remove the block so that nobody can get a half-generated one.
1928                 sector->removeBlock(block);
1929                 // Allocate the block to contain the generated data
1930                 block->unDummify();
1931         }
1932         
1933         u8 water_material = CONTENT_WATER;
1934         if(g_settings.getBool("endless_water"))
1935                 water_material = CONTENT_OCEAN;
1936         
1937         s32 lowest_ground_y = 32767;
1938         s32 highest_ground_y = -32768;
1939         
1940         // DEBUG
1941         //sector->printHeightmaps();
1942
1943         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1944         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1945         {
1946                 //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
1947
1948                 float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
1949                 //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
1950                 if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE)
1951                 {
1952                         dstream<<"WARNING: Surface height not found in sector "
1953                                         "for block that is being emerged"<<std::endl;
1954                         surface_y_f = 0.0;
1955                 }
1956
1957                 s16 surface_y = surface_y_f;
1958                 //avg_ground_y += surface_y;
1959                 if(surface_y < lowest_ground_y)
1960                         lowest_ground_y = surface_y;
1961                 if(surface_y > highest_ground_y)
1962                         highest_ground_y = surface_y;
1963
1964                 s32 surface_depth = 0;
1965                 
1966                 float slope = sector->getSlope(v2s16(x0,z0)).getLength();
1967                 
1968                 //float min_slope = 0.45;
1969                 //float max_slope = 0.85;
1970                 float min_slope = 0.60;
1971                 float max_slope = 1.20;
1972                 float min_slope_depth = 5.0;
1973                 float max_slope_depth = 0;
1974
1975                 if(slope < min_slope)
1976                         surface_depth = min_slope_depth;
1977                 else if(slope > max_slope)
1978                         surface_depth = max_slope_depth;
1979                 else
1980                         surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
1981
1982                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1983                 {
1984                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
1985                         MapNode n;
1986                         /*
1987                                 Calculate lighting
1988                                 
1989                                 NOTE: If there are some man-made structures above the
1990                                 newly created block, they won't be taken into account.
1991                         */
1992                         if(real_y > surface_y)
1993                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
1994
1995                         /*
1996                                 Calculate material
1997                         */
1998
1999                         // If node is over heightmap y, it's air or water
2000                         if(real_y > surface_y)
2001                         {
2002                                 // If under water level, it's water
2003                                 if(real_y < WATER_LEVEL)
2004                                 {
2005                                         n.d = water_material;
2006                                         n.setLight(LIGHTBANK_DAY,
2007                                                         diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
2008                                 }
2009                                 // else air
2010                                 else
2011                                         n.d = CONTENT_AIR;
2012                         }
2013                         // Else it's ground or dungeons (air)
2014                         else
2015                         {
2016                                 // If it's surface_depth under ground, it's stone
2017                                 if(real_y <= surface_y - surface_depth)
2018                                 {
2019                                         n.d = CONTENT_STONE;
2020                                 }
2021                                 else
2022                                 {
2023                                         // It is mud if it is under the first ground
2024                                         // level or under water
2025                                         if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
2026                                         {
2027                                                 n.d = CONTENT_MUD;
2028                                         }
2029                                         else
2030                                         {
2031                                                 n.d = CONTENT_GRASS;
2032                                         }
2033
2034                                         //n.d = CONTENT_MUD;
2035                                         
2036                                         /*// If under water level, it's mud
2037                                         if(real_y < WATER_LEVEL)
2038                                                 n.d = CONTENT_MUD;
2039                                         // Only the topmost node is grass
2040                                         else if(real_y <= surface_y - 1)
2041                                                 n.d = CONTENT_MUD;
2042                                         else
2043                                                 n.d = CONTENT_GRASS;*/
2044                                 }
2045                         }
2046
2047                         block->setNode(v3s16(x0,y0,z0), n);
2048                 }
2049         }
2050         
2051         /*
2052                 Calculate some helper variables
2053         */
2054         
2055         // Completely underground if the highest part of block is under lowest
2056         // ground height.
2057         // This has to be very sure; it's probably one too strict now but
2058         // that's just better.
2059         bool completely_underground =
2060                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
2061
2062         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
2063
2064         /*
2065                 Get local attributes
2066         */
2067         
2068         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2069         PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
2070         float caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
2071
2072         /*
2073                 Generate dungeons
2074         */
2075
2076         // Initialize temporary table
2077         const s32 ued = MAP_BLOCKSIZE;
2078         bool underground_emptiness[ued*ued*ued];
2079         for(s32 i=0; i<ued*ued*ued; i++)
2080         {
2081                 underground_emptiness[i] = 0;
2082         }
2083         
2084         // Fill table
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                         Don't always generate dungeon
2211                 */
2212                 bool do_generate_dungeons = true;
2213                 // Don't generate if no part is underground
2214                 if(!some_part_underground)
2215                         do_generate_dungeons = false;
2216                 // If block is partly underground, caves are generated.
2217                 else if(!completely_underground)
2218                         do_generate_dungeons = (rand() % 100 <= (u32)(caves_amount*100));
2219                 // Always continue if found existing dungeons underground
2220                 else if(found_existing && completely_underground)
2221                         do_generate_dungeons = true;
2222                 // If underground and no dungeons found
2223                 else
2224                         do_generate_dungeons = (rand() % 2 == 0);
2225
2226                 if(do_generate_dungeons)
2227                 {
2228                         /*
2229                                 Generate some tunnel starting from orp and ors
2230                         */
2231                         for(u16 i=0; i<3; i++)
2232                         {
2233                                 v3f rp(
2234                                         (float)(myrand()%ued)+0.5,
2235                                         (float)(myrand()%ued)+0.5,
2236                                         (float)(myrand()%ued)+0.5
2237                                 );
2238                                 s16 min_d = 0;
2239                                 s16 max_d = 6;
2240                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
2241                                 
2242                                 v3f vec = rp - orp;
2243
2244                                 for(float f=0; f<1.0; f+=0.04)
2245                                 {
2246                                         v3f fp = orp + vec * f;
2247                                         v3s16 cp(fp.X, fp.Y, fp.Z);
2248                                         s16 d0 = -rs/2;
2249                                         s16 d1 = d0 + rs - 1;
2250                                         for(s16 z0=d0; z0<=d1; z0++)
2251                                         {
2252                                                 s16 si = rs - abs(z0);
2253                                                 for(s16 x0=-si; x0<=si-1; x0++)
2254                                                 {
2255                                                         s16 si2 = rs - abs(x0);
2256                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
2257                                                         {
2258                                                                 s16 z = cp.Z + z0;
2259                                                                 s16 y = cp.Y + y0;
2260                                                                 s16 x = cp.X + x0;
2261                                                                 v3s16 p(x,y,z);
2262                                                                 if(isInArea(p, ued) == false)
2263                                                                         continue;
2264                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
2265                                                         }
2266                                                 }
2267                                         }
2268                                 }
2269
2270                                 orp = rp;
2271                         }
2272                 }
2273         }
2274
2275         // Set to true if has caves.
2276         // Set when some non-air is changed to air when making caves.
2277         bool has_caves = false;
2278
2279         /*
2280                 Apply temporary cave data to block
2281         */
2282
2283         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2284         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2285         {
2286                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2287                 {
2288                         MapNode n = block->getNode(v3s16(x0,y0,z0));
2289
2290                         // Create dungeons
2291                         if(underground_emptiness[
2292                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
2293                                         +ued*(y0*ued/MAP_BLOCKSIZE)
2294                                         +(x0*ued/MAP_BLOCKSIZE)])
2295                         {
2296                                 if(is_ground_content(n.d))
2297                                 {
2298                                         // Has now caves
2299                                         has_caves = true;
2300                                         // Set air to node
2301                                         n.d = CONTENT_AIR;
2302                                 }
2303                         }
2304
2305                         block->setNode(v3s16(x0,y0,z0), n);
2306                 }
2307         }
2308         
2309         /*
2310                 This is used for guessing whether or not the block should
2311                 receive sunlight from the top if the top block doesn't exist
2312         */
2313         block->setIsUnderground(completely_underground);
2314
2315         /*
2316                 Force lighting update if some part of block is partly
2317                 underground and has caves.
2318         */
2319         /*if(some_part_underground && !completely_underground && has_caves)
2320         {
2321                 //dstream<<"Half-ground caves"<<std::endl;
2322                 lighting_invalidated_blocks[block->getPos()] = block;
2323         }*/
2324         
2325         // DEBUG: Always update lighting
2326         //lighting_invalidated_blocks[block->getPos()] = block;
2327
2328         /*
2329                 Add some minerals
2330         */
2331
2332         if(some_part_underground)
2333         {
2334                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
2335
2336                 /*
2337                         Add meseblocks
2338                 */
2339                 for(s16 i=0; i< underground_level/4 + 1; i++)
2340                 {
2341                         if(myrand()%10 == 0)
2342                         {
2343                                 v3s16 cp(
2344                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2345                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2346                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2347                                 );
2348
2349                                 MapNode n;
2350                                 n.d = CONTENT_MESE;
2351                                 
2352                                 //if(is_ground_content(block->getNode(cp).d))
2353                                 if(block->getNode(cp).d == CONTENT_STONE)
2354                                         if(myrand()%8 == 0)
2355                                                 block->setNode(cp, n);
2356
2357                                 for(u16 i=0; i<26; i++)
2358                                 {
2359                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
2360                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
2361                                                 if(myrand()%8 == 0)
2362                                                         block->setNode(cp+g_26dirs[i], n);
2363                                 }
2364                         }
2365                 }
2366
2367                 /*
2368                         Add coal
2369                 */
2370                 u16 coal_amount = 30.0 * g_settings.getFloat("coal_amount");
2371                 u16 coal_rareness = 60 / coal_amount;
2372                 if(coal_rareness == 0)
2373                         coal_rareness = 1;
2374                 if(myrand()%coal_rareness == 0)
2375                 {
2376                         u16 a = myrand() % 16;
2377                         u16 amount = coal_amount * a*a*a / 1000;
2378                         for(s16 i=0; i<amount; i++)
2379                         {
2380                                 v3s16 cp(
2381                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2382                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2383                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2384                                 );
2385
2386                                 MapNode n;
2387                                 n.d = CONTENT_COALSTONE;
2388
2389                                 //dstream<<"Adding coalstone"<<std::endl;
2390                                 
2391                                 //if(is_ground_content(block->getNode(cp).d))
2392                                 if(block->getNode(cp).d == CONTENT_STONE)
2393                                         if(myrand()%8 == 0)
2394                                                 block->setNode(cp, n);
2395
2396                                 for(u16 i=0; i<26; i++)
2397                                 {
2398                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
2399                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
2400                                                 if(myrand()%8 == 0)
2401                                                         block->setNode(cp+g_26dirs[i], n);
2402                                 }
2403                         }
2404                 }
2405         }
2406         
2407         /*
2408                 Create a few rats in empty blocks underground
2409         */
2410         if(completely_underground)
2411         {
2412                 //for(u16 i=0; i<2; i++)
2413                 {
2414                         v3s16 cp(
2415                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
2416                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
2417                                 (myrand()%(MAP_BLOCKSIZE-2))+1
2418                         );
2419
2420                         // Check that the place is empty
2421                         //if(!is_ground_content(block->getNode(cp).d))
2422                         if(1)
2423                         {
2424                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
2425                                 block->addObject(obj);
2426                         }
2427                 }
2428         }
2429         
2430         /*
2431                 Add block to sector.
2432         */
2433         sector->insertBlock(block);
2434         
2435         /*
2436                 Sector object stuff
2437         */
2438                 
2439         // An y-wise container of changed blocks
2440         core::map<s16, MapBlock*> changed_blocks_sector;
2441
2442         /*
2443                 Check if any sector's objects can be placed now.
2444                 If so, place them.
2445         */
2446         core::map<v3s16, u8> *objects = sector->getObjects();
2447         core::list<v3s16> objects_to_remove;
2448         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
2449                         i.atEnd() == false; i++)
2450         {
2451                 v3s16 p = i.getNode()->getKey();
2452                 v2s16 p2d(p.X,p.Z);
2453                 u8 d = i.getNode()->getValue();
2454
2455                 // Ground level point (user for stuff that is on ground)
2456                 v3s16 gp = p;
2457                 bool ground_found = true;
2458                 
2459                 // Search real ground level
2460                 try{
2461                         for(;;)
2462                         {
2463                                 MapNode n = sector->getNode(gp);
2464
2465                                 // If not air, go one up and continue to placing the tree
2466                                 if(n.d != CONTENT_AIR)
2467                                 {
2468                                         gp += v3s16(0,1,0);
2469                                         break;
2470                                 }
2471
2472                                 // If air, go one down
2473                                 gp += v3s16(0,-1,0);
2474                         }
2475                 }catch(InvalidPositionException &e)
2476                 {
2477                         // Ground not found.
2478                         ground_found = false;
2479                         // This is most close to ground
2480                         gp += v3s16(0,1,0);
2481                 }
2482
2483                 try
2484                 {
2485
2486                 if(d == SECTOR_OBJECT_TEST)
2487                 {
2488                         if(sector->isValidArea(p + v3s16(0,0,0),
2489                                         p + v3s16(0,0,0), &changed_blocks_sector))
2490                         {
2491                                 MapNode n;
2492                                 n.d = CONTENT_TORCH;
2493                                 sector->setNode(p, n);
2494                                 objects_to_remove.push_back(p);
2495                         }
2496                 }
2497                 else if(d == SECTOR_OBJECT_TREE_1)
2498                 {
2499                         if(ground_found == false)
2500                                 continue;
2501
2502                         v3s16 p_min = gp + v3s16(-1,0,-1);
2503                         v3s16 p_max = gp + v3s16(1,5,1);
2504                         if(sector->isValidArea(p_min, p_max,
2505                                         &changed_blocks_sector))
2506                         {
2507                                 MapNode n;
2508                                 n.d = CONTENT_TREE;
2509                                 sector->setNode(gp+v3s16(0,0,0), n);
2510                                 sector->setNode(gp+v3s16(0,1,0), n);
2511                                 sector->setNode(gp+v3s16(0,2,0), n);
2512                                 sector->setNode(gp+v3s16(0,3,0), n);
2513
2514                                 n.d = CONTENT_LEAVES;
2515
2516                                 if(rand()%4!=0) sector->setNode(gp+v3s16(0,5,0), n);
2517
2518                                 if(rand()%3!=0) sector->setNode(gp+v3s16(-1,5,0), n);
2519                                 if(rand()%3!=0) sector->setNode(gp+v3s16(1,5,0), n);
2520                                 if(rand()%3!=0) sector->setNode(gp+v3s16(0,5,-1), n);
2521                                 if(rand()%3!=0) sector->setNode(gp+v3s16(0,5,1), n);
2522                                 /*if(rand()%3!=0) sector->setNode(gp+v3s16(1,5,1), n);
2523                                 if(rand()%3!=0) sector->setNode(gp+v3s16(-1,5,1), n);
2524                                 if(rand()%3!=0) sector->setNode(gp+v3s16(-1,5,-1), n);
2525                                 if(rand()%3!=0) sector->setNode(gp+v3s16(1,5,-1), n);*/
2526
2527                                 sector->setNode(gp+v3s16(0,4,0), n);
2528                                 
2529                                 sector->setNode(gp+v3s16(-1,4,0), n);
2530                                 sector->setNode(gp+v3s16(1,4,0), n);
2531                                 sector->setNode(gp+v3s16(0,4,-1), n);
2532                                 sector->setNode(gp+v3s16(0,4,1), n);
2533                                 sector->setNode(gp+v3s16(1,4,1), n);
2534                                 sector->setNode(gp+v3s16(-1,4,1), n);
2535                                 sector->setNode(gp+v3s16(-1,4,-1), n);
2536                                 sector->setNode(gp+v3s16(1,4,-1), n);
2537
2538                                 sector->setNode(gp+v3s16(-1,3,0), n);
2539                                 sector->setNode(gp+v3s16(1,3,0), n);
2540                                 sector->setNode(gp+v3s16(0,3,-1), n);
2541                                 sector->setNode(gp+v3s16(0,3,1), n);
2542                                 sector->setNode(gp+v3s16(1,3,1), n);
2543                                 sector->setNode(gp+v3s16(-1,3,1), n);
2544                                 sector->setNode(gp+v3s16(-1,3,-1), n);
2545                                 sector->setNode(gp+v3s16(1,3,-1), n);
2546                                 
2547                                 if(rand()%3!=0) sector->setNode(gp+v3s16(-1,2,0), n);
2548                                 if(rand()%3!=0) sector->setNode(gp+v3s16(1,2,0), n);
2549                                 if(rand()%3!=0) sector->setNode(gp+v3s16(0,2,-1), n);
2550                                 if(rand()%3!=0) sector->setNode(gp+v3s16(0,2,1), n);
2551                                 /*if(rand()%3!=0) sector->setNode(gp+v3s16(1,2,1), n);
2552                                 if(rand()%3!=0) sector->setNode(gp+v3s16(-1,2,1), n);
2553                                 if(rand()%3!=0) sector->setNode(gp+v3s16(-1,2,-1), n);
2554                                 if(rand()%3!=0) sector->setNode(gp+v3s16(1,2,-1), n);*/
2555                                 
2556                                 // Objects are identified by wanted position
2557                                 objects_to_remove.push_back(p);
2558                                 
2559                                 // Lighting has to be recalculated for this one.
2560                                 sector->getBlocksInArea(p_min, p_max, 
2561                                                 lighting_invalidated_blocks);
2562                         }
2563                 }
2564                 else if(d == SECTOR_OBJECT_BUSH_1)
2565                 {
2566                         if(ground_found == false)
2567                                 continue;
2568                         
2569                         if(sector->isValidArea(gp + v3s16(0,0,0),
2570                                         gp + v3s16(0,0,0), &changed_blocks_sector))
2571                         {
2572                                 MapNode n;
2573                                 n.d = CONTENT_LEAVES;
2574                                 sector->setNode(gp+v3s16(0,0,0), n);
2575                                 
2576                                 // Objects are identified by wanted position
2577                                 objects_to_remove.push_back(p);
2578                         }
2579                 }
2580                 else if(d == SECTOR_OBJECT_RAVINE)
2581                 {
2582                         s16 maxdepth = -20;
2583                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
2584                         v3s16 p_max = p + v3s16(6,6,6);
2585                         if(sector->isValidArea(p_min, p_max,
2586                                         &changed_blocks_sector))
2587                         {
2588                                 MapNode n;
2589                                 n.d = CONTENT_STONE;
2590                                 MapNode n2;
2591                                 n2.d = CONTENT_AIR;
2592                                 s16 depth = maxdepth + (myrand()%10);
2593                                 s16 z = 0;
2594                                 s16 minz = -6 - (-2);
2595                                 s16 maxz = 6 -1;
2596                                 for(s16 x=-6; x<=6; x++)
2597                                 {
2598                                         z += -1 + (myrand()%3);
2599                                         if(z < minz)
2600                                                 z = minz;
2601                                         if(z > maxz)
2602                                                 z = maxz;
2603                                         for(s16 y=depth+(myrand()%2); y<=6; y++)
2604                                         {
2605                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
2606                                                                 <<std::endl;*/
2607                                                 {
2608                                                         v3s16 p2 = p + v3s16(x,y,z-2);
2609                                                         if(is_ground_content(sector->getNode(p2).d)
2610                                                                         && !is_mineral(sector->getNode(p2).d))
2611                                                                 sector->setNode(p2, n);
2612                                                 }
2613                                                 {
2614                                                         v3s16 p2 = p + v3s16(x,y,z-1);
2615                                                         if(is_ground_content(sector->getNode(p2).d)
2616                                                                         && !is_mineral(sector->getNode(p2).d))
2617                                                                 sector->setNode(p2, n2);
2618                                                 }
2619                                                 {
2620                                                         v3s16 p2 = p + v3s16(x,y,z+0);
2621                                                         if(is_ground_content(sector->getNode(p2).d)
2622                                                                         && !is_mineral(sector->getNode(p2).d))
2623                                                                 sector->setNode(p2, n2);
2624                                                 }
2625                                                 {
2626                                                         v3s16 p2 = p + v3s16(x,y,z+1);
2627                                                         if(is_ground_content(sector->getNode(p2).d)
2628                                                                         && !is_mineral(sector->getNode(p2).d))
2629                                                                 sector->setNode(p2, n);
2630                                                 }
2631
2632                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
2633                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
2634                                         }
2635                                 }
2636                                 
2637                                 objects_to_remove.push_back(p);
2638                                 
2639                                 // Lighting has to be recalculated for this one.
2640                                 sector->getBlocksInArea(p_min, p_max, 
2641                                                 lighting_invalidated_blocks);
2642                         }
2643                 }
2644                 else
2645                 {
2646                         dstream<<"ServerMap::emergeBlock(): "
2647                                         "Invalid heightmap object"
2648                                         <<std::endl;
2649                 }
2650
2651                 }//try
2652                 catch(InvalidPositionException &e)
2653                 {
2654                         dstream<<"WARNING: "<<__FUNCTION_NAME
2655                                         <<": while inserting object "<<(int)d
2656                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
2657                                         <<" InvalidPositionException.what()="
2658                                         <<e.what()<<std::endl;
2659                         // This is not too fatal and seems to happen sometimes.
2660                         assert(0);
2661                 }
2662         }
2663
2664         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
2665                         i != objects_to_remove.end(); i++)
2666         {
2667                 objects->remove(*i);
2668         }
2669
2670         /*
2671                 Initially update sunlight
2672         */
2673         
2674         {
2675                 core::map<v3s16, bool> light_sources;
2676                 bool black_air_left = false;
2677                 bool bottom_invalid =
2678                                 block->propagateSunlight(light_sources, true, &black_air_left);
2679
2680                 // If sunlight didn't reach everywhere and part of block is
2681                 // above ground, lighting has to be properly updated
2682                 if(black_air_left && some_part_underground)
2683                 {
2684                         lighting_invalidated_blocks[block->getPos()] = block;
2685                 }
2686         }
2687
2688         /*
2689                 Translate sector's changed blocks to global changed blocks
2690         */
2691         
2692         for(core::map<s16, MapBlock*>::Iterator
2693                         i = changed_blocks_sector.getIterator();
2694                         i.atEnd() == false; i++)
2695         {
2696                 MapBlock *block = i.getNode()->getValue();
2697
2698                 changed_blocks.insert(block->getPos(), block);
2699         }
2700         
2701         if(HAXMODE)
2702         {
2703                 // Don't calculate lighting at all
2704                 lighting_invalidated_blocks.clear();
2705         }
2706
2707         return block;
2708 }
2709
2710 void ServerMap::createDir(std::string path)
2711 {
2712         if(fs::CreateDir(path) == false)
2713         {
2714                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2715                                 <<"\""<<path<<"\""<<std::endl;
2716                 throw BaseException("ServerMap failed to create directory");
2717         }
2718 }
2719
2720 std::string ServerMap::getSectorSubDir(v2s16 pos)
2721 {
2722         char cc[9];
2723         snprintf(cc, 9, "%.4x%.4x",
2724                         (unsigned int)pos.X&0xffff,
2725                         (unsigned int)pos.Y&0xffff);
2726
2727         return std::string(cc);
2728 }
2729
2730 std::string ServerMap::getSectorDir(v2s16 pos)
2731 {
2732         return m_savedir + "/sectors/" + getSectorSubDir(pos);
2733 }
2734
2735 v2s16 ServerMap::getSectorPos(std::string dirname)
2736 {
2737         if(dirname.size() != 8)
2738                 throw InvalidFilenameException("Invalid sector directory name");
2739         unsigned int x, y;
2740         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
2741         if(r != 2)
2742                 throw InvalidFilenameException("Invalid sector directory name");
2743         v2s16 pos((s16)x, (s16)y);
2744         return pos;
2745 }
2746
2747 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2748 {
2749         v2s16 p2d = getSectorPos(sectordir);
2750
2751         if(blockfile.size() != 4){
2752                 throw InvalidFilenameException("Invalid block filename");
2753         }
2754         unsigned int y;
2755         int r = sscanf(blockfile.c_str(), "%4x", &y);
2756         if(r != 1)
2757                 throw InvalidFilenameException("Invalid block filename");
2758         return v3s16(p2d.X, y, p2d.Y);
2759 }
2760
2761 // Debug helpers
2762 #define ENABLE_SECTOR_SAVING 1
2763 #define ENABLE_SECTOR_LOADING 1
2764 #define ENABLE_BLOCK_SAVING 1
2765 #define ENABLE_BLOCK_LOADING 1
2766
2767 void ServerMap::save(bool only_changed)
2768 {
2769         DSTACK(__FUNCTION_NAME);
2770         if(m_map_saving_enabled == false)
2771         {
2772                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2773                 return;
2774         }
2775         
2776         if(only_changed == false)
2777                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2778                                 <<std::endl;
2779         
2780         saveMasterHeightmap();
2781         
2782         u32 sector_meta_count = 0;
2783         u32 block_count = 0;
2784         
2785         { //sectorlock
2786         JMutexAutoLock lock(m_sector_mutex);
2787         
2788         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2789         for(; i.atEnd() == false; i++)
2790         {
2791                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2792                 assert(sector->getId() == MAPSECTOR_SERVER);
2793                 
2794                 if(ENABLE_SECTOR_SAVING)
2795                 {
2796                         if(sector->differs_from_disk || only_changed == false)
2797                         {
2798                                 saveSectorMeta(sector);
2799                                 sector_meta_count++;
2800                         }
2801                 }
2802                 if(ENABLE_BLOCK_SAVING)
2803                 {
2804                         core::list<MapBlock*> blocks;
2805                         sector->getBlocks(blocks);
2806                         core::list<MapBlock*>::Iterator j;
2807                         for(j=blocks.begin(); j!=blocks.end(); j++)
2808                         {
2809                                 MapBlock *block = *j;
2810                                 if(block->getChangedFlag() || only_changed == false)
2811                                 {
2812                                         saveBlock(block);
2813                                         block_count++;
2814                                 }
2815                         }
2816                 }
2817         }
2818
2819         }//sectorlock
2820         
2821         /*
2822                 Only print if something happened or saved whole map
2823         */
2824         if(only_changed == false || sector_meta_count != 0
2825                         || block_count != 0)
2826         {
2827                 dstream<<DTIME<<"ServerMap: Written: "
2828                                 <<sector_meta_count<<" sector metadata files, "
2829                                 <<block_count<<" block files"
2830                                 <<std::endl;
2831         }
2832 }
2833
2834 void ServerMap::loadAll()
2835 {
2836         DSTACK(__FUNCTION_NAME);
2837         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
2838
2839         loadMasterHeightmap();
2840
2841         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
2842
2843         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
2844         
2845         JMutexAutoLock lock(m_sector_mutex);
2846         
2847         s32 counter = 0;
2848         s32 printed_counter = -100000;
2849         s32 count = list.size();
2850
2851         std::vector<fs::DirListNode>::iterator i;
2852         for(i=list.begin(); i!=list.end(); i++)
2853         {
2854                 if(counter > printed_counter + 10)
2855                 {
2856                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
2857                         printed_counter = counter;
2858                 }
2859                 counter++;
2860
2861                 MapSector *sector = NULL;
2862
2863                 // We want directories
2864                 if(i->dir == false)
2865                         continue;
2866                 try{
2867                         sector = loadSectorMeta(i->name);
2868                 }
2869                 catch(InvalidFilenameException &e)
2870                 {
2871                         // This catches unknown crap in directory
2872                 }
2873                 
2874                 if(ENABLE_BLOCK_LOADING)
2875                 {
2876                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2877                                         (m_savedir+"/sectors/"+i->name);
2878                         std::vector<fs::DirListNode>::iterator i2;
2879                         for(i2=list2.begin(); i2!=list2.end(); i2++)
2880                         {
2881                                 // We want files
2882                                 if(i2->dir)
2883                                         continue;
2884                                 try{
2885                                         loadBlock(i->name, i2->name, sector);
2886                                 }
2887                                 catch(InvalidFilenameException &e)
2888                                 {
2889                                         // This catches unknown crap in directory
2890                                 }
2891                         }
2892                 }
2893         }
2894         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
2895 }
2896
2897 void ServerMap::saveMasterHeightmap()
2898 {
2899         DSTACK(__FUNCTION_NAME);
2900         createDir(m_savedir);
2901         
2902         std::string fullpath = m_savedir + "/master_heightmap";
2903         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2904         if(o.good() == false)
2905                 throw FileNotGoodException("Cannot open master heightmap");
2906         
2907         // Format used for writing
2908         u8 version = SER_FMT_VER_HIGHEST;
2909
2910 #if 0
2911         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
2912         /*
2913                 [0] u8 serialization version
2914                 [1] X master heightmap
2915         */
2916         u32 fullsize = 1 + hmdata.getSize();
2917         SharedBuffer<u8> data(fullsize);
2918
2919         data[0] = version;
2920         memcpy(&data[1], *hmdata, hmdata.getSize());
2921
2922         o.write((const char*)*data, fullsize);
2923 #endif
2924         
2925         m_heightmap->serialize(o, version);
2926 }
2927
2928 void ServerMap::loadMasterHeightmap()
2929 {
2930         DSTACK(__FUNCTION_NAME);
2931         std::string fullpath = m_savedir + "/master_heightmap";
2932         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2933         if(is.good() == false)
2934                 throw FileNotGoodException("Cannot open master heightmap");
2935         
2936         if(m_heightmap != NULL)
2937                 delete m_heightmap;
2938                 
2939         m_heightmap = UnlimitedHeightmap::deSerialize(is, &m_padb);
2940 }
2941
2942 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2943 {
2944         DSTACK(__FUNCTION_NAME);
2945         // Format used for writing
2946         u8 version = SER_FMT_VER_HIGHEST;
2947         // Get destination
2948         v2s16 pos = sector->getPos();
2949         createDir(m_savedir);
2950         createDir(m_savedir+"/sectors");
2951         std::string dir = getSectorDir(pos);
2952         createDir(dir);
2953         
2954         std::string fullpath = dir + "/heightmap";
2955         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2956         if(o.good() == false)
2957                 throw FileNotGoodException("Cannot open master heightmap");
2958
2959         sector->serialize(o, version);
2960         
2961         sector->differs_from_disk = false;
2962 }
2963
2964 MapSector* ServerMap::loadSectorMeta(std::string dirname)
2965 {
2966         DSTACK(__FUNCTION_NAME);
2967         // Get destination
2968         v2s16 p2d = getSectorPos(dirname);
2969         std::string dir = m_savedir + "/sectors/" + dirname;
2970         
2971         std::string fullpath = dir + "/heightmap";
2972         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2973         if(is.good() == false)
2974                 throw FileNotGoodException("Cannot open sector heightmap");
2975
2976         ServerMapSector *sector = ServerMapSector::deSerialize
2977                         (is, this, p2d, &m_hwrapper, m_sectors);
2978         
2979         sector->differs_from_disk = false;
2980
2981         return sector;
2982 }
2983
2984 bool ServerMap::loadSectorFull(v2s16 p2d)
2985 {
2986         DSTACK(__FUNCTION_NAME);
2987         std::string sectorsubdir = getSectorSubDir(p2d);
2988
2989         MapSector *sector = NULL;
2990
2991         JMutexAutoLock lock(m_sector_mutex);
2992
2993         try{
2994                 sector = loadSectorMeta(sectorsubdir);
2995         }
2996         catch(InvalidFilenameException &e)
2997         {
2998                 return false;
2999         }
3000         catch(FileNotGoodException &e)
3001         {
3002                 return false;
3003         }
3004         catch(std::exception &e)
3005         {
3006                 return false;
3007         }
3008
3009         if(ENABLE_BLOCK_LOADING)
3010         {
3011                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
3012                                 (m_savedir+"/sectors/"+sectorsubdir);
3013                 std::vector<fs::DirListNode>::iterator i2;
3014                 for(i2=list2.begin(); i2!=list2.end(); i2++)
3015                 {
3016                         // We want files
3017                         if(i2->dir)
3018                                 continue;
3019                         try{
3020                                 loadBlock(sectorsubdir, i2->name, sector);
3021                         }
3022                         catch(InvalidFilenameException &e)
3023                         {
3024                                 // This catches unknown crap in directory
3025                         }
3026                 }
3027         }
3028         return true;
3029 }
3030
3031 #if 0
3032 bool ServerMap::deFlushSector(v2s16 p2d)
3033 {
3034         DSTACK(__FUNCTION_NAME);
3035         // See if it already exists in memory
3036         try{
3037                 MapSector *sector = getSectorNoGenerate(p2d);
3038                 return true;
3039         }
3040         catch(InvalidPositionException &e)
3041         {
3042                 /*
3043                         Try to load the sector from disk.
3044                 */
3045                 if(loadSectorFull(p2d) == true)
3046                 {
3047                         return true;
3048                 }
3049         }
3050         return false;
3051 }
3052 #endif
3053
3054 void ServerMap::saveBlock(MapBlock *block)
3055 {
3056         DSTACK(__FUNCTION_NAME);
3057         /*
3058                 Dummy blocks are not written
3059         */
3060         if(block->isDummy())
3061         {
3062                 /*v3s16 p = block->getPos();
3063                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3064                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3065                 return;
3066         }
3067
3068         // Format used for writing
3069         u8 version = SER_FMT_VER_HIGHEST;
3070         // Get destination
3071         v3s16 p3d = block->getPos();
3072         v2s16 p2d(p3d.X, p3d.Z);
3073         createDir(m_savedir);
3074         createDir(m_savedir+"/sectors");
3075         std::string dir = getSectorDir(p2d);
3076         createDir(dir);
3077         
3078         // Block file is map/sectors/xxxxxxxx/xxxx
3079         char cc[5];
3080         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
3081         std::string fullpath = dir + "/" + cc;
3082         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3083         if(o.good() == false)
3084                 throw FileNotGoodException("Cannot open block data");
3085
3086         /*
3087                 [0] u8 serialization version
3088                 [1] data
3089         */
3090         o.write((char*)&version, 1);
3091         
3092         block->serialize(o, version);
3093
3094         /*
3095                 Versions up from 9 have block objects.
3096         */
3097         if(version >= 9)
3098         {
3099                 block->serializeObjects(o, version);
3100         }
3101         
3102         // We just wrote it to the disk
3103         block->resetChangedFlag();
3104 }
3105
3106 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
3107 {
3108         DSTACK(__FUNCTION_NAME);
3109
3110         try{
3111
3112         // Block file is map/sectors/xxxxxxxx/xxxx
3113         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
3114         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3115         if(is.good() == false)
3116                 throw FileNotGoodException("Cannot open block file");
3117
3118         v3s16 p3d = getBlockPos(sectordir, blockfile);
3119         v2s16 p2d(p3d.X, p3d.Z);
3120         
3121         assert(sector->getPos() == p2d);
3122         
3123         u8 version = SER_FMT_VER_INVALID;
3124         is.read((char*)&version, 1);
3125
3126         /*u32 block_size = MapBlock::serializedLength(version);
3127         SharedBuffer<u8> data(block_size);
3128         is.read((char*)*data, block_size);*/
3129
3130         // This will always return a sector because we're the server
3131         //MapSector *sector = emergeSector(p2d);
3132
3133         MapBlock *block = NULL;
3134         bool created_new = false;
3135         try{
3136                 block = sector->getBlockNoCreate(p3d.Y);
3137         }
3138         catch(InvalidPositionException &e)
3139         {
3140                 block = sector->createBlankBlockNoInsert(p3d.Y);
3141                 created_new = true;
3142         }
3143         
3144         // deserialize block data
3145         block->deSerialize(is, version);
3146         
3147         /*
3148                 Versions up from 9 have block objects.
3149         */
3150         if(version >= 9)
3151         {
3152                 block->updateObjects(is, version, NULL, 0);
3153         }
3154
3155         if(created_new)
3156                 sector->insertBlock(block);
3157         
3158         /*
3159                 Convert old formats to new and save
3160         */
3161
3162         // Save old format blocks in new format
3163         if(version < SER_FMT_VER_HIGHEST)
3164         {
3165                 saveBlock(block);
3166         }
3167         
3168         // We just loaded it from the disk, so it's up-to-date.
3169         block->resetChangedFlag();
3170
3171         }
3172         catch(SerializationError &e)
3173         {
3174                 dstream<<"WARNING: Invalid block data on disk "
3175                                 "(SerializationError). Ignoring."
3176                                 <<std::endl;
3177         }
3178 }
3179
3180 // Gets from master heightmap
3181 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
3182 {
3183         assert(m_heightmap != NULL);
3184         /*
3185                 Corner definition:
3186                 v2s16(0,0),
3187                 v2s16(1,0),
3188                 v2s16(1,1),
3189                 v2s16(0,1),
3190         */
3191         corners[0] = m_heightmap->getGroundHeight
3192                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
3193         corners[1] = m_heightmap->getGroundHeight
3194                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
3195         corners[2] = m_heightmap->getGroundHeight
3196                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
3197         corners[3] = m_heightmap->getGroundHeight
3198                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
3199 }
3200
3201 void ServerMap::PrintInfo(std::ostream &out)
3202 {
3203         out<<"ServerMap: ";
3204 }
3205
3206 #ifndef SERVER
3207
3208 /*
3209         ClientMap
3210 */
3211
3212 ClientMap::ClientMap(
3213                 Client *client,
3214                 MapDrawControl &control,
3215                 scene::ISceneNode* parent,
3216                 scene::ISceneManager* mgr,
3217                 s32 id
3218 ):
3219         Map(dout_client),
3220         scene::ISceneNode(parent, mgr, id),
3221         m_client(client),
3222         mesh(NULL),
3223         m_control(control)
3224 {
3225         mesh_mutex.Init();
3226
3227         /*m_box = core::aabbox3d<f32>(0,0,0,
3228                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
3229         /*m_box = core::aabbox3d<f32>(0,0,0,
3230                         map->getSizeNodes().X * BS,
3231                         map->getSizeNodes().Y * BS,
3232                         map->getSizeNodes().Z * BS);*/
3233         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3234                         BS*1000000,BS*1000000,BS*1000000);
3235         
3236         //setPosition(v3f(BS,BS,BS));
3237 }
3238
3239 ClientMap::~ClientMap()
3240 {
3241         JMutexAutoLock lock(mesh_mutex);
3242         
3243         if(mesh != NULL)
3244         {
3245                 mesh->drop();
3246                 mesh = NULL;
3247         }
3248 }
3249
3250 MapSector * ClientMap::emergeSector(v2s16 p2d)
3251 {
3252         DSTACK(__FUNCTION_NAME);
3253         // Check that it doesn't exist already
3254         try{
3255                 return getSectorNoGenerate(p2d);
3256         }
3257         catch(InvalidPositionException &e)
3258         {
3259         }
3260         
3261         // Create a sector with no heightmaps
3262         ClientMapSector *sector = new ClientMapSector(this, p2d);
3263         
3264         {
3265                 JMutexAutoLock lock(m_sector_mutex);
3266                 m_sectors.insert(p2d, sector);
3267         }
3268         
3269         return sector;
3270 }
3271
3272 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3273 {
3274         DSTACK(__FUNCTION_NAME);
3275         ClientMapSector *sector = NULL;
3276
3277         JMutexAutoLock lock(m_sector_mutex);
3278         
3279         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3280
3281         if(n != NULL)
3282         {
3283                 sector = (ClientMapSector*)n->getValue();
3284                 assert(sector->getId() == MAPSECTOR_CLIENT);
3285         }
3286         else
3287         {
3288                 sector = new ClientMapSector(this, p2d);
3289                 {
3290                         JMutexAutoLock lock(m_sector_mutex);
3291                         m_sectors.insert(p2d, sector);
3292                 }
3293         }
3294
3295         sector->deSerialize(is);
3296 }
3297
3298 void ClientMap::OnRegisterSceneNode()
3299 {
3300         if(IsVisible)
3301         {
3302                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3303                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3304         }
3305
3306         ISceneNode::OnRegisterSceneNode();
3307 }
3308
3309 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3310 {
3311         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3312         DSTACK(__FUNCTION_NAME);
3313
3314         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3315
3316         /*
3317                 Get time for measuring timeout.
3318                 
3319                 Measuring time is very useful for long delays when the
3320                 machine is swapping a lot.
3321         */
3322         int time1 = time(0);
3323
3324         u32 daynight_ratio = m_client->getDayNightRatio();
3325
3326         m_camera_mutex.Lock();
3327         v3f camera_position = m_camera_position;
3328         v3f camera_direction = m_camera_direction;
3329         m_camera_mutex.Unlock();
3330
3331         /*
3332                 Get all blocks and draw all visible ones
3333         */
3334
3335         v3s16 cam_pos_nodes(
3336                         camera_position.X / BS,
3337                         camera_position.Y / BS,
3338                         camera_position.Z / BS);
3339
3340         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3341
3342         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3343         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3344
3345         // Take a fair amount as we will be dropping more out later
3346         v3s16 p_blocks_min(
3347                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
3348                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
3349                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
3350         v3s16 p_blocks_max(
3351                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3352                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3353                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3354         
3355         u32 vertex_count = 0;
3356         
3357         // For limiting number of mesh updates per frame
3358         u32 mesh_update_count = 0;
3359         
3360         u32 blocks_would_have_drawn = 0;
3361         u32 blocks_drawn = 0;
3362
3363         //NOTE: The sectors map should be locked but we're not doing it
3364         // because it'd cause too much delays
3365
3366         int timecheck_counter = 0;
3367         core::map<v2s16, MapSector*>::Iterator si;
3368         si = m_sectors.getIterator();
3369         for(; si.atEnd() == false; si++)
3370         {
3371                 {
3372                         timecheck_counter++;
3373                         if(timecheck_counter > 50)
3374                         {
3375                                 int time2 = time(0);
3376                                 if(time2 > time1 + 4)
3377                                 {
3378                                         dstream<<"ClientMap::renderMap(): "
3379                                                 "Rendering takes ages, returning."
3380                                                 <<std::endl;
3381                                         return;
3382                                 }
3383                         }
3384                 }
3385
3386                 MapSector *sector = si.getNode()->getValue();
3387                 v2s16 sp = sector->getPos();
3388                 
3389                 if(m_control.range_all == false)
3390                 {
3391                         if(sp.X < p_blocks_min.X
3392                         || sp.X > p_blocks_max.X
3393                         || sp.Y < p_blocks_min.Z
3394                         || sp.Y > p_blocks_max.Z)
3395                                 continue;
3396                 }
3397
3398                 core::list< MapBlock * > sectorblocks;
3399                 sector->getBlocks(sectorblocks);
3400                 
3401                 /*
3402                         Draw blocks
3403                 */
3404
3405                 core::list< MapBlock * >::Iterator i;
3406                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3407                 {
3408                         MapBlock *block = *i;
3409
3410                         /*
3411                                 Compare block position to camera position, skip
3412                                 if not seen on display
3413                         */
3414                         
3415                         v3s16 blockpos_nodes = block->getPosRelative();
3416                         
3417                         // Block center position
3418                         v3f blockpos(
3419                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
3420                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
3421                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
3422                         );
3423
3424                         // Block position relative to camera
3425                         v3f blockpos_relative = blockpos - camera_position;
3426
3427                         // Distance in camera direction (+=front, -=back)
3428                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
3429
3430                         // Total distance
3431                         f32 d = blockpos_relative.getLength();
3432                         
3433                         if(m_control.range_all == false)
3434                         {
3435                                 // If block is far away, don't draw it
3436                                 if(d > m_control.wanted_range * BS)
3437                                 // This is nicer when fog is used
3438                                 //if((dforward+d)/2 > m_control.wanted_range * BS)
3439                                         continue;
3440                         }
3441                         
3442                         // Maximum radius of a block
3443                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
3444                         
3445                         // If block is (nearly) touching the camera, don't
3446                         // bother validating further (that is, render it anyway)
3447                         if(d > block_max_radius * 1.5)
3448                         {
3449                                 // Cosine of the angle between the camera direction
3450                                 // and the block direction (camera_direction is an unit vector)
3451                                 f32 cosangle = dforward / d;
3452                                 
3453                                 // Compensate for the size of the block
3454                                 // (as the block has to be shown even if it's a bit off FOV)
3455                                 // This is an estimate.
3456                                 cosangle += block_max_radius / dforward;
3457
3458                                 // If block is not in the field of view, skip it
3459                                 //if(cosangle < cos(FOV_ANGLE/2))
3460                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
3461                                         continue;
3462                         }
3463                         
3464                         /*
3465                                 Draw the faces of the block
3466                         */
3467 #if 1
3468                         bool mesh_expired = false;
3469                         
3470                         {
3471                                 JMutexAutoLock lock(block->mesh_mutex);
3472
3473                                 mesh_expired = block->getMeshExpired();
3474
3475                                 // Mesh has not been expired and there is no mesh:
3476                                 // block has no content
3477                                 if(block->mesh == NULL && mesh_expired == false)
3478                                         continue;
3479                         }
3480
3481                         f32 faraway = BS*50;
3482                         //f32 faraway = m_control.wanted_range * BS;
3483                         
3484                         /*
3485                                 This has to be done with the mesh_mutex unlocked
3486                         */
3487                         // Pretty random but this should work somewhat nicely
3488                         if(mesh_expired && (
3489                                         (mesh_update_count < 3
3490                                                 && (d < faraway || mesh_update_count < 2)
3491                                         )
3492                                         || 
3493                                         (m_control.range_all && mesh_update_count < 20)
3494                                 )
3495                         )
3496                         /*if(mesh_expired && mesh_update_count < 6
3497                                         && (d < faraway || mesh_update_count < 3))*/
3498                         {
3499                                 mesh_update_count++;
3500
3501                                 // Mesh has been expired: generate new mesh
3502                                 //block->updateMeshes(daynight_i);
3503                                 block->updateMesh(daynight_ratio);
3504
3505                                 mesh_expired = false;
3506                         }
3507                         
3508                         /*
3509                                 Don't draw an expired mesh that is far away
3510                         */
3511                         /*if(mesh_expired && d >= faraway)
3512                         //if(mesh_expired)
3513                         {
3514                                 // Instead, delete it
3515                                 JMutexAutoLock lock(block->mesh_mutex);
3516                                 if(block->mesh)
3517                                 {
3518                                         block->mesh->drop();
3519                                         block->mesh = NULL;
3520                                 }
3521                                 // And continue to next block
3522                                 continue;
3523                         }*/
3524 #endif
3525                         {
3526                                 JMutexAutoLock lock(block->mesh_mutex);
3527
3528                                 scene::SMesh *mesh = block->mesh;
3529
3530                                 if(mesh == NULL)
3531                                         continue;
3532                                 
3533                                 blocks_would_have_drawn++;
3534                                 if(blocks_drawn >= m_control.wanted_max_blocks
3535                                                 && m_control.range_all == false
3536                                                 && d > m_control.wanted_min_range * BS)
3537                                         continue;
3538                                 blocks_drawn++;
3539
3540                                 u32 c = mesh->getMeshBufferCount();
3541
3542                                 for(u32 i=0; i<c; i++)
3543                                 {
3544                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3545                                         const video::SMaterial& material = buf->getMaterial();
3546                                         video::IMaterialRenderer* rnd =
3547                                                         driver->getMaterialRenderer(material.MaterialType);
3548                                         bool transparent = (rnd && rnd->isTransparent());
3549                                         // Render transparent on transparent pass and likewise.
3550                                         if(transparent == is_transparent_pass)
3551                                         {
3552                                                 driver->setMaterial(buf->getMaterial());
3553                                                 driver->drawMeshBuffer(buf);
3554                                                 vertex_count += buf->getVertexCount();
3555                                         }
3556                                 }
3557                         }
3558                 } // foreach sectorblocks
3559         }
3560         
3561         m_control.blocks_drawn = blocks_drawn;
3562         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
3563
3564         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3565                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3566 }
3567
3568 v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod)
3569 {
3570         /*
3571                 Add it to all blocks touching it
3572         */
3573         v3s16 dirs[7] = {
3574                 v3s16(0,0,0), // this
3575                 v3s16(0,0,1), // back
3576                 v3s16(0,1,0), // top
3577                 v3s16(1,0,0), // right
3578                 v3s16(0,0,-1), // front
3579                 v3s16(0,-1,0), // bottom
3580                 v3s16(-1,0,0), // left
3581         };
3582         for(u16 i=0; i<7; i++)
3583         {
3584                 v3s16 p2 = p + dirs[i];
3585                 // Block position of neighbor (or requested) node
3586                 v3s16 blockpos = getNodeBlockPos(p2);
3587                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3588                 if(blockref == NULL)
3589                         continue;
3590                 // Relative position of requested node
3591                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3592                 blockref->setTempMod(relpos, mod);
3593         }
3594         return getNodeBlockPos(p);
3595 }
3596 v3s16 ClientMap::clearTempMod(v3s16 p)
3597 {
3598         v3s16 dirs[7] = {
3599                 v3s16(0,0,0), // this
3600                 v3s16(0,0,1), // back
3601                 v3s16(0,1,0), // top
3602                 v3s16(1,0,0), // right
3603                 v3s16(0,0,-1), // front
3604                 v3s16(0,-1,0), // bottom
3605                 v3s16(-1,0,0), // left
3606         };
3607         for(u16 i=0; i<7; i++)
3608         {
3609                 v3s16 p2 = p + dirs[i];
3610                 // Block position of neighbor (or requested) node
3611                 v3s16 blockpos = getNodeBlockPos(p2);
3612                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3613                 if(blockref == NULL)
3614                         continue;
3615                 // Relative position of requested node
3616                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3617                 blockref->clearTempMod(relpos);
3618         }
3619         return getNodeBlockPos(p);
3620 }
3621
3622 void ClientMap::PrintInfo(std::ostream &out)
3623 {
3624         out<<"ClientMap: ";
3625 }
3626
3627 #endif // !SERVER
3628
3629 /*
3630         MapVoxelManipulator
3631 */
3632
3633 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3634 {
3635         m_map = map;
3636 }
3637
3638 MapVoxelManipulator::~MapVoxelManipulator()
3639 {
3640         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3641                         <<std::endl;*/
3642 }
3643
3644 #if 1
3645 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3646 {
3647         TimeTaker timer1("emerge", &emerge_time);
3648
3649         // Units of these are MapBlocks
3650         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3651         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3652
3653         VoxelArea block_area_nodes
3654                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3655
3656         addArea(block_area_nodes);
3657
3658         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3659         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3660         for(s32 x=p_min.X; x<=p_max.X; x++)
3661         {
3662                 v3s16 p(x,y,z);
3663                 core::map<v3s16, bool>::Node *n;
3664                 n = m_loaded_blocks.find(p);
3665                 if(n != NULL)
3666                         continue;
3667                 
3668                 bool block_data_inexistent = false;
3669                 try
3670                 {
3671                         TimeTaker timer1("emerge load", &emerge_load_time);
3672
3673                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3674                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3675                                         <<" wanted area: ";
3676                         a.print(dstream);
3677                         dstream<<std::endl;*/
3678                         
3679                         MapBlock *block = m_map->getBlockNoCreate(p);
3680                         if(block->isDummy())
3681                                 block_data_inexistent = true;
3682                         else
3683                                 block->copyTo(*this);
3684                 }
3685                 catch(InvalidPositionException &e)
3686                 {
3687                         block_data_inexistent = true;
3688                 }
3689
3690                 if(block_data_inexistent)
3691                 {
3692                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3693                         // Fill with VOXELFLAG_INEXISTENT
3694                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3695                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3696                         {
3697                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3698                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3699                         }
3700                 }
3701
3702                 m_loaded_blocks.insert(p, true);
3703         }
3704
3705         //dstream<<"emerge done"<<std::endl;
3706 }
3707 #endif
3708
3709 #if 0
3710 void MapVoxelManipulator::emerge(VoxelArea a)
3711 {
3712         TimeTaker timer1("emerge", &emerge_time);
3713         
3714         v3s16 size = a.getExtent();
3715         
3716         VoxelArea padded = a;
3717         padded.pad(m_area.getExtent() / 4);
3718         addArea(padded);
3719
3720         for(s16 z=0; z<size.Z; z++)
3721         for(s16 y=0; y<size.Y; y++)
3722         for(s16 x=0; x<size.X; x++)
3723         {
3724                 v3s16 p(x,y,z);
3725                 s32 i = m_area.index(a.MinEdge + p);
3726                 // Don't touch nodes that have already been loaded
3727                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
3728                         continue;
3729                 try
3730                 {
3731                         TimeTaker timer1("emerge load", &emerge_load_time);
3732                         MapNode n = m_map->getNode(a.MinEdge + p);
3733                         m_data[i] = n;
3734                         m_flags[i] = 0;
3735                 }
3736                 catch(InvalidPositionException &e)
3737                 {
3738                         m_flags[i] = VOXELFLAG_INEXISTENT;
3739                 }
3740         }
3741 }
3742 #endif
3743
3744
3745 /*
3746         TODO: Add an option to only update eg. water and air nodes.
3747               This will make it interfere less with important stuff if
3748                   run on background.
3749 */
3750 void MapVoxelManipulator::blitBack
3751                 (core::map<v3s16, MapBlock*> & modified_blocks)
3752 {
3753         if(m_area.getExtent() == v3s16(0,0,0))
3754                 return;
3755         
3756         //TimeTaker timer1("blitBack");
3757         
3758         /*
3759                 Initialize block cache
3760         */
3761         v3s16 blockpos_last;
3762         MapBlock *block = NULL;
3763         bool block_checked_in_modified = false;
3764
3765         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3766         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3767         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3768         {
3769                 v3s16 p(x,y,z);
3770
3771                 u8 f = m_flags[m_area.index(p)];
3772                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3773                         continue;
3774
3775                 MapNode &n = m_data[m_area.index(p)];
3776                         
3777                 v3s16 blockpos = getNodeBlockPos(p);
3778                 
3779                 try
3780                 {
3781                         // Get block
3782                         if(block == NULL || blockpos != blockpos_last){
3783                                 block = m_map->getBlockNoCreate(blockpos);
3784                                 blockpos_last = blockpos;
3785                                 block_checked_in_modified = false;
3786                         }
3787                         
3788                         // Calculate relative position in block
3789                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3790
3791                         // Don't continue if nothing has changed here
3792                         if(block->getNode(relpos) == n)
3793                                 continue;
3794
3795                         //m_map->setNode(m_area.MinEdge + p, n);
3796                         block->setNode(relpos, n);
3797                         
3798                         /*
3799                                 Make sure block is in modified_blocks
3800                         */
3801                         if(block_checked_in_modified == false)
3802                         {
3803                                 modified_blocks[blockpos] = block;
3804                                 block_checked_in_modified = true;
3805                         }
3806                 }
3807                 catch(InvalidPositionException &e)
3808                 {
3809                 }
3810         }
3811 }
3812
3813 //END