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