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