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