d48003d4acb31a7a6b100407388d3ed11c5b35c9
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "main.h"
22 #include "jmutexautolock.h"
23 #include "client.h"
24 #include "filesys.h"
25 #include "utility.h"
26 #include "voxel.h"
27 #include "porting.h"
28 #include "mineral.h"
29 #include "noise.h"
30
31 /*
32         Map
33 */
34
35 Map::Map(std::ostream &dout):
36         m_dout(dout),
37         m_sector_cache(NULL)
38 {
39         m_sector_mutex.Init();
40         assert(m_sector_mutex.IsInitialized());
41 }
42
43 Map::~Map()
44 {
45         /*
46                 Free all MapSectors
47         */
48         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
49         for(; i.atEnd() == false; i++)
50         {
51                 MapSector *sector = i.getNode()->getValue();
52                 delete sector;
53         }
54 }
55
56 void Map::addEventReceiver(MapEventReceiver *event_receiver)
57 {
58         m_event_receivers.insert(event_receiver, false);
59 }
60
61 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
62 {
63         if(m_event_receivers.find(event_receiver) == NULL)
64                 return;
65         m_event_receivers.remove(event_receiver);
66 }
67
68 void Map::dispatchEvent(MapEditEvent *event)
69 {
70         for(core::map<MapEventReceiver*, bool>::Iterator
71                         i = m_event_receivers.getIterator();
72                         i.atEnd()==false; i++)
73         {
74                 MapEventReceiver* event_receiver = i.getNode()->getKey();
75                 event_receiver->onMapEditEvent(event);
76         }
77 }
78
79 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
80 {
81         if(m_sector_cache != NULL && p == m_sector_cache_p){
82                 MapSector * sector = m_sector_cache;
83                 // Reset inactivity timer
84                 sector->usage_timer = 0.0;
85                 return sector;
86         }
87         
88         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
89         
90         if(n == NULL)
91                 return NULL;
92         
93         MapSector *sector = n->getValue();
94         
95         // Cache the last result
96         m_sector_cache_p = p;
97         m_sector_cache = sector;
98
99         // Reset inactivity timer
100         sector->usage_timer = 0.0;
101         return sector;
102 }
103
104 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
105 {
106         JMutexAutoLock lock(m_sector_mutex);
107
108         return getSectorNoGenerateNoExNoLock(p);
109 }
110
111 MapSector * Map::getSectorNoGenerate(v2s16 p)
112 {
113         MapSector *sector = getSectorNoGenerateNoEx(p);
114         if(sector == NULL)
115                 throw InvalidPositionException();
116         
117         return sector;
118 }
119
120 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
121 {       
122         v2s16 p2d(p3d.X, p3d.Z);
123         MapSector * sector = getSectorNoGenerate(p2d);
124
125         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
126
127         return block;
128 }
129
130 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
131 {
132         try
133         {
134                 v2s16 p2d(p3d.X, p3d.Z);
135                 MapSector * sector = getSectorNoGenerate(p2d);
136                 MapBlock *block = sector->getBlockNoCreate(p3d.Y);
137                 return block;
138         }
139         catch(InvalidPositionException &e)
140         {
141                 return NULL;
142         }
143 }
144
145 /*MapBlock * Map::getBlockCreate(v3s16 p3d)
146 {
147         v2s16 p2d(p3d.X, p3d.Z);
148         MapSector * sector = getSectorCreate(p2d);
149         assert(sector);
150         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
151         if(block)
152                 return block;
153         block = sector->createBlankBlock(p3d.Y);
154         return block;
155 }*/
156
157 bool Map::isNodeUnderground(v3s16 p)
158 {
159         v3s16 blockpos = getNodeBlockPos(p);
160         try{
161                 MapBlock * block = getBlockNoCreate(blockpos);
162                 return block->getIsUnderground();
163         }
164         catch(InvalidPositionException &e)
165         {
166                 return false;
167         }
168 }
169
170 /*
171         Goes recursively through the neighbours of the node.
172
173         Alters only transparent nodes.
174
175         If the lighting of the neighbour is lower than the lighting of
176         the node was (before changing it to 0 at the step before), the
177         lighting of the neighbour is set to 0 and then the same stuff
178         repeats for the neighbour.
179
180         The ending nodes of the routine are stored in light_sources.
181         This is useful when a light is removed. In such case, this
182         routine can be called for the light node and then again for
183         light_sources to re-light the area without the removed light.
184
185         values of from_nodes are lighting values.
186 */
187 void Map::unspreadLight(enum LightBank bank,
188                 core::map<v3s16, u8> & from_nodes,
189                 core::map<v3s16, bool> & light_sources,
190                 core::map<v3s16, MapBlock*>  & modified_blocks)
191 {
192         v3s16 dirs[6] = {
193                 v3s16(0,0,1), // back
194                 v3s16(0,1,0), // top
195                 v3s16(1,0,0), // right
196                 v3s16(0,0,-1), // front
197                 v3s16(0,-1,0), // bottom
198                 v3s16(-1,0,0), // left
199         };
200         
201         if(from_nodes.size() == 0)
202                 return;
203         
204         u32 blockchangecount = 0;
205
206         core::map<v3s16, u8> unlighted_nodes;
207         core::map<v3s16, u8>::Iterator j;
208         j = from_nodes.getIterator();
209
210         /*
211                 Initialize block cache
212         */
213         v3s16 blockpos_last;
214         MapBlock *block = NULL;
215         // Cache this a bit, too
216         bool block_checked_in_modified = false;
217         
218         for(; j.atEnd() == false; j++)
219         {
220                 v3s16 pos = j.getNode()->getKey();
221                 v3s16 blockpos = getNodeBlockPos(pos);
222                 
223                 // Only fetch a new block if the block position has changed
224                 try{
225                         if(block == NULL || blockpos != blockpos_last){
226                                 block = getBlockNoCreate(blockpos);
227                                 blockpos_last = blockpos;
228
229                                 block_checked_in_modified = false;
230                                 blockchangecount++;
231                         }
232                 }
233                 catch(InvalidPositionException &e)
234                 {
235                         continue;
236                 }
237
238                 if(block->isDummy())
239                         continue;
240
241                 // Calculate relative position in block
242                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
243
244                 // Get node straight from the block
245                 MapNode n = block->getNode(relpos);
246                 
247                 u8 oldlight = j.getNode()->getValue();
248                 
249                 // Loop through 6 neighbors
250                 for(u16 i=0; i<6; i++)
251                 {
252                         // Get the position of the neighbor node
253                         v3s16 n2pos = pos + dirs[i];
254                         
255                         // Get the block where the node is located
256                         v3s16 blockpos = getNodeBlockPos(n2pos);
257
258                         try
259                         {
260                                 // Only fetch a new block if the block position has changed
261                                 try{
262                                         if(block == NULL || blockpos != blockpos_last){
263                                                 block = getBlockNoCreate(blockpos);
264                                                 blockpos_last = blockpos;
265
266                                                 block_checked_in_modified = false;
267                                                 blockchangecount++;
268                                         }
269                                 }
270                                 catch(InvalidPositionException &e)
271                                 {
272                                         continue;
273                                 }
274                                 
275                                 // Calculate relative position in block
276                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
277                                 // Get node straight from the block
278                                 MapNode n2 = block->getNode(relpos);
279                                 
280                                 bool changed = false;
281
282                                 //TODO: Optimize output by optimizing light_sources?
283
284                                 /*
285                                         If the neighbor is dimmer than what was specified
286                                         as oldlight (the light of the previous node)
287                                 */
288                                 if(n2.getLight(bank) < oldlight)
289                                 {
290                                         /*
291                                                 And the neighbor is transparent and it has some light
292                                         */
293                                         if(n2.light_propagates() && n2.getLight(bank) != 0)
294                                         {
295                                                 /*
296                                                         Set light to 0 and add to queue
297                                                 */
298
299                                                 u8 current_light = n2.getLight(bank);
300                                                 n2.setLight(bank, 0);
301                                                 block->setNode(relpos, n2);
302
303                                                 unlighted_nodes.insert(n2pos, current_light);
304                                                 changed = true;
305
306                                                 /*
307                                                         Remove from light_sources if it is there
308                                                         NOTE: This doesn't happen nearly at all
309                                                 */
310                                                 /*if(light_sources.find(n2pos))
311                                                 {
312                                                         std::cout<<"Removed from light_sources"<<std::endl;
313                                                         light_sources.remove(n2pos);
314                                                 }*/
315                                         }
316                                         
317                                         /*// DEBUG
318                                         if(light_sources.find(n2pos) != NULL)
319                                                 light_sources.remove(n2pos);*/
320                                 }
321                                 else{
322                                         light_sources.insert(n2pos, true);
323                                 }
324
325                                 // Add to modified_blocks
326                                 if(changed == true && block_checked_in_modified == false)
327                                 {
328                                         // If the block is not found in modified_blocks, add.
329                                         if(modified_blocks.find(blockpos) == NULL)
330                                         {
331                                                 modified_blocks.insert(blockpos, block);
332                                         }
333                                         block_checked_in_modified = true;
334                                 }
335                         }
336                         catch(InvalidPositionException &e)
337                         {
338                                 continue;
339                         }
340                 }
341         }
342
343         /*dstream<<"unspreadLight(): Changed block "
344                         <<blockchangecount<<" times"
345                         <<" for "<<from_nodes.size()<<" nodes"
346                         <<std::endl;*/
347         
348         if(unlighted_nodes.size() > 0)
349                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
350 }
351
352 /*
353         A single-node wrapper of the above
354 */
355 void Map::unLightNeighbors(enum LightBank bank,
356                 v3s16 pos, u8 lightwas,
357                 core::map<v3s16, bool> & light_sources,
358                 core::map<v3s16, MapBlock*>  & modified_blocks)
359 {
360         core::map<v3s16, u8> from_nodes;
361         from_nodes.insert(pos, lightwas);
362
363         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
364 }
365
366 /*
367         Lights neighbors of from_nodes, collects all them and then
368         goes on recursively.
369 */
370 void Map::spreadLight(enum LightBank bank,
371                 core::map<v3s16, bool> & from_nodes,
372                 core::map<v3s16, MapBlock*> & modified_blocks)
373 {
374         const v3s16 dirs[6] = {
375                 v3s16(0,0,1), // back
376                 v3s16(0,1,0), // top
377                 v3s16(1,0,0), // right
378                 v3s16(0,0,-1), // front
379                 v3s16(0,-1,0), // bottom
380                 v3s16(-1,0,0), // left
381         };
382
383         if(from_nodes.size() == 0)
384                 return;
385         
386         u32 blockchangecount = 0;
387
388         core::map<v3s16, bool> lighted_nodes;
389         core::map<v3s16, bool>::Iterator j;
390         j = from_nodes.getIterator();
391
392         /*
393                 Initialize block cache
394         */
395         v3s16 blockpos_last;
396         MapBlock *block = NULL;
397         // Cache this a bit, too
398         bool block_checked_in_modified = false;
399         
400         for(; j.atEnd() == false; j++)
401         //for(; j != from_nodes.end(); j++)
402         {
403                 v3s16 pos = j.getNode()->getKey();
404                 //v3s16 pos = *j;
405                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
406                 v3s16 blockpos = getNodeBlockPos(pos);
407                 
408                 // Only fetch a new block if the block position has changed
409                 try{
410                         if(block == NULL || blockpos != blockpos_last){
411                                 block = getBlockNoCreate(blockpos);
412                                 blockpos_last = blockpos;
413
414                                 block_checked_in_modified = false;
415                                 blockchangecount++;
416                         }
417                 }
418                 catch(InvalidPositionException &e)
419                 {
420                         continue;
421                 }
422
423                 if(block->isDummy())
424                         continue;
425
426                 // Calculate relative position in block
427                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
428
429                 // Get node straight from the block
430                 MapNode n = block->getNode(relpos);
431
432                 u8 oldlight = n.getLight(bank);
433                 u8 newlight = diminish_light(oldlight);
434
435                 // Loop through 6 neighbors
436                 for(u16 i=0; i<6; i++){
437                         // Get the position of the neighbor node
438                         v3s16 n2pos = pos + dirs[i];
439                         
440                         // Get the block where the node is located
441                         v3s16 blockpos = getNodeBlockPos(n2pos);
442
443                         try
444                         {
445                                 // Only fetch a new block if the block position has changed
446                                 try{
447                                         if(block == NULL || blockpos != blockpos_last){
448                                                 block = getBlockNoCreate(blockpos);
449                                                 blockpos_last = blockpos;
450
451                                                 block_checked_in_modified = false;
452                                                 blockchangecount++;
453                                         }
454                                 }
455                                 catch(InvalidPositionException &e)
456                                 {
457                                         continue;
458                                 }
459                                 
460                                 // Calculate relative position in block
461                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
462                                 // Get node straight from the block
463                                 MapNode n2 = block->getNode(relpos);
464                                 
465                                 bool changed = false;
466                                 /*
467                                         If the neighbor is brighter than the current node,
468                                         add to list (it will light up this node on its turn)
469                                 */
470                                 if(n2.getLight(bank) > undiminish_light(oldlight))
471                                 {
472                                         lighted_nodes.insert(n2pos, true);
473                                         //lighted_nodes.push_back(n2pos);
474                                         changed = true;
475                                 }
476                                 /*
477                                         If the neighbor is dimmer than how much light this node
478                                         would spread on it, add to list
479                                 */
480                                 if(n2.getLight(bank) < newlight)
481                                 {
482                                         if(n2.light_propagates())
483                                         {
484                                                 n2.setLight(bank, newlight);
485                                                 block->setNode(relpos, n2);
486                                                 lighted_nodes.insert(n2pos, true);
487                                                 //lighted_nodes.push_back(n2pos);
488                                                 changed = true;
489                                         }
490                                 }
491
492                                 // Add to modified_blocks
493                                 if(changed == true && block_checked_in_modified == false)
494                                 {
495                                         // If the block is not found in modified_blocks, add.
496                                         if(modified_blocks.find(blockpos) == NULL)
497                                         {
498                                                 modified_blocks.insert(blockpos, block);
499                                         }
500                                         block_checked_in_modified = true;
501                                 }
502                         }
503                         catch(InvalidPositionException &e)
504                         {
505                                 continue;
506                         }
507                 }
508         }
509
510         /*dstream<<"spreadLight(): Changed block "
511                         <<blockchangecount<<" times"
512                         <<" for "<<from_nodes.size()<<" nodes"
513                         <<std::endl;*/
514         
515         if(lighted_nodes.size() > 0)
516                 spreadLight(bank, lighted_nodes, modified_blocks);
517 }
518
519 /*
520         A single-node source variation of the above.
521 */
522 void Map::lightNeighbors(enum LightBank bank,
523                 v3s16 pos,
524                 core::map<v3s16, MapBlock*> & modified_blocks)
525 {
526         core::map<v3s16, bool> from_nodes;
527         from_nodes.insert(pos, true);
528         spreadLight(bank, from_nodes, modified_blocks);
529 }
530
531 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
532 {
533         v3s16 dirs[6] = {
534                 v3s16(0,0,1), // back
535                 v3s16(0,1,0), // top
536                 v3s16(1,0,0), // right
537                 v3s16(0,0,-1), // front
538                 v3s16(0,-1,0), // bottom
539                 v3s16(-1,0,0), // left
540         };
541         
542         u8 brightest_light = 0;
543         v3s16 brightest_pos(0,0,0);
544         bool found_something = false;
545
546         // Loop through 6 neighbors
547         for(u16 i=0; i<6; i++){
548                 // Get the position of the neighbor node
549                 v3s16 n2pos = p + dirs[i];
550                 MapNode n2;
551                 try{
552                         n2 = getNode(n2pos);
553                 }
554                 catch(InvalidPositionException &e)
555                 {
556                         continue;
557                 }
558                 if(n2.getLight(bank) > brightest_light || found_something == false){
559                         brightest_light = n2.getLight(bank);
560                         brightest_pos = n2pos;
561                         found_something = true;
562                 }
563         }
564
565         if(found_something == false)
566                 throw InvalidPositionException();
567                 
568         return brightest_pos;
569 }
570
571 /*
572         Propagates sunlight down from a node.
573         Starting point gets sunlight.
574
575         Returns the lowest y value of where the sunlight went.
576
577         Mud is turned into grass in where the sunlight stops.
578 */
579 s16 Map::propagateSunlight(v3s16 start,
580                 core::map<v3s16, MapBlock*> & modified_blocks)
581 {
582         s16 y = start.Y;
583         for(; ; y--)
584         {
585                 v3s16 pos(start.X, y, start.Z);
586                 
587                 v3s16 blockpos = getNodeBlockPos(pos);
588                 MapBlock *block;
589                 try{
590                         block = getBlockNoCreate(blockpos);
591                 }
592                 catch(InvalidPositionException &e)
593                 {
594                         break;
595                 }
596
597                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
598                 MapNode n = block->getNode(relpos);
599
600                 if(n.sunlight_propagates())
601                 {
602                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
603                         block->setNode(relpos, n);
604
605                         modified_blocks.insert(blockpos, block);
606                 }
607                 else
608                 {
609                         // Turn mud into grass
610                         if(n.d == CONTENT_MUD)
611                         {
612                                 n.d = CONTENT_GRASS;
613                                 block->setNode(relpos, n);
614                                 modified_blocks.insert(blockpos, block);
615                         }
616
617                         // Sunlight goes no further
618                         break;
619                 }
620         }
621         return y + 1;
622 }
623
624 void Map::updateLighting(enum LightBank bank,
625                 core::map<v3s16, MapBlock*> & a_blocks,
626                 core::map<v3s16, MapBlock*> & modified_blocks)
627 {
628         /*m_dout<<DTIME<<"Map::updateLighting(): "
629                         <<a_blocks.size()<<" blocks."<<std::endl;*/
630         
631         //TimeTaker timer("updateLighting");
632         
633         // For debugging
634         //bool debug=true;
635         //u32 count_was = modified_blocks.size();
636         
637         core::map<v3s16, MapBlock*> blocks_to_update;
638
639         core::map<v3s16, bool> light_sources;
640         
641         core::map<v3s16, u8> unlight_from;
642                 
643         core::map<v3s16, MapBlock*>::Iterator i;
644         i = a_blocks.getIterator();
645         for(; i.atEnd() == false; i++)
646         {
647                 MapBlock *block = i.getNode()->getValue();
648                 
649                 for(;;)
650                 {
651                         // Don't bother with dummy blocks.
652                         if(block->isDummy())
653                                 break;
654                 
655                         v3s16 pos = block->getPos();
656                         modified_blocks.insert(pos, block);
657
658                         blocks_to_update.insert(pos, block);
659
660                         /*
661                                 Clear all light from block
662                         */
663                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
664                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
665                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
666                         {
667                                 
668                                 try{
669                                         v3s16 p(x,y,z);
670                                         MapNode n = block->getNode(v3s16(x,y,z));
671                                         u8 oldlight = n.getLight(bank);
672                                         n.setLight(bank, 0);
673                                         block->setNode(v3s16(x,y,z), n);
674                                         
675                                         // Collect borders for unlighting
676                                         if(x==0 || x == MAP_BLOCKSIZE-1
677                                         || y==0 || y == MAP_BLOCKSIZE-1
678                                         || z==0 || z == MAP_BLOCKSIZE-1)
679                                         {
680                                                 v3s16 p_map = p + v3s16(
681                                                                 MAP_BLOCKSIZE*pos.X,
682                                                                 MAP_BLOCKSIZE*pos.Y,
683                                                                 MAP_BLOCKSIZE*pos.Z);
684                                                 unlight_from.insert(p_map, oldlight);
685                                         }
686                                 }
687                                 catch(InvalidPositionException &e)
688                                 {
689                                         /*
690                                                 This would happen when dealing with a
691                                                 dummy block.
692                                         */
693                                         //assert(0);
694                                         dstream<<"updateLighting(): InvalidPositionException"
695                                                         <<std::endl;
696                                 }
697                         }
698                         
699                         if(bank == LIGHTBANK_DAY)
700                         {
701                                 bool bottom_valid = block->propagateSunlight(light_sources);
702
703                                 // If bottom is valid, we're done.
704                                 if(bottom_valid)
705                                         break;
706                         }
707                         else if(bank == LIGHTBANK_NIGHT)
708                         {
709                                 // For night lighting, sunlight is not propagated
710                                 break;
711                         }
712                         else
713                         {
714                                 // Invalid lighting bank
715                                 assert(0);
716                         }
717                                 
718                         /*dstream<<"Bottom for sunlight-propagated block ("
719                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
720                                         <<std::endl;*/
721
722                         // Bottom sunlight is not valid; get the block and loop to it
723
724                         pos.Y--;
725                         try{
726                                 block = getBlockNoCreate(pos);
727                         }
728                         catch(InvalidPositionException &e)
729                         {
730                                 assert(0);
731                         }
732                         
733                 }
734         }
735
736 #if 0
737         {
738                 TimeTaker timer("unspreadLight");
739                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
740         }
741         
742         if(debug)
743         {
744                 u32 diff = modified_blocks.size() - count_was;
745                 count_was = modified_blocks.size();
746                 dstream<<"unspreadLight modified "<<diff<<std::endl;
747         }
748
749         {
750                 TimeTaker timer("spreadLight");
751                 spreadLight(bank, light_sources, modified_blocks);
752         }
753         
754         if(debug)
755         {
756                 u32 diff = modified_blocks.size() - count_was;
757                 count_was = modified_blocks.size();
758                 dstream<<"spreadLight modified "<<diff<<std::endl;
759         }
760 #endif
761         
762         {
763                 //MapVoxelManipulator vmanip(this);
764                 
765                 // Make a manual voxel manipulator and load all the blocks
766                 // that touch the requested blocks
767                 ManualMapVoxelManipulator vmanip(this);
768                 core::map<v3s16, MapBlock*>::Iterator i;
769                 i = blocks_to_update.getIterator();
770                 for(; i.atEnd() == false; i++)
771                 {
772                         MapBlock *block = i.getNode()->getValue();
773                         v3s16 p = block->getPos();
774                         
775                         // Add all surrounding blocks
776                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
777
778                         /*
779                                 Add all surrounding blocks that have up-to-date lighting
780                                 NOTE: This doesn't quite do the job (not everything
781                                       appropriate is lighted)
782                         */
783                         /*for(s16 z=-1; z<=1; z++)
784                         for(s16 y=-1; y<=1; y++)
785                         for(s16 x=-1; x<=1; x++)
786                         {
787                                 v3s16 p(x,y,z);
788                                 MapBlock *block = getBlockNoCreateNoEx(p);
789                                 if(block == NULL)
790                                         continue;
791                                 if(block->isDummy())
792                                         continue;
793                                 if(block->getLightingExpired())
794                                         continue;
795                                 vmanip.initialEmerge(p, p);
796                         }*/
797                         
798                         // Lighting of block will be updated completely
799                         block->setLightingExpired(false);
800                 }
801
802                 {
803                         //TimeTaker timer("unSpreadLight");
804                         vmanip.unspreadLight(bank, unlight_from, light_sources);
805                 }
806                 {
807                         //TimeTaker timer("spreadLight");
808                         vmanip.spreadLight(bank, light_sources);
809                 }
810                 {
811                         //TimeTaker timer("blitBack");
812                         vmanip.blitBack(modified_blocks);
813                 }
814                 /*dstream<<"emerge_time="<<emerge_time<<std::endl;
815                 emerge_time = 0;*/
816         }
817
818         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
819 }
820
821 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
822                 core::map<v3s16, MapBlock*> & modified_blocks)
823 {
824         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
825         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
826         
827         /*
828                 Update information about whether day and night light differ
829         */
830         for(core::map<v3s16, MapBlock*>::Iterator
831                         i = modified_blocks.getIterator();
832                         i.atEnd() == false; i++)
833         {
834                 MapBlock *block = i.getNode()->getValue();
835                 block->updateDayNightDiff();
836         }
837 }
838
839 /*
840         This is called after changing a node from transparent to opaque.
841         The lighting value of the node should be left as-is after changing
842         other values. This sets the lighting value to 0.
843 */
844 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
845                 core::map<v3s16, MapBlock*> &modified_blocks)
846 {
847         /*PrintInfo(m_dout);
848         m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
849                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
850         
851         /*
852                 From this node to nodes underneath:
853                 If lighting is sunlight (1.0), unlight neighbours and
854                 set lighting to 0.
855                 Else discontinue.
856         */
857
858         v3s16 toppos = p + v3s16(0,1,0);
859         v3s16 bottompos = p + v3s16(0,-1,0);
860
861         bool node_under_sunlight = true;
862         core::map<v3s16, bool> light_sources;
863
864         /*
865                 If there is a node at top and it doesn't have sunlight,
866                 there has not been any sunlight going down.
867
868                 Otherwise there probably is.
869         */
870         try{
871                 MapNode topnode = getNode(toppos);
872
873                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
874                         node_under_sunlight = false;
875         }
876         catch(InvalidPositionException &e)
877         {
878         }
879         
880         /*
881                 If the new node doesn't propagate sunlight and there is
882                 grass below, change it to mud
883         */
884         if(content_features(n.d).sunlight_propagates == false)
885         {
886                 try{
887                         MapNode bottomnode = getNode(bottompos);
888                         
889                         if(bottomnode.d == CONTENT_GRASS
890                                         || bottomnode.d == CONTENT_GRASS_FOOTSTEPS)
891                         {
892                                 bottomnode.d = CONTENT_MUD;
893                                 setNode(bottompos, bottomnode);
894                         }
895                 }
896                 catch(InvalidPositionException &e)
897                 {
898                 }
899         }
900
901         /*
902                 If the new node is mud and it is under sunlight, change it
903                 to grass
904         */
905         if(n.d == CONTENT_MUD && node_under_sunlight)
906         {
907                 n.d = CONTENT_GRASS;
908         }
909
910         /*
911                 Remove all light that has come out of this node
912         */
913
914         enum LightBank banks[] =
915         {
916                 LIGHTBANK_DAY,
917                 LIGHTBANK_NIGHT
918         };
919         for(s32 i=0; i<2; i++)
920         {
921                 enum LightBank bank = banks[i];
922
923                 u8 lightwas = getNode(p).getLight(bank);
924
925                 // Add the block of the added node to modified_blocks
926                 v3s16 blockpos = getNodeBlockPos(p);
927                 MapBlock * block = getBlockNoCreate(blockpos);
928                 assert(block != NULL);
929                 modified_blocks.insert(blockpos, block);
930                 
931                 assert(isValidPosition(p));
932                         
933                 // Unlight neighbours of node.
934                 // This means setting light of all consequent dimmer nodes
935                 // to 0.
936                 // This also collects the nodes at the border which will spread
937                 // light again into this.
938                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
939
940                 n.setLight(bank, 0);
941         }
942
943         /*
944                 Set the node on the map
945         */
946         
947         setNode(p, n);
948         
949         /*
950                 If node is under sunlight, take all sunlighted nodes under
951                 it and clear light from them and from where the light has
952                 been spread.
953                 TODO: This could be optimized by mass-unlighting instead
954                       of looping
955         */
956         if(node_under_sunlight)
957         {
958                 s16 y = p.Y - 1;
959                 for(;; y--){
960                         //m_dout<<DTIME<<"y="<<y<<std::endl;
961                         v3s16 n2pos(p.X, y, p.Z);
962                         
963                         MapNode n2;
964                         try{
965                                 n2 = getNode(n2pos);
966                         }
967                         catch(InvalidPositionException &e)
968                         {
969                                 break;
970                         }
971
972                         if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
973                         {
974                                 unLightNeighbors(LIGHTBANK_DAY,
975                                                 n2pos, n2.getLight(LIGHTBANK_DAY),
976                                                 light_sources, modified_blocks);
977                                 n2.setLight(LIGHTBANK_DAY, 0);
978                                 setNode(n2pos, n2);
979                         }
980                         else
981                                 break;
982                 }
983         }
984         
985         for(s32 i=0; i<2; i++)
986         {
987                 enum LightBank bank = banks[i];
988                 
989                 /*
990                         Spread light from all nodes that might be capable of doing so
991                 */
992                 spreadLight(bank, light_sources, modified_blocks);
993         }
994
995         /*
996                 Update information about whether day and night light differ
997         */
998         for(core::map<v3s16, MapBlock*>::Iterator
999                         i = modified_blocks.getIterator();
1000                         i.atEnd() == false; i++)
1001         {
1002                 MapBlock *block = i.getNode()->getValue();
1003                 block->updateDayNightDiff();
1004         }
1005
1006         /*
1007                 Add neighboring liquid nodes and the node itself if it is
1008                 liquid (=water node was added) to transform queue.
1009         */
1010         v3s16 dirs[7] = {
1011                 v3s16(0,0,0), // self
1012                 v3s16(0,0,1), // back
1013                 v3s16(0,1,0), // top
1014                 v3s16(1,0,0), // right
1015                 v3s16(0,0,-1), // front
1016                 v3s16(0,-1,0), // bottom
1017                 v3s16(-1,0,0), // left
1018         };
1019         for(u16 i=0; i<7; i++)
1020         {
1021                 try
1022                 {
1023
1024                 v3s16 p2 = p + dirs[i];
1025                 
1026                 MapNode n2 = getNode(p2);
1027                 if(content_liquid(n2.d))
1028                 {
1029                         m_transforming_liquid.push_back(p2);
1030                 }
1031                 
1032                 }catch(InvalidPositionException &e)
1033                 {
1034                 }
1035         }
1036 }
1037
1038 /*
1039 */
1040 void Map::removeNodeAndUpdate(v3s16 p,
1041                 core::map<v3s16, MapBlock*> &modified_blocks)
1042 {
1043         /*PrintInfo(m_dout);
1044         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1045                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1046         
1047         bool node_under_sunlight = true;
1048         
1049         v3s16 toppos = p + v3s16(0,1,0);
1050
1051         // Node will be replaced with this
1052         u8 replace_material = CONTENT_AIR;
1053         
1054         /*
1055                 If there is a node at top and it doesn't have sunlight,
1056                 there will be no sunlight going down.
1057         */
1058         try{
1059                 MapNode topnode = getNode(toppos);
1060
1061                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1062                         node_under_sunlight = false;
1063         }
1064         catch(InvalidPositionException &e)
1065         {
1066         }
1067
1068         core::map<v3s16, bool> light_sources;
1069
1070         enum LightBank banks[] =
1071         {
1072                 LIGHTBANK_DAY,
1073                 LIGHTBANK_NIGHT
1074         };
1075         for(s32 i=0; i<2; i++)
1076         {
1077                 enum LightBank bank = banks[i];
1078         
1079                 /*
1080                         Unlight neighbors (in case the node is a light source)
1081                 */
1082                 unLightNeighbors(bank, p,
1083                                 getNode(p).getLight(bank),
1084                                 light_sources, modified_blocks);
1085         }
1086
1087         /*
1088                 Remove the node.
1089                 This also clears the lighting.
1090         */
1091
1092         MapNode n;
1093         n.d = replace_material;
1094         setNode(p, n);
1095         
1096         for(s32 i=0; i<2; i++)
1097         {
1098                 enum LightBank bank = banks[i];
1099         
1100                 /*
1101                         Recalculate lighting
1102                 */
1103                 spreadLight(bank, light_sources, modified_blocks);
1104         }
1105
1106         // Add the block of the removed node to modified_blocks
1107         v3s16 blockpos = getNodeBlockPos(p);
1108         MapBlock * block = getBlockNoCreate(blockpos);
1109         assert(block != NULL);
1110         modified_blocks.insert(blockpos, block);
1111
1112         /*
1113                 If the removed node was under sunlight, propagate the
1114                 sunlight down from it and then light all neighbors
1115                 of the propagated blocks.
1116         */
1117         if(node_under_sunlight)
1118         {
1119                 s16 ybottom = propagateSunlight(p, modified_blocks);
1120                 /*m_dout<<DTIME<<"Node was under sunlight. "
1121                                 "Propagating sunlight";
1122                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1123                 s16 y = p.Y;
1124                 for(; y >= ybottom; y--)
1125                 {
1126                         v3s16 p2(p.X, y, p.Z);
1127                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1128                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1129                                         <<std::endl;*/
1130                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1131                 }
1132         }
1133         else
1134         {
1135                 // Set the lighting of this node to 0
1136                 // TODO: Is this needed? Lighting is cleared up there already.
1137                 try{
1138                         MapNode n = getNode(p);
1139                         n.setLight(LIGHTBANK_DAY, 0);
1140                         setNode(p, n);
1141                 }
1142                 catch(InvalidPositionException &e)
1143                 {
1144                         assert(0);
1145                 }
1146         }
1147
1148         for(s32 i=0; i<2; i++)
1149         {
1150                 enum LightBank bank = banks[i];
1151         
1152                 // Get the brightest neighbour node and propagate light from it
1153                 v3s16 n2p = getBrightestNeighbour(bank, p);
1154                 try{
1155                         MapNode n2 = getNode(n2p);
1156                         lightNeighbors(bank, n2p, modified_blocks);
1157                 }
1158                 catch(InvalidPositionException &e)
1159                 {
1160                 }
1161         }
1162
1163         /*
1164                 Update information about whether day and night light differ
1165         */
1166         for(core::map<v3s16, MapBlock*>::Iterator
1167                         i = modified_blocks.getIterator();
1168                         i.atEnd() == false; i++)
1169         {
1170                 MapBlock *block = i.getNode()->getValue();
1171                 block->updateDayNightDiff();
1172         }
1173
1174         /*
1175                 Add neighboring liquid nodes to transform queue.
1176         */
1177         v3s16 dirs[6] = {
1178                 v3s16(0,0,1), // back
1179                 v3s16(0,1,0), // top
1180                 v3s16(1,0,0), // right
1181                 v3s16(0,0,-1), // front
1182                 v3s16(0,-1,0), // bottom
1183                 v3s16(-1,0,0), // left
1184         };
1185         for(u16 i=0; i<6; i++)
1186         {
1187                 try
1188                 {
1189
1190                 v3s16 p2 = p + dirs[i];
1191                 
1192                 MapNode n2 = getNode(p2);
1193                 if(content_liquid(n2.d))
1194                 {
1195                         m_transforming_liquid.push_back(p2);
1196                 }
1197                 
1198                 }catch(InvalidPositionException &e)
1199                 {
1200                 }
1201         }
1202 }
1203
1204 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1205 {
1206         MapEditEvent event;
1207         event.type = MEET_ADDNODE;
1208         event.p = p;
1209         event.n = n;
1210
1211         bool succeeded = true;
1212         try{
1213                 core::map<v3s16, MapBlock*> modified_blocks;
1214                 addNodeAndUpdate(p, n, modified_blocks);
1215
1216                 // Copy modified_blocks to event
1217                 for(core::map<v3s16, MapBlock*>::Iterator
1218                                 i = modified_blocks.getIterator();
1219                                 i.atEnd()==false; i++)
1220                 {
1221                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1222                 }
1223         }
1224         catch(InvalidPositionException &e){
1225                 succeeded = false;
1226         }
1227
1228         dispatchEvent(&event);
1229
1230         return succeeded;
1231 }
1232
1233 bool Map::removeNodeWithEvent(v3s16 p)
1234 {
1235         MapEditEvent event;
1236         event.type = MEET_REMOVENODE;
1237         event.p = p;
1238
1239         bool succeeded = true;
1240         try{
1241                 core::map<v3s16, MapBlock*> modified_blocks;
1242                 removeNodeAndUpdate(p, modified_blocks);
1243
1244                 // Copy modified_blocks to event
1245                 for(core::map<v3s16, MapBlock*>::Iterator
1246                                 i = modified_blocks.getIterator();
1247                                 i.atEnd()==false; i++)
1248                 {
1249                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1250                 }
1251         }
1252         catch(InvalidPositionException &e){
1253                 succeeded = false;
1254         }
1255
1256         dispatchEvent(&event);
1257
1258         return succeeded;
1259 }
1260
1261 bool Map::dayNightDiffed(v3s16 blockpos)
1262 {
1263         try{
1264                 v3s16 p = blockpos + v3s16(0,0,0);
1265                 MapBlock *b = getBlockNoCreate(p);
1266                 if(b->dayNightDiffed())
1267                         return true;
1268         }
1269         catch(InvalidPositionException &e){}
1270         // Leading edges
1271         try{
1272                 v3s16 p = blockpos + v3s16(-1,0,0);
1273                 MapBlock *b = getBlockNoCreate(p);
1274                 if(b->dayNightDiffed())
1275                         return true;
1276         }
1277         catch(InvalidPositionException &e){}
1278         try{
1279                 v3s16 p = blockpos + v3s16(0,-1,0);
1280                 MapBlock *b = getBlockNoCreate(p);
1281                 if(b->dayNightDiffed())
1282                         return true;
1283         }
1284         catch(InvalidPositionException &e){}
1285         try{
1286                 v3s16 p = blockpos + v3s16(0,0,-1);
1287                 MapBlock *b = getBlockNoCreate(p);
1288                 if(b->dayNightDiffed())
1289                         return true;
1290         }
1291         catch(InvalidPositionException &e){}
1292         // Trailing edges
1293         try{
1294                 v3s16 p = blockpos + v3s16(1,0,0);
1295                 MapBlock *b = getBlockNoCreate(p);
1296                 if(b->dayNightDiffed())
1297                         return true;
1298         }
1299         catch(InvalidPositionException &e){}
1300         try{
1301                 v3s16 p = blockpos + v3s16(0,1,0);
1302                 MapBlock *b = getBlockNoCreate(p);
1303                 if(b->dayNightDiffed())
1304                         return true;
1305         }
1306         catch(InvalidPositionException &e){}
1307         try{
1308                 v3s16 p = blockpos + v3s16(0,0,1);
1309                 MapBlock *b = getBlockNoCreate(p);
1310                 if(b->dayNightDiffed())
1311                         return true;
1312         }
1313         catch(InvalidPositionException &e){}
1314
1315         return false;
1316 }
1317
1318 /*
1319         Updates usage timers
1320 */
1321 void Map::timerUpdate(float dtime)
1322 {
1323         JMutexAutoLock lock(m_sector_mutex);
1324
1325         core::map<v2s16, MapSector*>::Iterator si;
1326
1327         si = m_sectors.getIterator();
1328         for(; si.atEnd() == false; si++)
1329         {
1330                 MapSector *sector = si.getNode()->getValue();
1331                 sector->usage_timer += dtime;
1332         }
1333 }
1334
1335 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
1336 {
1337         /*
1338                 Wait for caches to be removed before continuing.
1339                 
1340                 This disables the existence of caches while locked
1341         */
1342         //SharedPtr<JMutexAutoLock> cachelock(m_blockcachelock.waitCaches());
1343
1344         core::list<v2s16>::Iterator j;
1345         for(j=list.begin(); j!=list.end(); j++)
1346         {
1347                 MapSector *sector = m_sectors[*j];
1348                 if(only_blocks)
1349                 {
1350                         sector->deleteBlocks();
1351                 }
1352                 else
1353                 {
1354                         /*
1355                                 If sector is in sector cache, remove it from there
1356                         */
1357                         if(m_sector_cache == sector)
1358                         {
1359                                 m_sector_cache = NULL;
1360                         }
1361                         /*
1362                                 Remove from map and delete
1363                         */
1364                         m_sectors.remove(*j);
1365                         delete sector;
1366                 }
1367         }
1368 }
1369
1370 u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
1371                 core::list<v3s16> *deleted_blocks)
1372 {
1373         JMutexAutoLock lock(m_sector_mutex);
1374
1375         core::list<v2s16> sector_deletion_queue;
1376         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
1377         for(; i.atEnd() == false; i++)
1378         {
1379                 MapSector *sector = i.getNode()->getValue();
1380                 /*
1381                         Delete sector from memory if it hasn't been used in a long time
1382                 */
1383                 if(sector->usage_timer > timeout)
1384                 {
1385                         sector_deletion_queue.push_back(i.getNode()->getKey());
1386                         
1387                         if(deleted_blocks != NULL)
1388                         {
1389                                 // Collect positions of blocks of sector
1390                                 MapSector *sector = i.getNode()->getValue();
1391                                 core::list<MapBlock*> blocks;
1392                                 sector->getBlocks(blocks);
1393                                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1394                                                 i != blocks.end(); i++)
1395                                 {
1396                                         deleted_blocks->push_back((*i)->getPos());
1397                                 }
1398                         }
1399                 }
1400         }
1401         deleteSectors(sector_deletion_queue, only_blocks);
1402         return sector_deletion_queue.getSize();
1403 }
1404
1405 void Map::PrintInfo(std::ostream &out)
1406 {
1407         out<<"Map: ";
1408 }
1409
1410 #define WATER_DROP_BOOST 4
1411
1412 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1413 {
1414         DSTACK(__FUNCTION_NAME);
1415         //TimeTaker timer("transformLiquids()");
1416
1417         u32 loopcount = 0;
1418         u32 initial_size = m_transforming_liquid.size();
1419         
1420         /*if(initial_size != 0)
1421                 dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1422
1423         while(m_transforming_liquid.size() != 0)
1424         {
1425                 try
1426                 {
1427
1428                 /*
1429                         Get a queued transforming liquid node
1430                 */
1431                 v3s16 p0 = m_transforming_liquid.pop_front();
1432
1433                 MapNode n0 = getNode(p0);
1434                 
1435                 // Don't deal with non-liquids
1436                 if(content_liquid(n0.d) == false)
1437                         continue;
1438
1439                 bool is_source = !content_flowing_liquid(n0.d);
1440                 
1441                 u8 liquid_level = 8;
1442                 if(is_source == false)
1443                         liquid_level = n0.param2 & 0x0f;
1444                 
1445                 // Turn possible source into non-source
1446                 u8 nonsource_c = make_liquid_flowing(n0.d);
1447
1448                 /*
1449                         If not source, check that some node flows into this one
1450                         and what is the level of liquid in this one
1451                 */
1452                 if(is_source == false)
1453                 {
1454                         s8 new_liquid_level_max = -1;
1455
1456                         v3s16 dirs_from[5] = {
1457                                 v3s16(0,1,0), // top
1458                                 v3s16(0,0,1), // back
1459                                 v3s16(1,0,0), // right
1460                                 v3s16(0,0,-1), // front
1461                                 v3s16(-1,0,0), // left
1462                         };
1463                         for(u16 i=0; i<5; i++)
1464                         {
1465                                 try
1466                                 {
1467
1468                                 bool from_top = (i==0);
1469
1470                                 v3s16 p2 = p0 + dirs_from[i];
1471                                 MapNode n2 = getNode(p2);
1472
1473                                 if(content_liquid(n2.d))
1474                                 {
1475                                         u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1476                                         // Check that the liquids are the same type
1477                                         if(n2_nonsource_c != nonsource_c)
1478                                         {
1479                                                 dstream<<"WARNING: Not handling: different liquids"
1480                                                                 " collide"<<std::endl;
1481                                                 continue;
1482                                         }
1483                                         bool n2_is_source = !content_flowing_liquid(n2.d);
1484                                         s8 n2_liquid_level = 8;
1485                                         if(n2_is_source == false)
1486                                                 n2_liquid_level = n2.param2 & 0x07;
1487                                         
1488                                         s8 new_liquid_level = -1;
1489                                         if(from_top)
1490                                         {
1491                                                 //new_liquid_level = 7;
1492                                                 if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
1493                                                         new_liquid_level = 7;
1494                                                 else
1495                                                         new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
1496                                         }
1497                                         else if(n2_liquid_level > 0)
1498                                         {
1499                                                 new_liquid_level = n2_liquid_level - 1;
1500                                         }
1501
1502                                         if(new_liquid_level > new_liquid_level_max)
1503                                                 new_liquid_level_max = new_liquid_level;
1504                                 }
1505
1506                                 }catch(InvalidPositionException &e)
1507                                 {
1508                                 }
1509                         } //for
1510                         
1511                         /*
1512                                 If liquid level should be something else, update it and
1513                                 add all the neighboring water nodes to the transform queue.
1514                         */
1515                         if(new_liquid_level_max != liquid_level)
1516                         {
1517                                 if(new_liquid_level_max == -1)
1518                                 {
1519                                         // Remove water alltoghether
1520                                         n0.d = CONTENT_AIR;
1521                                         n0.param2 = 0;
1522                                         setNode(p0, n0);
1523                                 }
1524                                 else
1525                                 {
1526                                         n0.param2 = new_liquid_level_max;
1527                                         setNode(p0, n0);
1528                                 }
1529                                 
1530                                 // Block has been modified
1531                                 {
1532                                         v3s16 blockpos = getNodeBlockPos(p0);
1533                                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1534                                         if(block != NULL)
1535                                                 modified_blocks.insert(blockpos, block);
1536                                 }
1537                                 
1538                                 /*
1539                                         Add neighboring non-source liquid nodes to transform queue.
1540                                 */
1541                                 v3s16 dirs[6] = {
1542                                         v3s16(0,0,1), // back
1543                                         v3s16(0,1,0), // top
1544                                         v3s16(1,0,0), // right
1545                                         v3s16(0,0,-1), // front
1546                                         v3s16(0,-1,0), // bottom
1547                                         v3s16(-1,0,0), // left
1548                                 };
1549                                 for(u16 i=0; i<6; i++)
1550                                 {
1551                                         try
1552                                         {
1553
1554                                         v3s16 p2 = p0 + dirs[i];
1555                                         
1556                                         MapNode n2 = getNode(p2);
1557                                         if(content_flowing_liquid(n2.d))
1558                                         {
1559                                                 m_transforming_liquid.push_back(p2);
1560                                         }
1561                                         
1562                                         }catch(InvalidPositionException &e)
1563                                         {
1564                                         }
1565                                 }
1566                         }
1567                 }
1568                 
1569                 // Get a new one from queue if the node has turned into non-water
1570                 if(content_liquid(n0.d) == false)
1571                         continue;
1572
1573                 /*
1574                         Flow water from this node
1575                 */
1576                 v3s16 dirs_to[5] = {
1577                         v3s16(0,-1,0), // bottom
1578                         v3s16(0,0,1), // back
1579                         v3s16(1,0,0), // right
1580                         v3s16(0,0,-1), // front
1581                         v3s16(-1,0,0), // left
1582                 };
1583                 for(u16 i=0; i<5; i++)
1584                 {
1585                         try
1586                         {
1587
1588                         bool to_bottom = (i == 0);
1589
1590                         // If liquid is at lowest possible height, it's not going
1591                         // anywhere except down
1592                         if(liquid_level == 0 && to_bottom == false)
1593                                 continue;
1594                         
1595                         u8 liquid_next_level = 0;
1596                         // If going to bottom
1597                         if(to_bottom)
1598                         {
1599                                 //liquid_next_level = 7;
1600                                 if(liquid_level >= 7 - WATER_DROP_BOOST)
1601                                         liquid_next_level = 7;
1602                                 else
1603                                         liquid_next_level = liquid_level + WATER_DROP_BOOST;
1604                         }
1605                         else
1606                                 liquid_next_level = liquid_level - 1;
1607
1608                         bool n2_changed = false;
1609                         bool flowed = false;
1610                         
1611                         v3s16 p2 = p0 + dirs_to[i];
1612
1613                         MapNode n2 = getNode(p2);
1614                         //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
1615
1616                         if(content_liquid(n2.d))
1617                         {
1618                                 u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1619                                 // Check that the liquids are the same type
1620                                 if(n2_nonsource_c != nonsource_c)
1621                                 {
1622                                         dstream<<"WARNING: Not handling: different liquids"
1623                                                         " collide"<<std::endl;
1624                                         continue;
1625                                 }
1626                                 bool n2_is_source = !content_flowing_liquid(n2.d);
1627                                 u8 n2_liquid_level = 8;
1628                                 if(n2_is_source == false)
1629                                         n2_liquid_level = n2.param2 & 0x07;
1630                                 
1631                                 if(to_bottom)
1632                                 {
1633                                         flowed = true;
1634                                 }
1635
1636                                 if(n2_is_source)
1637                                 {
1638                                         // Just flow into the source, nothing changes.
1639                                         // n2_changed is not set because destination didn't change
1640                                         flowed = true;
1641                                 }
1642                                 else
1643                                 {
1644                                         if(liquid_next_level > liquid_level)
1645                                         {
1646                                                 n2.param2 = liquid_next_level;
1647                                                 setNode(p2, n2);
1648
1649                                                 n2_changed = true;
1650                                                 flowed = true;
1651                                         }
1652                                 }
1653                         }
1654                         else if(n2.d == CONTENT_AIR)
1655                         {
1656                                 n2.d = nonsource_c;
1657                                 n2.param2 = liquid_next_level;
1658                                 setNode(p2, n2);
1659                                 
1660                                 n2_changed = true;
1661                                 flowed = true;
1662                         }
1663                         
1664                         //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl;
1665
1666                         if(n2_changed)
1667                         {
1668                                 m_transforming_liquid.push_back(p2);
1669                                 
1670                                 v3s16 blockpos = getNodeBlockPos(p2);
1671                                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1672                                 if(block != NULL)
1673                                         modified_blocks.insert(blockpos, block);
1674                         }
1675                         
1676                         // If n2_changed to bottom, don't flow anywhere else
1677                         if(to_bottom && flowed && !is_source)
1678                                 break;
1679                                 
1680                         }catch(InvalidPositionException &e)
1681                         {
1682                         }
1683                 }
1684
1685                 loopcount++;
1686                 if(loopcount >= initial_size * 1 || loopcount >= 1000)
1687                         break;
1688                         
1689                 }catch(InvalidPositionException &e)
1690                 {
1691                 }
1692         }
1693         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1694 }
1695
1696 /*
1697         ServerMap
1698 */
1699
1700 ServerMap::ServerMap(std::string savedir):
1701         Map(dout_server),
1702         m_seed(0)
1703 {
1704         
1705         //m_chunksize = 64;
1706         //m_chunksize = 16; // Too slow
1707         //m_chunksize = 8; // Takes a few seconds
1708         m_chunksize = 4; // Too small?
1709         //m_chunksize = 2;
1710         
1711         // TODO: Save to and load from a file
1712         m_seed = (((u64)(myrand()%0xffff)<<0)
1713                         + ((u64)(myrand()%0xffff)<<16)
1714                         + ((u64)(myrand()%0xffff)<<32)
1715                         + ((u64)(myrand()%0xffff)<<48));
1716
1717         /*
1718                 Experimental and debug stuff
1719         */
1720         
1721         {
1722         }
1723         
1724         /*
1725                 Try to load map; if not found, create a new one.
1726         */
1727
1728         m_savedir = savedir;
1729         m_map_saving_enabled = false;
1730         
1731         try
1732         {
1733                 // If directory exists, check contents and load if possible
1734                 if(fs::PathExists(m_savedir))
1735                 {
1736                         // If directory is empty, it is safe to save into it.
1737                         if(fs::GetDirListing(m_savedir).size() == 0)
1738                         {
1739                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1740                                                 <<std::endl;
1741                                 m_map_saving_enabled = true;
1742                         }
1743                         else
1744                         {
1745                                 // Load map metadata (seed, chunksize)
1746                                 loadMapMeta();
1747                                 
1748                                 // Load chunk metadata
1749                                 loadChunkMeta();
1750                         
1751                                 /*// Load sector (0,0) and throw and exception on fail
1752                                 if(loadSectorFull(v2s16(0,0)) == false)
1753                                         throw LoadError("Failed to load sector (0,0)");*/
1754
1755                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1756                                                 "metadata and sector (0,0) from "<<savedir<<
1757                                                 ", assuming valid save directory."
1758                                                 <<std::endl;*/
1759
1760                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1761                                                 <<"and chunk metadata from "<<savedir
1762                                                 <<", assuming valid save directory."
1763                                                 <<std::endl;
1764
1765                                 m_map_saving_enabled = true;
1766                                 // Map loaded, not creating new one
1767                                 return;
1768                         }
1769                 }
1770                 // If directory doesn't exist, it is safe to save to it
1771                 else{
1772                         m_map_saving_enabled = true;
1773                 }
1774         }
1775         catch(std::exception &e)
1776         {
1777                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1778                                 <<", exception: "<<e.what()<<std::endl;
1779                 dstream<<"Please remove the map or fix it."<<std::endl;
1780                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1781         }
1782
1783         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1784         
1785         // Create zero sector
1786         emergeSector(v2s16(0,0));
1787
1788         // Initially write whole map
1789         save(false);
1790 }
1791
1792 ServerMap::~ServerMap()
1793 {
1794         try
1795         {
1796                 if(m_map_saving_enabled)
1797                 {
1798                         //save(false);
1799                         // Save only changed parts
1800                         save(true);
1801                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1802                 }
1803                 else
1804                 {
1805                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1806                 }
1807         }
1808         catch(std::exception &e)
1809         {
1810                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1811                                 <<", exception: "<<e.what()<<std::endl;
1812         }
1813         
1814         /*
1815                 Free all MapChunks
1816         */
1817         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1818         for(; i.atEnd() == false; i++)
1819         {
1820                 MapChunk *chunk = i.getNode()->getValue();
1821                 delete chunk;
1822         }
1823 }
1824
1825 /*
1826         Some helper functions for the map generator
1827 */
1828
1829 s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
1830 {
1831         v3s16 em = vmanip.m_area.getExtent();
1832         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1833         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1834         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1835         s16 y;
1836         for(y=y_nodes_max; y>=y_nodes_min; y--)
1837         {
1838                 MapNode &n = vmanip.m_data[i];
1839                 if(content_walkable(n.d))
1840                         break;
1841                         
1842                 vmanip.m_area.add_y(em, i, -1);
1843         }
1844         if(y >= y_nodes_min)
1845                 return y;
1846         else
1847                 return y_nodes_min;
1848 }
1849
1850 s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
1851 {
1852         v3s16 em = vmanip.m_area.getExtent();
1853         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1854         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1855         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1856         s16 y;
1857         for(y=y_nodes_max; y>=y_nodes_min; y--)
1858         {
1859                 MapNode &n = vmanip.m_data[i];
1860                 if(content_walkable(n.d)
1861                                 && n.d != CONTENT_TREE
1862                                 && n.d != CONTENT_LEAVES)
1863                         break;
1864                         
1865                 vmanip.m_area.add_y(em, i, -1);
1866         }
1867         if(y >= y_nodes_min)
1868                 return y;
1869         else
1870                 return y_nodes_min;
1871 }
1872
1873 void make_tree(VoxelManipulator &vmanip, v3s16 p0)
1874 {
1875         MapNode treenode(CONTENT_TREE);
1876         MapNode leavesnode(CONTENT_LEAVES);
1877
1878         vmanip.emerge(VoxelArea(p0-v3s16(2,0,2),p0+v3s16(2,7+2,2)));
1879
1880         s16 trunk_h = myrand_range(4, 7);
1881         v3s16 p1 = p0;
1882         for(s16 ii=0; ii<trunk_h; ii++)
1883         {
1884                 if(vmanip.m_area.contains(p1))
1885                         vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
1886                 p1.Y++;
1887         }
1888         
1889         // p1 is now the last piece of the trunk
1890         p1.Y -= 1;
1891
1892         VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
1893         //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
1894         Buffer<u8> leaves_d(leaves_a.getVolume());
1895         for(s32 i=0; i<leaves_a.getVolume(); i++)
1896                 leaves_d[i] = 0;
1897         
1898         // Force leaves at near the end of the trunk
1899         {
1900                 s16 d = 1;
1901                 for(s16 z=-d; z<=d; z++)
1902                 for(s16 y=-d; y<=d; y++)
1903                 for(s16 x=-d; x<=d; x++)
1904                 {
1905                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
1906                 }
1907         }
1908         
1909         // Add leaves randomly
1910         for(u32 iii=0; iii<7; iii++)
1911         {
1912                 s16 d = 1;
1913
1914                 v3s16 p(
1915                         myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
1916                         myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
1917                         myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
1918                 );
1919                 
1920                 for(s16 z=0; z<=d; z++)
1921                 for(s16 y=0; y<=d; y++)
1922                 for(s16 x=0; x<=d; x++)
1923                 {
1924                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
1925                 }
1926         }
1927         
1928         // Blit leaves to vmanip
1929         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
1930         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
1931         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
1932         {
1933                 v3s16 p(x,y,z);
1934                 p += p1;
1935                 if(vmanip.m_area.contains(p) == false)
1936                         continue;
1937                 u32 vi = vmanip.m_area.index(p);
1938                 if(vmanip.m_data[vi].d != CONTENT_AIR)
1939                         continue;
1940                 u32 i = leaves_a.index(x,y,z);
1941                 if(leaves_d[i] == 1)
1942                         vmanip.m_data[vi] = leavesnode;
1943         }
1944 }
1945
1946 /*
1947         Noise functions. Make sure seed is mangled differently in each one.
1948 */
1949
1950 // Amount of trees per area in nodes
1951 double tree_amount_2d(u64 seed, v2s16 p)
1952 {
1953         double noise = noise2d_perlin(
1954                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1955                         seed+2, 5, 0.66);
1956         double zeroval = -0.3;
1957         if(noise < zeroval)
1958                 return 0;
1959         else
1960                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1961 }
1962
1963 #define AVERAGE_MUD_AMOUNT 4.0
1964
1965 double get_mud_amount(u64 seed, v2f p)
1966 {
1967         return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1968                         0.5+p.X/200, 0.5+p.Y/200,
1969                         seed+1, 5, 0.65));
1970 }
1971
1972 bool get_have_sand(u64 seed, v2f p)
1973 {
1974         double sandnoise = noise2d_perlin(
1975                         0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1976                         seed+59420, 3, 0.50);
1977         return (sandnoise > -0.15);
1978 }
1979
1980 // -1->0, 0->1, 1->0
1981 double contour(double v)
1982 {
1983         v = fabs(v);
1984         if(v >= 1.0)
1985                 return 0.0;
1986         return (1.0-v);
1987 }
1988
1989 // -1->0, -r->1, 0->1, r->1, 1->0
1990 double contour_flat_top(double v, double r)
1991 {
1992         v = fabs(v);
1993         if(v >= 1.0)
1994                 return 0.0;
1995         double rmax = 0.999;
1996         if(r >= rmax)
1997                 r = rmax;
1998         if(v <= r)
1999                 return 1.0;
2000         v -= r;
2001         return ((1.0-r)-v) / (1.0-r);
2002         //return easeCurve(((1.0-r)-v) / (1.0-r));
2003 }
2004
2005 double base_rock_level_2d(u64 seed, v2f p)
2006 {
2007         // The ground level (return value)
2008         double h = WATER_LEVEL-1.5;
2009         
2010         // Raises from 0 when parameter is -1...1
2011         /*double m2 = contour_flat_top(-0.8 + 2.0 * noise2d_perlin(
2012                         0.0+(float)p.X/1500., 0.0+(float)p.Y/1500.,
2013                         (seed>>32)+34758, 5, 0.55), 0.10);*/
2014         /*double m2 = 1.0;
2015         if(m2 > 0.0001)
2016         {
2017                 // HUGE mountains
2018                 double m1 = 200.0 + 300.0 * noise2d_perlin(
2019                                 0.0+(float)p.X/1000., 0.0+(float)p.Y/1000.,
2020                                 (seed>>32)+98525, 8, 0.5);
2021                 h += m1 * m2;
2022                 //h += 30 * m2;
2023         }*/
2024
2025         /*double tm2 = contour_flat_top(-1.0 + 3.0 * noise2d_perlin(
2026                         0.0+(float)p.X/300., 0.0+(float)p.Y/300.,
2027                         (seed>>32)+78593, 5, 0.55), 0.15);
2028         h += 30 * tm2;*/
2029
2030 #if 0
2031         {
2032                 // Large mountains
2033                 double m3 = 100.0 - 600.0 * noise2d_perlin_abs(
2034                                 0.324+(float)p.X/2000., 0.423+(float)p.Y/2000.,
2035                                 (seed>>32)+985251, 9, 0.55);
2036                 if(m3 > h)
2037                         h = m3;
2038         }
2039 #endif
2040
2041 #if 0
2042         {
2043                 // More mountain ranges
2044                 double d = 100;
2045                 double a1 = d*2.0 - d*7 * noise2d_perlin_abs(
2046                                 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000.,
2047                                 seed+850342, 7, 0.55);
2048                 /*if(a1 > d)
2049                         a1 = d + sqrt(a1-d);*/
2050                 a1 = (1.0 - exp(-a1/d))*d;
2051                 /*if(a1 > h)
2052                         h = a1;*/
2053                 if(a1 > 0)
2054                         h += a1;
2055         }
2056 #endif
2057
2058 #if 0
2059         {
2060                 // More mountain ranges
2061                 double d = 60;
2062                 double a1 = d*2.0 - d*7 * noise2d_perlin_abs(
2063                                 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000.,
2064                                 seed+850342, 7, 0.55);
2065                 /*if(a1 > d)
2066                         a1 = d + sqrt(a1-d);*/
2067                 a1 = (1.0 - exp(-a1/d))*d;
2068                 /*if(a1 > h)
2069                         h = a1;*/
2070                 if(a1 > 0)
2071                         h += a1;
2072         }
2073 #endif
2074
2075 #if 0
2076         {
2077                 // Very steep mountain ranges
2078                 double d = 120;
2079                 double a1 = d*2 - d*6.5 * noise2d_perlin_abs(
2080                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2081                                 seed+850342, 6, 0.6);
2082                 /*if(a1 > d)
2083                         a1 = d + sqrt(a1-d);*/
2084                 a1 = (1.0 - exp(-a1/d))*d;
2085                 /*if(a1 > h)
2086                         h = a1;*/
2087                 if(a1 > 0)
2088                         h += a1;
2089                 /*double a = noise2d_perlin_abs(
2090                                 0.94+(float)p.X/2000., 0.26+(float)p.Y/2000.,
2091                                 (seed>>32)+65012102, 8, 0.50);
2092                 double m4 = 100.0 - 400.0 * a;
2093                 if(m4 > h)
2094                         h = m4;*/
2095         }
2096 #endif
2097         
2098         /*
2099                 The sutff before this comment is usually not used.
2100                 The stuff after this comment is usually used.
2101         */
2102
2103 #if 1
2104         {
2105                 // Pretty neat looking mountains
2106                 double m4 = 100.0 - 400.0 * noise2d_perlin_abs(
2107                                 0.324+(float)p.X/2000., 0.423+(float)p.Y/2000.,
2108                                 (seed>>32)+65012102, 7, 0.6);
2109                 if(m4 > h)
2110                         h = m4;
2111         }
2112 #endif
2113
2114 #if 1
2115         // Some kind of hill chains or something
2116         {
2117                 double a1 = 30 - 130. * noise2d_perlin_abs(
2118                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2119                                 seed+850342, 6, 0.63);
2120                 double d = 15;
2121                 if(a1 > d)
2122                         a1 = d + sqrt(a1-d);
2123                 /*if(a1 > h)
2124                         h = a1;*/
2125                 if(a1 > 0)
2126                         h += a1;
2127         }
2128 #endif
2129
2130 #if 1
2131         double base = -2. + 30. * noise2d_perlin(
2132                         0.5+(float)p.X/1000., 0.5+(float)p.Y/1000.,
2133                         (seed>>32)+653876, 7, 0.6);
2134 #else
2135         double base = 0;
2136 #endif
2137         
2138 #if 1
2139         /*
2140                 Combined with turbulence, this thing here is able to make very
2141                 awesome terrain, albeit rarely.
2142         */
2143
2144         double higher = 40. * noise2d_perlin(
2145                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2146                         seed+39292, 6, 0.50);
2147         /*double higher = 50. * noise2d_perlin_abs(
2148                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2149                         seed+85039, 5, 0.63);*/
2150         //higher = 25;
2151
2152         if(higher > base)
2153         {
2154                 // Steepness factor of cliffs
2155                 double b = 1.0 + 1.0 * noise2d_perlin(
2156                                 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2157                                 seed-932, 6, 0.7);
2158                 b = rangelim(b, 0.0, 1000.0);
2159 #if 1
2160                 b = pow(b, 5);
2161                 b *= 16;
2162                 b = rangelim(b, 3.0, 1000.0);
2163                 //dstream<<"b="<<b<<std::endl;
2164                 //double b = 20;
2165                 // Offset to more low
2166                 //double a_off = -0.30;
2167                 double a_off = -0.20;
2168                 // High/low selector
2169                 double a = (double)0.5 + b * (a_off + noise2d_perlin(
2170                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2171                                 seed-359, 7, 0.70));
2172 #endif
2173 #if 0
2174                 /*b = pow(b, 5);
2175                 b *= 2;
2176                 b = rangelim(b, 3.0, 20.0);*/
2177                 //b = 10.0;
2178                 double a = -1.5 + 5.0 * (noise2d_perlin_abs(
2179                                 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2180                                 seed-359, 6, 0.6));
2181                 a *= 3.0;
2182                 /*double a = 5.0 * (noise2d_perlin(
2183                                 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2184                                 seed-359, 5, 0.6));*/
2185                 //a = contour_flat_top(a, 0.2);
2186 #endif
2187                 // Limit
2188                 a = rangelim(a, 0.0, 1.0);
2189                 a = easeCurve(a);
2190
2191                 //dstream<<"a="<<a<<std::endl;
2192
2193                 /*double h2 = higher * a;
2194                 if(h2 > h)
2195                         h = h2;*/
2196                 
2197                 h += base*(1.0-a) + higher*a;
2198         }
2199         else
2200         {
2201                 h += base;
2202         }
2203 #else
2204         h += base;
2205 #endif
2206
2207         return h;
2208 }
2209
2210 double base_rock_level_2d(u64 seed, v2s16 p)
2211 {
2212         return base_rock_level_2d(seed, v2f((float)p.X, (float)p.Y));
2213 }
2214
2215 v2f base_ground_turbulence(u64 seed, v3f p)
2216 {
2217 #if 1
2218         double f = 20;
2219
2220 #if 1
2221         // Cut off at a minimum height
2222         {
2223                 double d = 5;
2224                 double min = WATER_LEVEL;
2225                 if(p.Y < min)
2226                         return v2f(0,0);
2227                 else if(p.Y < min + d)
2228                         f *= ((p.Y-min)/d);
2229         }
2230 #endif
2231
2232 #if 1
2233         double vv = 0.75 + 1.0 * noise3d_perlin(
2234                         0.5+p.X/250,
2235                         0.5+p.Y/250,
2236                         0.5+p.Z/250,
2237                         seed+1324381, 4, 0.5);
2238         double vve = rangelim(vv, 0.0, 1.0);
2239         /*double vv = 1.0 - 2.0 * noise3d_perlin_abs(
2240                         0.5+p.X/250,
2241                         0.5+p.Y/250,
2242                         0.5+p.Z/250,
2243                         seed+1324031, 4, 0.5);
2244         double vve = 1.0 - exp(-MYMAX(0, vv*2.0));*/
2245         //double vve = rangelim(vv, 0, 1.0);
2246         //dstream<<"vve="<<vve<<std::endl;
2247         
2248         /*// Limit turbulence near water level
2249         double a = contour((p.Y-WATER_LEVEL)/10.0);
2250         vve = (1.-a) * vve;*/
2251
2252         // Increase turbulence in elevated heights
2253         double ah = WATER_LEVEL + 40;
2254         if(p.Y > ah)
2255         {
2256                 vve *= p.Y/ah;
2257         }
2258 #else
2259         double vve = 1;
2260 #endif
2261
2262         double v1 = f * noise3d_perlin(
2263                         0.5+p.X/200,
2264                         0.5+p.Y/200,
2265                         0.5+p.Z/200,
2266                         seed+4045, 6, 0.7);
2267
2268         double v2 = f * noise3d_perlin(
2269                         0.5+p.X/200,
2270                         0.5+p.Y/200,
2271                         0.5+p.Z/200,
2272                         seed+9495, 6, 0.7);
2273         
2274         return v2f(v1*vve, v2*vve);
2275 #else
2276         return v2f(0,0);
2277 #endif
2278 }
2279
2280 bool is_carved(u64 seed, v3f p)
2281 {
2282 #if 1
2283         double v1 = noise3d_perlin_abs(
2284                         0.5+p.X/200,
2285                         0.5+p.Y/200,
2286                         0.5+p.Z/200,
2287                         seed+657890854, 5, 0.7);
2288         
2289         if(v1 > 1.45)
2290                 return true;
2291 #endif
2292
2293         double f = 10.0;
2294         double y_div = 1.5;
2295
2296         double v4 = contour(f*noise3d_perlin(
2297                         0.5+p.X/200,
2298                         0.5+p.Y/200*y_div,
2299                         0.5+p.Z/200,
2300                         seed+87592, 5, 0.7));
2301         // Tilted 90 degrees
2302         double v5 = contour(f*noise3d_perlin(
2303                         0.5+p.X/200,
2304                         0.5+p.Z/200,
2305                         0.5+p.Y/200*y_div,
2306                         seed+98594, 5, 0.7));
2307         
2308         double v45 = v4*v5;
2309         if(v45 > 2.5/f)
2310                 return true;
2311         
2312         return false;
2313 }
2314
2315 bool is_underground_mud(u64 seed, v3f p)
2316 {
2317         double v1 = noise3d_perlin_abs(
2318                         0.5+p.X/50,
2319                         0.5+p.Y/50,
2320                         0.5+p.Z/50,
2321                         seed+83401, 5, 0.75);
2322         return (v1 > 1.3);
2323 }
2324         
2325 /*
2326         if depth_guess!=NULL, it is set to a guessed value of how deep
2327         underground the position is.
2328 */
2329 bool is_base_ground(u64 seed, v3f p, double *depth_guess=NULL)
2330 {
2331 #if 0
2332         // This is used for testing the output of the cave function
2333         {
2334                 if(depth_guess)
2335                         *depth_guess = 10;
2336                 if(p.Y > 50)
2337                         return false;
2338                 return is_carved(seed, p);
2339         }
2340 #endif
2341 #if 0
2342         // This is used for testing the output of the underground mud function
2343         {
2344                 if(depth_guess)
2345                         *depth_guess = 10;
2346                 if(p.Y > 50)
2347                         return false;
2348                 return is_underground_mud(seed, p);
2349         }
2350 #endif
2351
2352         bool is_ground = true;
2353
2354 #if 1
2355         if(is_carved(seed, p))
2356                 is_ground = false;
2357 #endif
2358         
2359         if(depth_guess || is_ground == true)
2360         {
2361                 v2f t = base_ground_turbulence(seed, p);
2362
2363                 double surface_y_f = base_rock_level_2d(seed, v2f(p.X+t.X, p.Z+t.Y));
2364
2365 #if 0
2366                 if(depth_guess)
2367                 {
2368                         // Find highest surface near current
2369                         v3f dirs[4] = {
2370                                 v3f(1,0,0),
2371                                 v3f(-1,0,0),
2372                                 v3f(0,0,1),
2373                                 v3f(0,0,-1)
2374                         };
2375                         double s2 = surface_y_f;
2376                         for(u32 i=0; i<4; i++)
2377                         {
2378                                 v3f dir = dirs[i];
2379                                 // Get turbulence at around there
2380                                 v2f t2 = base_ground_turbulence(seed, p+dir);
2381                                 // Get ground height
2382                                 v2f l = v2f(p.X+t2.X+dir.X, p.Z+t2.Y+dir.Z);
2383                                 double s = base_rock_level_2d(seed, l);
2384                                 if(s > s2)
2385                                         s2 = s;
2386                         }
2387                         *depth_guess = s2 - p.Y;
2388                 }
2389 #endif
2390 #if 1
2391                 if(depth_guess)
2392                 {
2393                         // Check a bit lower also, take highest surface
2394                         v2f t2 = base_ground_turbulence(seed, p + v3f(0,-2,0));
2395                         double s2 = base_rock_level_2d(seed, v2f(p.X+t2.X, p.Z+t2.Y));
2396                         if(s2 > surface_y_f)
2397                                 *depth_guess = s2 - p.Y;
2398                         else
2399                                 *depth_guess = surface_y_f - p.Y;
2400                 }
2401 #endif
2402 #if 0
2403                 if(depth_guess)
2404                         *depth_guess = surface_y_f - p.Y;
2405 #endif
2406
2407                 if(p.Y > surface_y_f)
2408                         is_ground = false;
2409         }
2410         
2411         /*if(depth_guess)
2412         {
2413                 // Guess surface point
2414                 v3f p2(p.X, surface_y_f, p.Z);
2415                 v2f t2 = base_ground_turbulence
2416                 double u1 = 
2417                 double s1 = base_rock_level_2d(seed, v2f(p.X+v1,p.Z+v2));
2418         }*/
2419
2420         return is_ground;
2421 }
2422
2423 #define VMANIP_FLAG_DUNGEON VOXELFLAG_CHECKED1
2424
2425 /*
2426         This is the main map generation method
2427 */
2428
2429 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
2430                 core::map<v3s16, MapBlock*> &changed_blocks,
2431                 bool force)
2432 {
2433         DSTACK(__FUNCTION_NAME);
2434
2435         // Shall be not used now
2436         //assert(0);
2437
2438 #if 0
2439
2440         /*
2441                 Don't generate if already fully generated
2442         */
2443         if(force == false)
2444         {
2445                 MapChunk *chunk = getChunk(chunkpos);
2446                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
2447                 {
2448                         dstream<<"generateChunkRaw(): Chunk "
2449                                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2450                                         <<" already generated"<<std::endl;
2451                         return chunk;
2452                 }
2453         }
2454
2455         dstream<<"generateChunkRaw(): Generating chunk "
2456                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2457                         <<std::endl;
2458         
2459         TimeTaker timer("generateChunkRaw()");
2460         
2461         // The distance how far into the neighbors the generator is allowed to go.
2462         s16 max_spread_amount_sectors = 2;
2463         assert(max_spread_amount_sectors <= m_chunksize);
2464         s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
2465
2466         // Minimum amount of space left on sides for mud to fall in
2467         //s16 min_mud_fall_space = 2;
2468         
2469         // Maximum diameter of stone obstacles in X and Z
2470         /*s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
2471         assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);*/
2472         
2473         s16 y_blocks_min = -4;
2474         s16 y_blocks_max = 3;
2475         s16 h_blocks = y_blocks_max - y_blocks_min + 1;
2476         s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
2477         s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
2478
2479         v2s16 sectorpos_base = chunk_to_sector(chunkpos);
2480         s16 sectorpos_base_size = m_chunksize;
2481
2482         /*v2s16 sectorpos_bigbase = chunk_to_sector(chunkpos - v2s16(1,1));
2483         s16 sectorpos_bigbase_size = m_chunksize * 3;*/
2484         v2s16 sectorpos_bigbase =
2485                         sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
2486         s16 sectorpos_bigbase_size =
2487                         sectorpos_base_size + 2 * max_spread_amount_sectors;
2488
2489         v3s16 bigarea_blocks_min(
2490                 sectorpos_bigbase.X,
2491                 y_blocks_min,
2492                 sectorpos_bigbase.Y
2493         );
2494
2495         v3s16 bigarea_blocks_max(
2496                 sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
2497                 y_blocks_max,
2498                 sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
2499         );
2500         
2501         // Relative values to control amount of stuff in one chunk
2502         /*u32 relative_area = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2503                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE;*/
2504         u32 relative_volume = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2505                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE
2506                         *(u32)h_blocks*MAP_BLOCKSIZE;
2507                 
2508         /*
2509                 The limiting edges of the lighting update, inclusive.
2510         */
2511         s16 lighting_min_d = 0-max_spread_amount;
2512         s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
2513
2514         /*
2515                 Create the whole area of this and the neighboring chunks
2516         */
2517         {
2518                 TimeTaker timer("generateChunkRaw() create area");
2519                 
2520                 for(s16 x=0; x<sectorpos_bigbase_size; x++)
2521                 for(s16 z=0; z<sectorpos_bigbase_size; z++)
2522                 {
2523                         v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
2524                         ServerMapSector *sector = createSector(sectorpos);
2525                         assert(sector);
2526
2527                         for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
2528                         {
2529                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
2530                                 MapBlock *block = createBlock(blockpos);
2531
2532                                 // Lighting won't be calculated
2533                                 //block->setLightingExpired(true);
2534                                 // Lighting will be calculated
2535                                 block->setLightingExpired(false);
2536
2537                                 /*
2538                                         Block gets sunlight if this is true.
2539
2540                                         This should be set to true when the top side of a block
2541                                         is completely exposed to the sky.
2542
2543                                         Actually this doesn't matter now because the
2544                                         initial lighting is done here.
2545                                 */
2546                                 block->setIsUnderground(y != y_blocks_max);
2547                         }
2548                 }
2549         }
2550         
2551         /*
2552                 Now we have a big empty area.
2553
2554                 Make a ManualMapVoxelManipulator that contains this and the
2555                 neighboring chunks
2556         */
2557
2558         ManualMapVoxelManipulator vmanip(this);
2559         // Add the area we just generated
2560         {
2561                 TimeTaker timer("generateChunkRaw() initialEmerge");
2562                 vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2563         }
2564
2565         // Clear all flags
2566         vmanip.clearFlag(0xff);
2567
2568         TimeTaker timer_generate("generateChunkRaw() generate");
2569
2570         // Maximum height of the stone surface and obstacles.
2571         // This is used to disable dungeon generation from going too high.
2572         s16 stone_surface_max_y = 0;
2573
2574         /*
2575                 Generate general ground level to full area
2576         */
2577         
2578         {
2579         // 22ms @cs=8
2580         TimeTaker timer1("ground level");
2581         dstream<<"Generating base ground..."<<std::endl;
2582
2583         for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
2584         for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
2585         {
2586                 // Node position
2587                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2588                 
2589                 /*
2590                         Skip if already generated
2591                 */
2592                 {
2593                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2594                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
2595                                 continue;
2596                 }
2597
2598                 v2f p2df(p2d.X, p2d.Y);
2599
2600                 {
2601                         // Use fast index incrementing
2602                         v3s16 em = vmanip.m_area.getExtent();
2603                         s16 min = y_nodes_min;
2604                         s16 max = y_nodes_max;
2605                         /*s16 min = -10;
2606                         s16 max = 20;*/
2607                         //float surface_y_f = base_rock_level_2d(m_seed, p2df);
2608                         u32 i = vmanip.m_area.index(v3s16(p2d.X, min, p2d.Y));
2609                         for(s16 y=min; y<=max; y++)
2610                         {
2611 #if 1
2612                                 bool is = is_base_ground(m_seed, v3f(p2df.X,y,p2df.Y));
2613                                 if(is)
2614                                         vmanip.m_data[i].d = CONTENT_STONE;
2615                                 else
2616                                         vmanip.m_data[i].d = CONTENT_AIR;
2617 #endif
2618 #if 0
2619                                 double v = noise3d_perlin(
2620                                                 0.5+(float)p2d.X/200,
2621                                                 0.5+(float)y/200,
2622                                                 0.5+(float)p2d.Y/200,
2623                                                 m_seed+293, 6, 0.55);
2624                                 if(v > 0.0)
2625                                         vmanip.m_data[i].d = CONTENT_STONE;
2626                                 else
2627                                         vmanip.m_data[i].d = CONTENT_AIR;
2628 #endif
2629 #if 0
2630                                 /*double v1 = 5 * noise3d_perlin(
2631                                                 0.5+(float)p2df.X/200,
2632                                                 0.5+(float)y/200,
2633                                                 0.5+(float)p2df.Y/200,
2634                                                 m_seed+293, 6, 0.55);
2635
2636                                 double v2 = 5 * noise3d_perlin(
2637                                                 0.5+(float)p2df.X/200,
2638                                                 0.5+(float)y/200,
2639                                                 0.5+(float)p2df.Y/200,
2640                                                 m_seed+293, 6, 0.55);*/
2641
2642                                 double v1 = 0;
2643                                 double v2 = 0;
2644
2645                                 float surface_y_f = base_rock_level_2d(m_seed, p2df+v2f(v1,v2));
2646
2647                                 if(y <= surface_y_f)
2648                                         vmanip.m_data[i].d = CONTENT_STONE;
2649                                 else
2650                                         vmanip.m_data[i].d = CONTENT_AIR;
2651 #endif
2652
2653                                 vmanip.m_area.add_y(em, i, 1);
2654                         }
2655                 }
2656
2657 #if 0
2658                 // Node position
2659                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2660
2661                 /*
2662                         Skip if already generated
2663                 */
2664                 {
2665                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2666                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
2667                                 continue;
2668                 }
2669
2670                 // Ground height at this point
2671                 float surface_y_f = 0.0;
2672
2673                 // Use perlin noise for ground height
2674                 surface_y_f = base_rock_level_2d(m_seed, p2d);
2675                 
2676                 /*// Experimental stuff
2677                 {
2678                         float a = highlands_level_2d(m_seed, p2d);
2679                         if(a > surface_y_f)
2680                                 surface_y_f = a;
2681                 }*/
2682
2683                 // Convert to integer
2684                 s16 surface_y = (s16)surface_y_f;
2685                 
2686                 // Log it
2687                 if(surface_y > stone_surface_max_y)
2688                         stone_surface_max_y = surface_y;
2689
2690                 /*
2691                         Fill ground with stone
2692                 */
2693                 {
2694                         // Use fast index incrementing
2695                         v3s16 em = vmanip.m_area.getExtent();
2696                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
2697                         for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++)
2698                         {
2699                                 vmanip.m_data[i].d = CONTENT_STONE;
2700
2701                                 vmanip.m_area.add_y(em, i, 1);
2702                         }
2703                 }
2704 #endif
2705         }
2706         
2707         }//timer1
2708
2709         /*
2710                 Randomize some parameters
2711         */
2712         
2713         s32 stone_obstacle_count = 0;
2714         /*s32 stone_obstacle_count =
2715                         rangelim((1.0+noise2d(m_seed+897,
2716                         sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2717         
2718         s16 stone_obstacle_max_height = 0;
2719         /*s16 stone_obstacle_max_height =
2720                         rangelim((1.0+noise2d(m_seed+5902,
2721                         sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2722
2723         /*
2724                 Loop this part, it will make stuff look older and newer nicely
2725         */
2726         u32 age_count = 2;
2727         for(u32 i_age=0; i_age<age_count; i_age++)
2728         { // Aging loop
2729
2730         {
2731         // 8ms @cs=8
2732         //TimeTaker timer1("stone obstacles");
2733
2734         /*
2735                 Add some random stone obstacles
2736         */
2737         
2738         for(s32 ri=0; ri<stone_obstacle_count; ri++)
2739         {
2740                 // Randomize max height so usually stuff will be quite low
2741                 s16 maxheight_randomized = myrand_range(0, stone_obstacle_max_height);
2742
2743                 //s16 stone_obstacle_max_size = sectorpos_base_size * MAP_BLOCKSIZE - 10;
2744                 s16 stone_obstacle_max_size = MAP_BLOCKSIZE*4-4;
2745
2746                 v3s16 ob_size(
2747                         myrand_range(5, stone_obstacle_max_size),
2748                         myrand_range(0, maxheight_randomized),
2749                         myrand_range(5, stone_obstacle_max_size)
2750                 );
2751                 
2752                 // Don't make stupid small rectangle bumps
2753                 if(ob_size.Y < 5)
2754                         continue;
2755                 
2756                 v2s16 ob_place(
2757                         myrand_range(1+ob_size.X/2+2,
2758                                         sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.X/2-2),
2759                         myrand_range(1+ob_size.Z/2+2,
2760                                         sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.Z/2-2)
2761                 );
2762                 
2763                 // Minimum space left on top of the obstacle
2764                 s16 min_head_space = 12;
2765                 
2766                 for(s16 x=-ob_size.X/2; x<ob_size.X/2; x++)
2767                 for(s16 z=-ob_size.Z/2; z<ob_size.Z/2; z++)
2768                 {
2769                         // Node position in 2d
2770                         v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + ob_place + v2s16(x,z);
2771                         
2772                         // Find stone ground level
2773                         // (ignore everything else than mud in already generated chunks)
2774                         // and mud amount over the stone level
2775                         s16 surface_y = 0;
2776                         s16 mud_amount = 0;
2777                         {
2778                                 v3s16 em = vmanip.m_area.getExtent();
2779                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2780                                 s16 y;
2781                                 // Go to ground level
2782                                 for(y=y_nodes_max; y>=y_nodes_min; y--)
2783                                 {
2784                                         MapNode *n = &vmanip.m_data[i];
2785                                         /*if(content_walkable(n.d)
2786                                                         && n.d != CONTENT_MUD
2787                                                         && n.d != CONTENT_GRASS)
2788                                                 break;*/
2789                                         if(n->d == CONTENT_STONE)
2790                                                 break;
2791                                         
2792                                         if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
2793                                         {
2794                                                 mud_amount++;
2795                                                 /*
2796                                                         Change to mud because otherwise we might
2797                                                         be throwing mud on grass at the next
2798                                                         step
2799                                                 */
2800                                                 n->d = CONTENT_MUD;
2801                                         }
2802                                                 
2803                                         vmanip.m_area.add_y(em, i, -1);
2804                                 }
2805                                 if(y >= y_nodes_min)
2806                                         surface_y = y;
2807                                 else
2808                                         surface_y = y_nodes_min;
2809                         }
2810
2811
2812                         /*
2813                                 Add stone on ground
2814                         */
2815                         {
2816                                 v3s16 em = vmanip.m_area.getExtent();
2817                                 s16 y_start = surface_y+1;
2818                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2819                                 s16 y;
2820                                 // Add stone
2821                                 s16 count = 0;
2822                                 for(y=y_start; y<=y_nodes_max - min_head_space; y++)
2823                                 {
2824                                         MapNode &n = vmanip.m_data[i];
2825                                         n.d = CONTENT_STONE;
2826
2827                                         if(y > stone_surface_max_y)
2828                                                 stone_surface_max_y = y;
2829
2830                                         count++;
2831                                         if(count >= ob_size.Y)
2832                                                 break;
2833                                                 
2834                                         vmanip.m_area.add_y(em, i, 1);
2835                                 }
2836                                 // Add mud
2837                                 count = 0;
2838                                 for(; y<=y_nodes_max - min_head_space; y++)
2839                                 {
2840                                         MapNode &n = vmanip.m_data[i];
2841                                         n.d = CONTENT_MUD;
2842                                         count++;
2843                                         if(count >= mud_amount)
2844                                                 break;
2845                                                 
2846                                         vmanip.m_area.add_y(em, i, 1);
2847                                 }
2848                         }
2849
2850                 }
2851         }
2852
2853         }//timer1
2854         {
2855         // 24ms @cs=8
2856         //TimeTaker timer1("dungeons");
2857
2858         /*
2859                 Make dungeons
2860         */
2861         u32 dungeons_count = relative_volume / 600000;
2862         u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
2863         if(stone_surface_max_y < WATER_LEVEL)
2864                 bruises_count = 0;
2865         /*u32 dungeons_count = 0;
2866         u32 bruises_count = 0;*/
2867         for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
2868         {
2869                 s16 min_tunnel_diameter = 2;
2870                 s16 max_tunnel_diameter = 6;
2871                 u16 tunnel_routepoints = 25;
2872                 
2873                 bool bruise_surface = (jj < bruises_count);
2874
2875                 if(bruise_surface)
2876                 {
2877                         min_tunnel_diameter = 5;
2878                         max_tunnel_diameter = myrand_range(10, 20);
2879                         /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
2880                         max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
2881                         
2882                         /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(m_seed+42,
2883                                         sectorpos_base.X, sectorpos_base.Y)), 0, 15);*/
2884
2885                         tunnel_routepoints = 5;
2886                 }
2887
2888                 // Allowed route area size in nodes
2889                 v3s16 ar(
2890                         sectorpos_base_size*MAP_BLOCKSIZE,
2891                         h_blocks*MAP_BLOCKSIZE,
2892                         sectorpos_base_size*MAP_BLOCKSIZE
2893                 );
2894
2895                 // Area starting point in nodes
2896                 v3s16 of(
2897                         sectorpos_base.X*MAP_BLOCKSIZE,
2898                         y_blocks_min*MAP_BLOCKSIZE,
2899                         sectorpos_base.Y*MAP_BLOCKSIZE
2900                 );
2901
2902                 // Allow a bit more
2903                 //(this should be more than the maximum radius of the tunnel)
2904                 //s16 insure = 5; // Didn't work with max_d = 20
2905                 s16 insure = 10;
2906                 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
2907                 ar += v3s16(1,0,1) * more * 2;
2908                 of -= v3s16(1,0,1) * more;
2909                 
2910                 s16 route_y_min = 0;
2911                 // Allow half a diameter + 7 over stone surface
2912                 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
2913
2914                 /*// If dungeons, don't go through surface too often
2915                 if(bruise_surface == false)
2916                         route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
2917
2918                 // Limit maximum to area
2919                 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
2920
2921                 if(bruise_surface)
2922                 {
2923                         /*// Minimum is at y=0
2924                         route_y_min = -of.Y - 0;*/
2925                         // Minimum is at y=max_tunnel_diameter/4
2926                         //route_y_min = -of.Y + max_tunnel_diameter/4;
2927                         //s16 min = -of.Y + max_tunnel_diameter/4;
2928                         s16 min = -of.Y + 0;
2929                         route_y_min = myrand_range(min, min + max_tunnel_diameter);
2930                         route_y_min = rangelim(route_y_min, 0, route_y_max);
2931                 }
2932
2933                 /*dstream<<"route_y_min = "<<route_y_min
2934                                 <<", route_y_max = "<<route_y_max<<std::endl;*/
2935
2936                 s16 route_start_y_min = route_y_min;
2937                 s16 route_start_y_max = route_y_max;
2938
2939                 // Start every 2nd dungeon from surface
2940                 bool coming_from_surface = (jj % 2 == 0 && bruise_surface == false);
2941
2942                 if(coming_from_surface)
2943                 {
2944                         route_start_y_min = -of.Y + stone_surface_max_y + 5;
2945                 }
2946                 
2947                 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
2948                 route_start_y_max = rangelim(route_start_y_max, 0, ar.Y-1);
2949
2950                 // Randomize starting position
2951                 v3f orp(
2952                         (float)(myrand()%ar.X)+0.5,
2953                         (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
2954                         (float)(myrand()%ar.Z)+0.5
2955                 );
2956
2957                 MapNode airnode(CONTENT_AIR);
2958                 
2959                 /*
2960                         Generate some tunnel starting from orp
2961                 */
2962                 
2963                 for(u16 j=0; j<tunnel_routepoints; j++)
2964                 {
2965                         // Randomize size
2966                         s16 min_d = min_tunnel_diameter;
2967                         s16 max_d = max_tunnel_diameter;
2968                         s16 rs = myrand_range(min_d, max_d);
2969                         
2970                         v3s16 maxlen;
2971                         if(bruise_surface)
2972                         {
2973                                 maxlen = v3s16(rs*7,rs*7,rs*7);
2974                         }
2975                         else
2976                         {
2977                                 maxlen = v3s16(15, myrand_range(1, 20), 15);
2978                         }
2979
2980                         v3f vec;
2981                         
2982                         if(coming_from_surface && j < 3)
2983                         {
2984                                 vec = v3f(
2985                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2986                                         (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
2987                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2988                                 );
2989                         }
2990                         else
2991                         {
2992                                 vec = v3f(
2993                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2994                                         (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
2995                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2996                                 );
2997                         }
2998
2999                         v3f rp = orp + vec;
3000                         if(rp.X < 0)
3001                                 rp.X = 0;
3002                         else if(rp.X >= ar.X)
3003                                 rp.X = ar.X-1;
3004                         if(rp.Y < route_y_min)
3005                                 rp.Y = route_y_min;
3006                         else if(rp.Y >= route_y_max)
3007                                 rp.Y = route_y_max-1;
3008                         if(rp.Z < 0)
3009                                 rp.Z = 0;
3010                         else if(rp.Z >= ar.Z)
3011                                 rp.Z = ar.Z-1;
3012                         vec = rp - orp;
3013
3014                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
3015                         {
3016                                 v3f fp = orp + vec * f;
3017                                 v3s16 cp(fp.X, fp.Y, fp.Z);
3018
3019                                 s16 d0 = -rs/2;
3020                                 s16 d1 = d0 + rs - 1;
3021                                 for(s16 z0=d0; z0<=d1; z0++)
3022                                 {
3023                                         //s16 si = rs - MYMAX(0, abs(z0)-rs/4);
3024                                         s16 si = rs - MYMAX(0, abs(z0)-rs/7);
3025                                         for(s16 x0=-si; x0<=si-1; x0++)
3026                                         {
3027                                                 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
3028                                                 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
3029                                                 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
3030                                                 //s16 si2 = rs - abs(x0);
3031                                                 for(s16 y0=-si2+1+2; y0<=si2-1; y0++)
3032                                                 {
3033                                                         s16 z = cp.Z + z0;
3034                                                         s16 y = cp.Y + y0;
3035                                                         s16 x = cp.X + x0;
3036                                                         v3s16 p(x,y,z);
3037                                                         /*if(isInArea(p, ar) == false)
3038                                                                 continue;*/
3039                                                         // Check only height
3040                                                         if(y < 0 || y >= ar.Y)
3041                                                                 continue;
3042                                                         p += of;
3043                                                         
3044                                                         //assert(vmanip.m_area.contains(p));
3045                                                         if(vmanip.m_area.contains(p) == false)
3046                                                         {
3047                                                                 dstream<<"WARNING: "<<__FUNCTION_NAME
3048                                                                                 <<":"<<__LINE__<<": "
3049                                                                                 <<"point not in area"
3050                                                                                 <<std::endl;
3051                                                                 continue;
3052                                                         }
3053                                                         
3054                                                         // Just set it to air, it will be changed to
3055                                                         // water afterwards
3056                                                         u32 i = vmanip.m_area.index(p);
3057                                                         vmanip.m_data[i] = airnode;
3058
3059                                                         if(bruise_surface == false)
3060                                                         {
3061                                                                 // Set tunnel flag
3062                                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON;
3063                                                         }
3064                                                 }
3065                                         }
3066                                 }
3067                         }
3068
3069                         orp = rp;
3070                 }
3071         
3072         }
3073
3074         }//timer1
3075         {
3076         // 46ms @cs=8
3077         //TimeTaker timer1("ore veins");
3078
3079         /*
3080                 Make ore veins
3081         */
3082         for(u32 jj=0; jj<relative_volume/1000; jj++)
3083         {
3084                 s16 max_vein_diameter = 3;
3085
3086                 // Allowed route area size in nodes
3087                 v3s16 ar(
3088                         sectorpos_base_size*MAP_BLOCKSIZE,
3089                         h_blocks*MAP_BLOCKSIZE,
3090                         sectorpos_base_size*MAP_BLOCKSIZE
3091                 );
3092
3093                 // Area starting point in nodes
3094                 v3s16 of(
3095                         sectorpos_base.X*MAP_BLOCKSIZE,
3096                         y_blocks_min*MAP_BLOCKSIZE,
3097                         sectorpos_base.Y*MAP_BLOCKSIZE
3098                 );
3099
3100                 // Allow a bit more
3101                 //(this should be more than the maximum radius of the tunnel)
3102                 s16 insure = 3;
3103                 s16 more = max_spread_amount - max_vein_diameter/2 - insure;
3104                 ar += v3s16(1,0,1) * more * 2;
3105                 of -= v3s16(1,0,1) * more;
3106                 
3107                 // Randomize starting position
3108                 v3f orp(
3109                         (float)(myrand()%ar.X)+0.5,
3110                         (float)(myrand()%ar.Y)+0.5,
3111                         (float)(myrand()%ar.Z)+0.5
3112                 );
3113
3114                 // Randomize mineral
3115                 u8 mineral;
3116                 if(myrand()%3 != 0)
3117                         mineral = MINERAL_COAL;
3118                 else
3119                         mineral = MINERAL_IRON;
3120
3121                 /*
3122                         Generate some vein starting from orp
3123                 */
3124
3125                 for(u16 j=0; j<2; j++)
3126                 {
3127                         /*v3f rp(
3128                                 (float)(myrand()%ar.X)+0.5,
3129                                 (float)(myrand()%ar.Y)+0.5,
3130                                 (float)(myrand()%ar.Z)+0.5
3131                         );
3132                         v3f vec = rp - orp;*/
3133                         
3134                         v3s16 maxlen(5, 5, 5);
3135                         v3f vec(
3136                                 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
3137                                 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
3138                                 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
3139                         );
3140                         v3f rp = orp + vec;
3141                         if(rp.X < 0)
3142                                 rp.X = 0;
3143                         else if(rp.X >= ar.X)
3144                                 rp.X = ar.X;
3145                         if(rp.Y < 0)
3146                                 rp.Y = 0;
3147                         else if(rp.Y >= ar.Y)
3148                                 rp.Y = ar.Y;
3149                         if(rp.Z < 0)
3150                                 rp.Z = 0;
3151                         else if(rp.Z >= ar.Z)
3152                                 rp.Z = ar.Z;
3153                         vec = rp - orp;
3154
3155                         // Randomize size
3156                         s16 min_d = 0;
3157                         s16 max_d = max_vein_diameter;
3158                         s16 rs = myrand_range(min_d, max_d);
3159                         
3160                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
3161                         {
3162                                 v3f fp = orp + vec * f;
3163                                 v3s16 cp(fp.X, fp.Y, fp.Z);
3164                                 s16 d0 = -rs/2;
3165                                 s16 d1 = d0 + rs - 1;
3166                                 for(s16 z0=d0; z0<=d1; z0++)
3167                                 {
3168                                         s16 si = rs - abs(z0);
3169                                         for(s16 x0=-si; x0<=si-1; x0++)
3170                                         {
3171                                                 s16 si2 = rs - abs(x0);
3172                                                 for(s16 y0=-si2+1; y0<=si2-1; y0++)
3173                                                 {
3174                                                         // Don't put mineral to every place
3175                                                         if(myrand()%5 != 0)
3176                                                                 continue;
3177
3178                                                         s16 z = cp.Z + z0;
3179                                                         s16 y = cp.Y + y0;
3180                                                         s16 x = cp.X + x0;
3181                                                         v3s16 p(x,y,z);
3182                                                         /*if(isInArea(p, ar) == false)
3183                                                                 continue;*/
3184                                                         // Check only height
3185                                                         if(y < 0 || y >= ar.Y)
3186                                                                 continue;
3187                                                         p += of;
3188                                                         
3189                                                         assert(vmanip.m_area.contains(p));
3190                                                         
3191                                                         // Just set it to air, it will be changed to
3192                                                         // water afterwards
3193                                                         u32 i = vmanip.m_area.index(p);
3194                                                         MapNode *n = &vmanip.m_data[i];
3195                                                         if(n->d == CONTENT_STONE)
3196                                                                 n->param = mineral;
3197                                                 }
3198                                         }
3199                                 }
3200                         }
3201
3202                         orp = rp;
3203                 }
3204         
3205         }
3206
3207         }//timer1
3208         {
3209         // 15ms @cs=8
3210         //TimeTaker timer1("add mud");
3211
3212         /*
3213                 Add mud to the central chunk
3214         */
3215         
3216         for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3217         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)
3218         {
3219                 // Node position in 2d
3220                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3221                 
3222                 // Randomize mud amount
3223                 s16 mud_add_amount = get_mud_amount(m_seed, v2f(p2d.X,p2d.Y))/age_count;
3224
3225                 // Find ground level
3226                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
3227
3228                 /*
3229                         If topmost node is grass, change it to mud.
3230                         It might be if it was flown to there from a neighboring
3231                         chunk and then converted.
3232                 */
3233                 {
3234                         u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
3235                         MapNode *n = &vmanip.m_data[i];
3236                         if(n->d == CONTENT_GRASS)
3237                                 n->d = CONTENT_MUD;
3238                 }
3239
3240                 /*
3241                         Add mud on ground
3242                 */
3243                 {
3244                         s16 mudcount = 0;
3245                         v3s16 em = vmanip.m_area.getExtent();
3246                         s16 y_start = surface_y+1;
3247                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3248                         for(s16 y=y_start; y<=y_nodes_max; y++)
3249                         {
3250                                 if(mudcount >= mud_add_amount)
3251                                         break;
3252                                         
3253                                 MapNode &n = vmanip.m_data[i];
3254                                 n.d = CONTENT_MUD;
3255                                 mudcount++;
3256
3257                                 vmanip.m_area.add_y(em, i, 1);
3258                         }
3259                 }
3260
3261         }
3262
3263         }//timer1
3264         {
3265         // 340ms @cs=8
3266         //TimeTaker timer1("flow mud");
3267
3268         /*
3269                 Flow mud away from steep edges
3270         */
3271
3272         // Limit area by 1 because mud is flown into neighbors.
3273         s16 mudflow_minpos = 0-max_spread_amount+1;
3274         s16 mudflow_maxpos = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
3275
3276         // Iterate a few times
3277         for(s16 k=0; k<3; k++)
3278         {
3279
3280         for(s16 x=mudflow_minpos;
3281                         x<=mudflow_maxpos;
3282                         x++)
3283         for(s16 z=mudflow_minpos;
3284                         z<=mudflow_maxpos;
3285                         z++)
3286         {
3287                 // Invert coordinates every 2nd iteration
3288                 if(k%2 == 0)
3289                 {
3290                         x = mudflow_maxpos - (x-mudflow_minpos);
3291                         z = mudflow_maxpos - (z-mudflow_minpos);
3292                 }
3293
3294                 // Node position in 2d
3295                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3296                 
3297                 v3s16 em = vmanip.m_area.getExtent();
3298                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3299                 s16 y=y_nodes_max;
3300
3301                 for(;; y--)
3302                 {
3303                         MapNode *n = NULL;
3304                         // Find mud
3305                         for(; y>=y_nodes_min; y--)
3306                         {
3307                                 n = &vmanip.m_data[i];
3308                                 //if(content_walkable(n->d))
3309                                 //      break;
3310                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
3311                                         break;
3312                                         
3313                                 vmanip.m_area.add_y(em, i, -1);
3314                         }
3315
3316                         // Stop if out of area
3317                         //if(vmanip.m_area.contains(i) == false)
3318                         if(y < y_nodes_min)
3319                                 break;
3320
3321                         /*// If not mud, do nothing to it
3322                         MapNode *n = &vmanip.m_data[i];
3323                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3324                                 continue;*/
3325
3326                         /*
3327                                 Don't flow it if the stuff under it is not mud
3328                         */
3329                         {
3330                                 u32 i2 = i;
3331                                 vmanip.m_area.add_y(em, i2, -1);
3332                                 // Cancel if out of area
3333                                 if(vmanip.m_area.contains(i2) == false)
3334                                         continue;
3335                                 MapNode *n2 = &vmanip.m_data[i2];
3336                                 if(n2->d != CONTENT_MUD && n2->d != CONTENT_GRASS)
3337                                         continue;
3338                         }
3339
3340                         // Make it exactly mud
3341                         n->d = CONTENT_MUD;
3342                         
3343                         /*s16 recurse_count = 0;
3344         mudflow_recurse:*/
3345
3346                         v3s16 dirs4[4] = {
3347                                 v3s16(0,0,1), // back
3348                                 v3s16(1,0,0), // right
3349                                 v3s16(0,0,-1), // front
3350                                 v3s16(-1,0,0), // left
3351                         };
3352
3353                         // Theck that upper is air or doesn't exist.
3354                         // Cancel dropping if upper keeps it in place
3355                         u32 i3 = i;
3356                         vmanip.m_area.add_y(em, i3, 1);
3357                         if(vmanip.m_area.contains(i3) == true
3358                                         && content_walkable(vmanip.m_data[i3].d) == true)
3359                         {
3360                                 continue;
3361                         }
3362
3363                         // Drop mud on side
3364                         
3365                         for(u32 di=0; di<4; di++)
3366                         {
3367                                 v3s16 dirp = dirs4[di];
3368                                 u32 i2 = i;
3369                                 // Move to side
3370                                 vmanip.m_area.add_p(em, i2, dirp);
3371                                 // Fail if out of area
3372                                 if(vmanip.m_area.contains(i2) == false)
3373                                         continue;
3374                                 // Check that side is air
3375                                 MapNode *n2 = &vmanip.m_data[i2];
3376                                 if(content_walkable(n2->d))
3377                                         continue;
3378                                 // Check that under side is air
3379                                 vmanip.m_area.add_y(em, i2, -1);
3380                                 if(vmanip.m_area.contains(i2) == false)
3381                                         continue;
3382                                 n2 = &vmanip.m_data[i2];
3383                                 if(content_walkable(n2->d))
3384                                         continue;
3385                                 /*// Check that under that is air (need a drop of 2)
3386                                 vmanip.m_area.add_y(em, i2, -1);
3387                                 if(vmanip.m_area.contains(i2) == false)
3388                                         continue;
3389                                 n2 = &vmanip.m_data[i2];
3390                                 if(content_walkable(n2->d))
3391                                         continue;*/
3392                                 // Loop further down until not air
3393                                 do{
3394                                         vmanip.m_area.add_y(em, i2, -1);
3395                                         // Fail if out of area
3396                                         if(vmanip.m_area.contains(i2) == false)
3397                                                 continue;
3398                                         n2 = &vmanip.m_data[i2];
3399                                 }while(content_walkable(n2->d) == false);
3400                                 // Loop one up so that we're in air
3401                                 vmanip.m_area.add_y(em, i2, 1);
3402                                 n2 = &vmanip.m_data[i2];
3403
3404                                 // Move mud to new place
3405                                 *n2 = *n;
3406                                 // Set old place to be air
3407                                 *n = MapNode(CONTENT_AIR);
3408
3409                                 // Done
3410                                 break;
3411                         }
3412                 }
3413         }
3414         
3415         }
3416
3417         }//timer1
3418         {
3419         // 50ms @cs=8
3420         //TimeTaker timer1("add water");
3421
3422         /*
3423                 Add water to the central chunk (and a bit more)
3424         */
3425         
3426         for(s16 x=0-max_spread_amount;
3427                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3428                         x++)
3429         for(s16 z=0-max_spread_amount;
3430                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3431                         z++)
3432         {
3433                 // Node position in 2d
3434                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3435                 
3436                 // Find ground level
3437                 //s16 surface_y = find_ground_level(vmanip, p2d);
3438
3439                 /*
3440                         If ground level is over water level, skip.
3441                         NOTE: This leaves caves near water without water,
3442                         which looks especially crappy when the nearby water
3443                         won't start flowing either for some reason
3444                 */
3445                 /*if(surface_y > WATER_LEVEL)
3446                         continue;*/
3447
3448                 /*
3449                         Add water on ground
3450                 */
3451                 {
3452                         v3s16 em = vmanip.m_area.getExtent();
3453                         u8 light = LIGHT_MAX;
3454                         // Start at global water surface level
3455                         s16 y_start = WATER_LEVEL;
3456                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3457                         MapNode *n = &vmanip.m_data[i];
3458
3459                         /*// Add first one to transforming liquid queue, if water
3460                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
3461                         {
3462                                 v3s16 p = v3s16(p2d.X, y_start, p2d.Y);
3463                                 m_transforming_liquid.push_back(p);
3464                         }*/
3465
3466                         for(s16 y=y_start; y>=y_nodes_min; y--)
3467                         {
3468                                 n = &vmanip.m_data[i];
3469                                 
3470                                 // Stop when there is no water and no air
3471                                 if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
3472                                                 && n->d != CONTENT_WATER)
3473                                 {
3474                                         /*// Add bottom one to transforming liquid queue
3475                                         vmanip.m_area.add_y(em, i, 1);
3476                                         n = &vmanip.m_data[i];
3477                                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
3478                                         {
3479                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
3480                                                 m_transforming_liquid.push_back(p);
3481                                         }*/
3482
3483                                         break;
3484                                 }
3485                                 
3486                                 // Make water only not in dungeons
3487                                 if(!(vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
3488                                 {
3489                                         n->d = CONTENT_WATERSOURCE;
3490                                         //n->setLight(LIGHTBANK_DAY, light);
3491
3492                                         // Add to transforming liquid queue (in case it'd
3493                                         // start flowing)
3494                                         v3s16 p = v3s16(p2d.X, y, p2d.Y);
3495                                         m_transforming_liquid.push_back(p);
3496                                 }
3497                                 
3498                                 // Next one
3499                                 vmanip.m_area.add_y(em, i, -1);
3500                                 if(light > 0)
3501                                         light--;
3502                         }
3503                 }
3504
3505         }
3506
3507         }//timer1
3508         
3509         } // Aging loop
3510
3511         {
3512         //TimeTaker timer1("convert mud to sand");
3513
3514         /*
3515                 Convert mud to sand
3516         */
3517         
3518         //s16 mud_add_amount = myrand_range(2, 4);
3519         //s16 mud_add_amount = 0;
3520         
3521         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3522         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3523         for(s16 x=0-max_spread_amount+1;
3524                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3525                         x++)
3526         for(s16 z=0-max_spread_amount+1;
3527                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3528                         z++)
3529         {
3530                 // Node position in 2d
3531                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3532                 
3533                 // Determine whether to have sand here
3534                 bool have_sand = get_have_sand(p2d);
3535
3536                 if(have_sand == false)
3537                         continue;
3538
3539                 // Find ground level
3540                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
3541                 
3542                 if(surface_y > WATER_LEVEL + 2)
3543                         continue;
3544
3545                 {
3546                         v3s16 em = vmanip.m_area.getExtent();
3547                         s16 y_start = surface_y;
3548                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3549                         u32 not_sand_counter = 0;
3550                         for(s16 y=y_start; y>=y_nodes_min; y--)
3551                         {
3552                                 MapNode *n = &vmanip.m_data[i];
3553                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
3554                                 {
3555                                         n->d = CONTENT_SAND;
3556                                 }
3557                                 else
3558                                 {
3559                                         not_sand_counter++;
3560                                         if(not_sand_counter > 3)
3561                                                 break;
3562                                 }
3563
3564                                 vmanip.m_area.add_y(em, i, -1);
3565                         }
3566                 }
3567
3568         }
3569
3570         }//timer1
3571         {
3572         // 1ms @cs=8
3573         //TimeTaker timer1("generate trees");
3574
3575         /*
3576                 Generate some trees
3577         */
3578         {
3579                 // Divide area into parts
3580                 s16 div = 8;
3581                 s16 sidelen = sectorpos_base_size*MAP_BLOCKSIZE / div;
3582                 double area = sidelen * sidelen;
3583                 for(s16 x0=0; x0<div; x0++)
3584                 for(s16 z0=0; z0<div; z0++)
3585                 {
3586                         // Center position of part of division
3587                         v2s16 p2d_center(
3588                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
3589                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
3590                         );
3591                         // Minimum edge of part of division
3592                         v2s16 p2d_min(
3593                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
3594                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
3595                         );
3596                         // Maximum edge of part of division
3597                         v2s16 p2d_max(
3598                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
3599                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
3600                         );
3601                         // Amount of trees
3602                         u32 tree_count = area * tree_amount_2d(m_seed, p2d_center);
3603                         // Put trees in random places on part of division
3604                         for(u32 i=0; i<tree_count; i++)
3605                         {
3606                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
3607                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
3608                                 s16 y = find_ground_level(vmanip, v2s16(x,z));
3609                                 // Don't make a tree under water level
3610                                 if(y < WATER_LEVEL)
3611                                         continue;
3612                                 v3s16 p(x,y,z);
3613                                 /*
3614                                         Trees grow only on mud and grass
3615                                 */
3616                                 {
3617                                         u32 i = vmanip.m_area.index(v3s16(p));
3618                                         MapNode *n = &vmanip.m_data[i];
3619                                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3620                                                 continue;
3621                                 }
3622                                 p.Y++;
3623                                 // Make a tree
3624                                 make_tree(vmanip, p);
3625                         }
3626                 }
3627                 /*u32 tree_max = relative_area / 60;
3628                 //u32 count = myrand_range(0, tree_max);
3629                 for(u32 i=0; i<count; i++)
3630                 {
3631                         s16 x = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
3632                         s16 z = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
3633                         x += sectorpos_base.X*MAP_BLOCKSIZE;
3634                         z += sectorpos_base.Y*MAP_BLOCKSIZE;
3635                         s16 y = find_ground_level(vmanip, v2s16(x,z));
3636                         // Don't make a tree under water level
3637                         if(y < WATER_LEVEL)
3638                                 continue;
3639                         v3s16 p(x,y+1,z);
3640                         // Make a tree
3641                         make_tree(vmanip, p);
3642                 }*/
3643         }
3644
3645         }//timer1
3646
3647         {
3648         // 19ms @cs=8
3649         //TimeTaker timer1("grow grass");
3650
3651         /*
3652                 Grow grass
3653         */
3654
3655         /*for(s16 x=0-4; x<sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
3656         for(s16 z=0-4; z<sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
3657         for(s16 x=0-max_spread_amount;
3658                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3659                         x++)
3660         for(s16 z=0-max_spread_amount;
3661                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3662                         z++)
3663         {
3664                 // Node position in 2d
3665                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3666                 
3667                 /*
3668                         Find the lowest surface to which enough light ends up
3669                         to make grass grow.
3670
3671                         Basically just wait until not air and not leaves.
3672                 */
3673                 s16 surface_y = 0;
3674                 {
3675                         v3s16 em = vmanip.m_area.getExtent();
3676                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3677                         s16 y;
3678                         // Go to ground level
3679                         for(y=y_nodes_max; y>=y_nodes_min; y--)
3680                         {
3681                                 MapNode &n = vmanip.m_data[i];
3682                                 if(n.d != CONTENT_AIR
3683                                                 && n.d != CONTENT_LEAVES)
3684                                         break;
3685                                 vmanip.m_area.add_y(em, i, -1);
3686                         }
3687                         if(y >= y_nodes_min)
3688                                 surface_y = y;
3689                         else
3690                                 surface_y = y_nodes_min;
3691                 }
3692                 
3693                 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
3694                 MapNode *n = &vmanip.m_data[i];
3695                 if(n->d == CONTENT_MUD)
3696                         n->d = CONTENT_GRASS;
3697         }
3698
3699         }//timer1
3700
3701         /*
3702                 Initial lighting (sunlight)
3703         */
3704
3705         core::map<v3s16, bool> light_sources;
3706
3707         {
3708         // 750ms @cs=8, can't optimize more
3709         TimeTaker timer1("initial lighting");
3710
3711 #if 0
3712         /*
3713                 Go through the edges and add all nodes that have light to light_sources
3714         */
3715         
3716         // Four edges
3717         for(s16 i=0; i<4; i++)
3718         // Edge length
3719         for(s16 j=lighting_min_d;
3720                         j<=lighting_max_d;
3721                         j++)
3722         {
3723                 s16 x;
3724                 s16 z;
3725                 // +-X
3726                 if(i == 0 || i == 1)
3727                 {
3728                         x = (i==0) ? lighting_min_d : lighting_max_d;
3729                         if(i == 0)
3730                                 z = lighting_min_d;
3731                         else
3732                                 z = lighting_max_d;
3733                 }
3734                 // +-Z
3735                 else
3736                 {
3737                         z = (i==0) ? lighting_min_d : lighting_max_d;
3738                         if(i == 0)
3739                                 x = lighting_min_d;
3740                         else
3741                                 x = lighting_max_d;
3742                 }
3743                 
3744                 // Node position in 2d
3745                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3746
3747                 {
3748                         v3s16 em = vmanip.m_area.getExtent();
3749                         s16 y_start = y_nodes_max;
3750                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3751                         for(s16 y=y_start; y>=y_nodes_min; y--)
3752                         {
3753                                 MapNode *n = &vmanip.m_data[i];
3754                                 if(n->getLight(LIGHTBANK_DAY) != 0)
3755                                 {
3756                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3757                                 }
3758                                 //NOTE: This is broken, at least the index has to
3759                                 // be incremented
3760                         }
3761                 }
3762         }
3763 #endif
3764
3765 #if 1
3766         /*
3767                 Go through the edges and apply sunlight to them, not caring
3768                 about neighbors
3769         */
3770         
3771         // Four edges
3772         for(s16 i=0; i<4; i++)
3773         // Edge length
3774         for(s16 j=lighting_min_d;
3775                         j<=lighting_max_d;
3776                         j++)
3777         {
3778                 s16 x;
3779                 s16 z;
3780                 // +-X
3781                 if(i == 0 || i == 1)
3782                 {
3783                         x = (i==0) ? lighting_min_d : lighting_max_d;
3784                         if(i == 0)
3785                                 z = lighting_min_d;
3786                         else
3787                                 z = lighting_max_d;
3788                 }
3789                 // +-Z
3790                 else
3791                 {
3792                         z = (i==0) ? lighting_min_d : lighting_max_d;
3793                         if(i == 0)
3794                                 x = lighting_min_d;
3795                         else
3796                                 x = lighting_max_d;
3797                 }
3798                 
3799                 // Node position in 2d
3800                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3801                 
3802                 // Loop from top to down
3803                 {
3804                         u8 light = LIGHT_SUN;
3805                         v3s16 em = vmanip.m_area.getExtent();
3806                         s16 y_start = y_nodes_max;
3807                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3808                         for(s16 y=y_start; y>=y_nodes_min; y--)
3809                         {
3810                                 MapNode *n = &vmanip.m_data[i];
3811                                 if(light_propagates_content(n->d) == false)
3812                                 {
3813                                         light = 0;
3814                                 }
3815                                 else if(light != LIGHT_SUN
3816                                         || sunlight_propagates_content(n->d) == false)
3817                                 {
3818                                         if(light > 0)
3819                                                 light--;
3820                                 }
3821                                 
3822                                 n->setLight(LIGHTBANK_DAY, light);
3823                                 n->setLight(LIGHTBANK_NIGHT, 0);
3824                                 
3825                                 if(light != 0)
3826                                 {
3827                                         // Insert light source
3828                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3829                                 }
3830                                 
3831                                 // Increment index by y
3832                                 vmanip.m_area.add_y(em, i, -1);
3833                         }
3834                 }
3835         }
3836 #endif
3837
3838         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3839         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3840         /*for(s16 x=0-max_spread_amount+1;
3841                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3842                         x++)
3843         for(s16 z=0-max_spread_amount+1;
3844                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3845                         z++)*/
3846 #if 1
3847         /*
3848                 This has to be 1 smaller than the actual area, because
3849                 neighboring nodes are checked.
3850         */
3851         for(s16 x=lighting_min_d+1;
3852                         x<=lighting_max_d-1;
3853                         x++)
3854         for(s16 z=lighting_min_d+1;
3855                         z<=lighting_max_d-1;
3856                         z++)
3857         {
3858                 // Node position in 2d
3859                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3860                 
3861                 /*
3862                         Apply initial sunlight
3863                 */
3864                 {
3865                         u8 light = LIGHT_SUN;
3866                         bool add_to_sources = false;
3867                         v3s16 em = vmanip.m_area.getExtent();
3868                         s16 y_start = y_nodes_max;
3869                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3870                         for(s16 y=y_start; y>=y_nodes_min; y--)
3871                         {
3872                                 MapNode *n = &vmanip.m_data[i];
3873
3874                                 if(light_propagates_content(n->d) == false)
3875                                 {
3876                                         light = 0;
3877                                 }
3878                                 else if(light != LIGHT_SUN
3879                                         || sunlight_propagates_content(n->d) == false)
3880                                 {
3881                                         if(light > 0)
3882                                                 light--;
3883                                 }
3884                                 
3885                                 // This doesn't take much time
3886                                 if(add_to_sources == false)
3887                                 {
3888                                         /*
3889                                                 Check sides. If side is not air or water, start
3890                                                 adding to light_sources.
3891                                         */
3892                                         v3s16 dirs4[4] = {
3893                                                 v3s16(0,0,1), // back
3894                                                 v3s16(1,0,0), // right
3895                                                 v3s16(0,0,-1), // front
3896                                                 v3s16(-1,0,0), // left
3897                                         };
3898                                         for(u32 di=0; di<4; di++)
3899                                         {
3900                                                 v3s16 dirp = dirs4[di];
3901                                                 u32 i2 = i;
3902                                                 vmanip.m_area.add_p(em, i2, dirp);
3903                                                 MapNode *n2 = &vmanip.m_data[i2];
3904                                                 if(
3905                                                         n2->d != CONTENT_AIR
3906                                                         && n2->d != CONTENT_WATERSOURCE
3907                                                         && n2->d != CONTENT_WATER
3908                                                 ){
3909                                                         add_to_sources = true;
3910                                                         break;
3911                                                 }
3912                                         }
3913                                 }
3914                                 
3915                                 n->setLight(LIGHTBANK_DAY, light);
3916                                 n->setLight(LIGHTBANK_NIGHT, 0);
3917                                 
3918                                 // This doesn't take much time
3919                                 if(light != 0 && add_to_sources)
3920                                 {
3921                                         // Insert light source
3922                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3923                                 }
3924                                 
3925                                 // Increment index by y
3926                                 vmanip.m_area.add_y(em, i, -1);
3927                         }
3928                 }
3929         }
3930 #endif
3931
3932         }//timer1
3933
3934         // Spread light around
3935         {
3936                 TimeTaker timer("generateChunkRaw() spreadLight");
3937                 vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
3938         }
3939         
3940         /*
3941                 Generation ended
3942         */
3943
3944         timer_generate.stop();
3945
3946         /*
3947                 Blit generated stuff to map
3948         */
3949         {
3950                 // 70ms @cs=8
3951                 //TimeTaker timer("generateChunkRaw() blitBackAll");
3952                 vmanip.blitBackAll(&changed_blocks);
3953         }
3954
3955         /*
3956                 Update day/night difference cache of the MapBlocks
3957         */
3958         {
3959                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
3960                                 i.atEnd() == false; i++)
3961                 {
3962                         MapBlock *block = i.getNode()->getValue();
3963                         block->updateDayNightDiff();
3964                 }
3965         }
3966
3967 #endif
3968         
3969         /*
3970                 Create chunk metadata
3971         */
3972
3973         for(s16 x=-1; x<=1; x++)
3974         for(s16 y=-1; y<=1; y++)
3975         {
3976                 v2s16 chunkpos0 = chunkpos + v2s16(x,y);
3977                 // Add chunk meta information
3978                 MapChunk *chunk = getChunk(chunkpos0);
3979                 if(chunk == NULL)
3980                 {
3981                         chunk = new MapChunk();
3982                         m_chunks.insert(chunkpos0, chunk);
3983                 }
3984                 //chunk->setIsVolatile(true);
3985                 if(chunk->getGenLevel() > GENERATED_PARTLY)
3986                         chunk->setGenLevel(GENERATED_PARTLY);
3987         }
3988
3989         /*
3990                 Set central chunk non-volatile
3991         */
3992         MapChunk *chunk = getChunk(chunkpos);
3993         assert(chunk);
3994         // Set non-volatile
3995         //chunk->setIsVolatile(false);
3996         chunk->setGenLevel(GENERATED_FULLY);
3997         
3998         /*
3999                 Save changed parts of map
4000         */
4001         save(true);
4002
4003         /*
4004                 Return central chunk (which was requested)
4005         */
4006         return chunk;
4007 }
4008
4009 MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
4010                 core::map<v3s16, MapBlock*> &changed_blocks)
4011 {
4012         dstream<<"generateChunk(): Generating chunk "
4013                         <<"("<<chunkpos1.X<<","<<chunkpos1.Y<<")"
4014                         <<std::endl;
4015         
4016         // Shall be not used now
4017         //assert(0);
4018         
4019         /*for(s16 x=-1; x<=1; x++)
4020         for(s16 y=-1; y<=1; y++)*/
4021         for(s16 x=-0; x<=0; x++)
4022         for(s16 y=-0; y<=0; y++)
4023         {
4024                 v2s16 chunkpos0 = chunkpos1 + v2s16(x,y);
4025                 MapChunk *chunk = getChunk(chunkpos0);
4026                 // Skip if already generated
4027                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
4028                         continue;
4029                 generateChunkRaw(chunkpos0, changed_blocks);
4030         }
4031         
4032         assert(chunkNonVolatile(chunkpos1));
4033
4034         MapChunk *chunk = getChunk(chunkpos1);
4035         return chunk;
4036 }
4037
4038 ServerMapSector * ServerMap::createSector(v2s16 p2d)
4039 {
4040         DSTACK("%s: p2d=(%d,%d)",
4041                         __FUNCTION_NAME,
4042                         p2d.X, p2d.Y);
4043         
4044         /*
4045                 Check if it exists already in memory
4046         */
4047         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
4048         if(sector != NULL)
4049                 return sector;
4050         
4051         /*
4052                 Try to load it from disk (with blocks)
4053         */
4054         if(loadSectorFull(p2d) == true)
4055         {
4056                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
4057                 if(sector == NULL)
4058                 {
4059                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
4060                         throw InvalidPositionException("");
4061                 }
4062                 return sector;
4063         }
4064
4065         /*
4066                 Do not create over-limit
4067         */
4068         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4069         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4070         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4071         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4072                 throw InvalidPositionException("createSector(): pos. over limit");
4073
4074         /*
4075                 Generate blank sector
4076         */
4077         
4078         sector = new ServerMapSector(this, p2d);
4079         
4080         // Sector position on map in nodes
4081         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
4082
4083         /*
4084                 Insert to container
4085         */
4086         m_sectors.insert(p2d, sector);
4087         
4088         return sector;
4089 }
4090
4091 MapSector * ServerMap::emergeSector(v2s16 p2d,
4092                 core::map<v3s16, MapBlock*> &changed_blocks)
4093 {
4094         DSTACK("%s: p2d=(%d,%d)",
4095                         __FUNCTION_NAME,
4096                         p2d.X, p2d.Y);
4097         
4098         /*
4099                 Check chunk status
4100         */
4101         v2s16 chunkpos = sector_to_chunk(p2d);
4102         /*bool chunk_nonvolatile = false;
4103         MapChunk *chunk = getChunk(chunkpos);
4104         if(chunk && chunk->getIsVolatile() == false)
4105                 chunk_nonvolatile = true;*/
4106         bool chunk_nonvolatile = chunkNonVolatile(chunkpos);
4107
4108         /*
4109                 If chunk is not fully generated, generate chunk
4110         */
4111         if(chunk_nonvolatile == false)
4112         {
4113                 // Generate chunk and neighbors
4114                 generateChunk(chunkpos, changed_blocks);
4115         }
4116         
4117         /*
4118                 Return sector if it exists now
4119         */
4120         MapSector *sector = getSectorNoGenerateNoEx(p2d);
4121         if(sector != NULL)
4122                 return sector;
4123         
4124         /*
4125                 Try to load it from disk
4126         */
4127         if(loadSectorFull(p2d) == true)
4128         {
4129                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
4130                 if(sector == NULL)
4131                 {
4132                         dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<<std::endl;
4133                         throw InvalidPositionException("");
4134                 }
4135                 return sector;
4136         }
4137
4138         /*
4139                 generateChunk should have generated the sector
4140         */
4141         //assert(0);
4142         
4143         dstream<<"WARNING: ServerMap::emergeSector: Cannot find sector ("
4144                         <<p2d.X<<","<<p2d.Y<<" and chunk is already generated. "
4145                         <<std::endl;
4146
4147 #if 1
4148         dstream<<"WARNING: Forcing regeneration of chunk."<<std::endl;
4149
4150         // Generate chunk
4151         generateChunkRaw(chunkpos, changed_blocks, true);
4152
4153         /*
4154                 Return sector if it exists now
4155         */
4156         sector = getSectorNoGenerateNoEx(p2d);
4157         if(sector != NULL)
4158                 return sector;
4159         
4160         dstream<<"ERROR: Could not get sector from anywhere."<<std::endl;
4161         
4162         //assert(0);
4163 #endif
4164         
4165 #if 1
4166         dstream<<"WARNING: Creating an empty sector."<<std::endl;
4167
4168         return createSector(p2d);
4169         
4170 #endif
4171         
4172         /*
4173                 Generate directly
4174         */
4175         //return generateSector();
4176 }
4177
4178 /*
4179         NOTE: This is not used for main map generation, only for blocks
4180         that are very high or low
4181 */
4182 MapBlock * ServerMap::generateBlock(
4183                 v3s16 p,
4184                 MapBlock *original_dummy,
4185                 ServerMapSector *sector,
4186                 core::map<v3s16, MapBlock*> &changed_blocks,
4187                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
4188 )
4189 {
4190         DSTACK("%s: p=(%d,%d,%d)",
4191                         __FUNCTION_NAME,
4192                         p.X, p.Y, p.Z);
4193         
4194         /*dstream<<"generateBlock(): "
4195                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4196                         <<std::endl;*/
4197         
4198         MapBlock *block = original_dummy;
4199                         
4200         v2s16 p2d(p.X, p.Z);
4201         s16 block_y = p.Y;
4202         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
4203         v3s16 p_nodes = p * MAP_BLOCKSIZE;
4204         
4205         /*
4206                 Do not generate over-limit
4207         */
4208         if(blockpos_over_limit(p))
4209         {
4210                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
4211                 throw InvalidPositionException("generateBlock(): pos. over limit");
4212         }
4213
4214         /*
4215                 If block doesn't exist, create one.
4216                 If it exists, it is a dummy. In that case unDummify() it.
4217
4218                 NOTE: This already sets the map as the parent of the block
4219         */
4220         if(block == NULL)
4221         {
4222                 block = sector->createBlankBlockNoInsert(block_y);
4223         }
4224         else
4225         {
4226                 // Remove the block so that nobody can get a half-generated one.
4227                 sector->removeBlock(block);
4228                 // Allocate the block to contain the generated data
4229                 block->unDummify();
4230         }
4231         
4232         u8 water_material = CONTENT_WATERSOURCE;
4233         
4234         s32 lowest_ground_y = 32767;
4235         s32 highest_ground_y = -32768;
4236
4237         enum{
4238                 BT_GROUND,
4239                 BT_SURFACE,
4240                 BT_SKY
4241         } block_type = BT_SURFACE;
4242
4243         {// ground_timer (0ms or ~100ms)
4244         TimeTaker ground_timer("Ground generation");
4245
4246         /*
4247                 Approximate whether this block is a surface block, an air
4248                 block or a ground block.
4249
4250                 This shall never mark a surface block as non-surface.
4251         */
4252
4253         {
4254                 /*
4255                         Estimate surface at different positions of the block, to
4256                         try to accomodate the effect of turbulence.
4257                 */
4258                 v3f checklist[] = {
4259                         v3f(0,0,0),
4260                         v3f(0,1,0),
4261                         v3f(0,1,1),
4262                         v3f(0,0,1),
4263                         v3f(1,0,0),
4264                         v3f(1,1,0),
4265                         v3f(1,1,1),
4266                         v3f(1,0,1),
4267                         v3f(0.5,0.5,0.5),
4268                 };
4269                 v3f p_nodes_f = intToFloat(p_nodes, 1);
4270                 float surface_y_max = -1000000;
4271                 float surface_y_min = 1000000;
4272                 for(u32 i=0; i<sizeof(checklist)/sizeof(checklist[0]); i++)
4273                 {
4274                         v3f p_map_f = p_nodes_f + checklist[i]*MAP_BLOCKSIZE;
4275
4276                         double depth_guess;
4277                         /*bool is_ground =*/ is_base_ground(m_seed, p_map_f, &depth_guess);
4278                         
4279                         // Estimate the surface height
4280                         float surface_y_f = p_map_f.Y + depth_guess;
4281
4282                         if(surface_y_f > surface_y_max)
4283                                 surface_y_max = surface_y_f;
4284                         if(surface_y_f < surface_y_min)
4285                                 surface_y_min = surface_y_f;
4286                 }
4287
4288                 float block_low_y_f = p_nodes_f.Y;
4289                 float block_high_y_f = p_nodes_f.Y + MAP_BLOCKSIZE;
4290
4291                 /*dstream<<"surface_y_max="<<surface_y_max
4292                                 <<", surface_y_min="<<surface_y_min
4293                                 <<", block_low_y_f="<<block_low_y_f
4294                                 <<", block_high_y_f="<<block_high_y_f
4295                                 <<std::endl;*/
4296                 
4297                 // A fuzzyness value
4298                 // Must accomodate mud and turbulence holes
4299                 float d_down = 16;
4300                 // Must accomodate a bit less
4301                 float d_up = 5;
4302
4303                 if(block_high_y_f < surface_y_min - d_down)
4304                 {
4305                         //dstream<<"BT_GROUND"<<std::endl;
4306                         // A ground block
4307                         block_type = BT_GROUND;
4308                 }
4309                 else if(block_low_y_f >= surface_y_max + d_up
4310                                 && block_low_y_f > WATER_LEVEL + d_up)
4311                 {
4312                         //dstream<<"BT_SKY"<<std::endl;
4313                         // A sky block
4314                         block_type = BT_SKY;
4315                 }
4316                 else
4317                 {
4318                         //dstream<<"BT_SURFACE"<<std::endl;
4319                         // A surface block
4320                         block_type = BT_SURFACE;
4321                 }
4322
4323                 if(/*block_type == BT_GROUND ||*/ block_type == BT_SKY)
4324                 {
4325                         lowest_ground_y = surface_y_min;
4326                         highest_ground_y = surface_y_max;
4327                 }
4328         }
4329         
4330         if(block_type == BT_SURFACE || block_type == BT_GROUND)
4331         {
4332                 /*
4333                         Generate ground precisely
4334                 */
4335                 
4336                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4337                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4338                 {
4339                         //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
4340
4341                         //s16 surface_y = 0;
4342
4343                         /*s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
4344                                         + AVERAGE_MUD_AMOUNT;
4345
4346                         if(surface_y < lowest_ground_y)
4347                                 lowest_ground_y = surface_y;
4348                         if(surface_y > highest_ground_y)
4349                                 highest_ground_y = surface_y;*/
4350
4351                         v2s16 real_p2d = v2s16(x0,z0) + p2d*MAP_BLOCKSIZE;
4352
4353                         //s32 surface_depth = AVERAGE_MUD_AMOUNT;
4354                         s16 surface_depth = get_mud_amount(m_seed, v2f(real_p2d.X,real_p2d.Y));
4355                         
4356                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4357                         {
4358         #if 1
4359                                 s16 real_y = block_y * MAP_BLOCKSIZE + y0;
4360                                 v3s16 real_pos = v3s16(x0,y0,z0) + p_nodes;
4361                                 MapNode n;
4362                                 /*
4363                                         Calculate lighting
4364                                         
4365                                         NOTE: If there are some man-made structures above the
4366                                         newly created block, they won't be taken into account.
4367                                 */
4368                                 /*if(real_y > surface_y)
4369                                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);*/
4370
4371                                 /*
4372                                         Calculate material
4373                                 */
4374                                 
4375                                 v3f real_pos_f = intToFloat(real_pos, 1);
4376                                 v2f real_pos_f_2d(real_pos_f.X, real_pos_f.Z);
4377                                 double depth_guess;
4378                                 bool is_ground = is_base_ground(m_seed,
4379                                                 real_pos_f, &depth_guess);
4380                                 
4381                                 // Estimate the surface height
4382                                 float surface_y_f = (float)real_y + depth_guess;
4383                                 s16 surface_y = real_y + depth_guess;
4384                                 
4385                                 // Get some statistics of surface height
4386                                 if(surface_y < lowest_ground_y)
4387                                         lowest_ground_y = surface_y;
4388                                 if(surface_y > highest_ground_y)
4389                                         highest_ground_y = surface_y;
4390
4391                                 // If node is not ground, it's air or water
4392                                 if(is_ground == false)
4393                                 {
4394                                         // If under water level, it's water
4395                                         if(real_y < WATER_LEVEL)
4396                                         {
4397                                                 n.d = water_material;
4398                                                 n.setLight(LIGHTBANK_DAY,
4399                                                                 diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
4400                                                 /*
4401                                                         Add to transforming liquid queue (in case it'd
4402                                                         start flowing)
4403                                                 */
4404                                                 m_transforming_liquid.push_back(real_pos);
4405                                         }
4406                                         // else air
4407                                         else
4408                                                 n.d = CONTENT_AIR;
4409                                 }
4410                                 // Else it's ground or dungeons (air)
4411                                 else
4412                                 {
4413                                         // If it's surface_depth under ground, it's stone
4414                                         if((float)real_y <= surface_y_f - surface_depth - 0.75)
4415                                         {
4416                                                 if(is_underground_mud(m_seed, real_pos_f))
4417                                                         n.d = CONTENT_MUD;
4418                                                 else
4419                                                         n.d = CONTENT_STONE;
4420                                         }
4421                                         else if(surface_y_f <= WATER_LEVEL + 2.1
4422                                                         && get_have_sand(m_seed, real_pos_f_2d))
4423                                         {
4424                                                 n.d = CONTENT_SAND;
4425                                         }
4426                                         else
4427                                         {
4428                                                 /*// It is mud if it is under the first ground
4429                                                 // level or under water
4430                                                 if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
4431                                                 {
4432                                                         n.d = CONTENT_MUD;
4433                                                 }
4434                                                 else
4435                                                 {
4436                                                         n.d = CONTENT_GRASS;
4437                                                 }*/
4438
4439                                                 n.d = CONTENT_MUD;
4440                                                 
4441                                                 /*// If under water level, it's mud
4442                                                 if(real_y < WATER_LEVEL)
4443                                                         n.d = CONTENT_MUD;
4444                                                 // Only the topmost node is grass
4445                                                 else if(real_y <= surface_y - 1)
4446                                                         n.d = CONTENT_MUD;
4447                                                 else
4448                                                         n.d = CONTENT_GRASS;*/
4449                                         }
4450                                 }
4451
4452                                 block->setNode(v3s16(x0,y0,z0), n);
4453         #endif
4454         #if 0
4455                                 s16 real_y = block_y * MAP_BLOCKSIZE + y0;
4456                                 MapNode n;
4457                                 /*
4458                                         Calculate lighting
4459                                         
4460                                         NOTE: If there are some man-made structures above the
4461                                         newly created block, they won't be taken into account.
4462                                 */
4463                                 if(real_y > surface_y)
4464                                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
4465
4466                                 /*
4467                                         Calculate material
4468                                 */
4469
4470                                 // If node is over heightmap y, it's air or water
4471                                 if(real_y > surface_y)
4472                                 {
4473                                         // If under water level, it's water
4474                                         if(real_y < WATER_LEVEL)
4475                                         {
4476                                                 n.d = water_material;
4477                                                 n.setLight(LIGHTBANK_DAY,
4478                                                                 diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
4479                                                 /*
4480                                                         Add to transforming liquid queue (in case it'd
4481                                                         start flowing)
4482                                                 */
4483                                                 v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
4484                                                 m_transforming_liquid.push_back(real_pos);
4485                                         }
4486                                         // else air
4487                                         else
4488                                                 n.d = CONTENT_AIR;
4489                                 }
4490                                 // Else it's ground or dungeons (air)
4491                                 else
4492                                 {
4493                                         // If it's surface_depth under ground, it's stone
4494                                         if(real_y <= surface_y - surface_depth)
4495                                         {
4496                                                 n.d = CONTENT_STONE;
4497                                         }
4498                                         else
4499                                         {
4500                                                 // It is mud if it is under the first ground
4501                                                 // level or under water
4502                                                 if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
4503                                                 {
4504                                                         n.d = CONTENT_MUD;
4505                                                 }
4506                                                 else
4507                                                 {
4508                                                         n.d = CONTENT_GRASS;
4509                                                 }
4510
4511                                                 //n.d = CONTENT_MUD;
4512                                                 
4513                                                 /*// If under water level, it's mud
4514                                                 if(real_y < WATER_LEVEL)
4515                                                         n.d = CONTENT_MUD;
4516                                                 // Only the topmost node is grass
4517                                                 else if(real_y <= surface_y - 1)
4518                                                         n.d = CONTENT_MUD;
4519                                                 else
4520                                                         n.d = CONTENT_GRASS;*/
4521                                         }
4522                                 }
4523
4524                                 block->setNode(v3s16(x0,y0,z0), n);
4525         #endif
4526                         }
4527                 }
4528         }// BT_SURFACE
4529         else // BT_GROUND, BT_SKY or anything else
4530         {
4531                 MapNode n_fill;
4532                 if(block_type == BT_GROUND)
4533                 {
4534                         //n_fill.d = CONTENT_STONE;
4535                 }
4536                 else if(block_type == BT_SKY)
4537                 {
4538                         n_fill.d = CONTENT_AIR;
4539                         n_fill.setLight(LIGHTBANK_DAY, LIGHT_SUN);
4540                 }
4541                 else // fallback
4542                 {
4543                         n_fill.d = CONTENT_MESE;
4544                 }
4545
4546
4547                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4548                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4549                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4550                 {
4551                         //MapNode n = block->getNode(v3s16(x0,y0,z0));
4552                         block->setNode(v3s16(x0,y0,z0), n_fill);
4553                 }
4554         }
4555         
4556         }// ground_timer
4557         
4558         /*
4559                 Calculate some helper variables
4560         */
4561         
4562         // Completely underground if the highest part of block is under lowest
4563         // ground height.
4564         // This has to be very sure; it's probably one too strict now but
4565         // that's just better.
4566         bool completely_underground =
4567                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
4568
4569         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
4570
4571         bool mostly_underwater_surface = false;
4572         if(highest_ground_y < WATER_LEVEL
4573                         && some_part_underground && !completely_underground)
4574                 mostly_underwater_surface = true;
4575
4576         /*
4577                 Get local attributes
4578         */
4579
4580         //dstream<<"generateBlock(): Getting local attributes"<<std::endl;
4581
4582         //float caves_amount = 0.5;
4583
4584 #if 0
4585         {
4586                 /*
4587                         NOTE: BEWARE: Too big amount of attribute points slows verything
4588                         down by a lot.
4589                         1 interpolation from 5000 points takes 2-3ms.
4590                 */
4591                 //TimeTaker timer("generateBlock() local attribute retrieval");
4592                 v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
4593                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
4594                 caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
4595         }
4596 #endif
4597
4598         //dstream<<"generateBlock(): Done"<<std::endl;
4599
4600 #if 0
4601         // Set to true if has caves.
4602         // Set when some non-air is changed to air when making caves.
4603         bool has_dungeons = false;
4604
4605         /*
4606                 Generate dungeons
4607         */
4608
4609         // Initialize temporary table
4610         const s32 ued = MAP_BLOCKSIZE;
4611         bool underground_emptiness[ued*ued*ued];
4612         for(s32 i=0; i<ued*ued*ued; i++)
4613         {
4614                 underground_emptiness[i] = 0;
4615         }
4616         
4617         // Fill table
4618 #if 0
4619         {
4620                 /*
4621                         Initialize orp and ors. Try to find if some neighboring
4622                         MapBlock has a tunnel ended in its side
4623                 */
4624
4625                 v3f orp(
4626                         (float)(myrand()%ued)+0.5,
4627                         (float)(myrand()%ued)+0.5,
4628                         (float)(myrand()%ued)+0.5
4629                 );
4630                 
4631                 bool found_existing = false;
4632
4633                 // Check z-
4634                 try
4635                 {
4636                         s16 z = -1;
4637                         for(s16 y=0; y<ued; y++)
4638                         for(s16 x=0; x<ued; x++)
4639                         {
4640                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4641                                 if(getNode(ap).d == CONTENT_AIR)
4642                                 {
4643                                         orp = v3f(x+1,y+1,0);
4644                                         found_existing = true;
4645                                         goto continue_generating;
4646                                 }
4647                         }
4648                 }
4649                 catch(InvalidPositionException &e){}
4650                 
4651                 // Check z+
4652                 try
4653                 {
4654                         s16 z = ued;
4655                         for(s16 y=0; y<ued; y++)
4656                         for(s16 x=0; x<ued; x++)
4657                         {
4658                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4659                                 if(getNode(ap).d == CONTENT_AIR)
4660                                 {
4661                                         orp = v3f(x+1,y+1,ued-1);
4662                                         found_existing = true;
4663                                         goto continue_generating;
4664                                 }
4665                         }
4666                 }
4667                 catch(InvalidPositionException &e){}
4668                 
4669                 // Check x-
4670                 try
4671                 {
4672                         s16 x = -1;
4673                         for(s16 y=0; y<ued; y++)
4674                         for(s16 z=0; z<ued; z++)
4675                         {
4676                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4677                                 if(getNode(ap).d == CONTENT_AIR)
4678                                 {
4679                                         orp = v3f(0,y+1,z+1);
4680                                         found_existing = true;
4681                                         goto continue_generating;
4682                                 }
4683                         }
4684                 }
4685                 catch(InvalidPositionException &e){}
4686                 
4687                 // Check x+
4688                 try
4689                 {
4690                         s16 x = ued;
4691                         for(s16 y=0; y<ued; y++)
4692                         for(s16 z=0; z<ued; z++)
4693                         {
4694                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4695                                 if(getNode(ap).d == CONTENT_AIR)
4696                                 {
4697                                         orp = v3f(ued-1,y+1,z+1);
4698                                         found_existing = true;
4699                                         goto continue_generating;
4700                                 }
4701                         }
4702                 }
4703                 catch(InvalidPositionException &e){}
4704
4705                 // Check y-
4706                 try
4707                 {
4708                         s16 y = -1;
4709                         for(s16 x=0; x<ued; x++)
4710                         for(s16 z=0; z<ued; z++)
4711                         {
4712                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4713                                 if(getNode(ap).d == CONTENT_AIR)
4714                                 {
4715                                         orp = v3f(x+1,0,z+1);
4716                                         found_existing = true;
4717                                         goto continue_generating;
4718                                 }
4719                         }
4720                 }
4721                 catch(InvalidPositionException &e){}
4722                 
4723                 // Check y+
4724                 try
4725                 {
4726                         s16 y = ued;
4727                         for(s16 x=0; x<ued; x++)
4728                         for(s16 z=0; z<ued; z++)
4729                         {
4730                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4731                                 if(getNode(ap).d == CONTENT_AIR)
4732                                 {
4733                                         orp = v3f(x+1,ued-1,z+1);
4734                                         found_existing = true;
4735                                         goto continue_generating;
4736                                 }
4737                         }
4738                 }
4739                 catch(InvalidPositionException &e){}
4740
4741 continue_generating:
4742                 
4743                 /*
4744                         Choose whether to actually generate dungeon
4745                 */
4746                 bool do_generate_dungeons = true;
4747                 // Don't generate if no part is underground
4748                 if(!some_part_underground)
4749                 {
4750                         do_generate_dungeons = false;
4751                 }
4752                 // Don't generate if mostly underwater surface
4753                 /*else if(mostly_underwater_surface)
4754                 {
4755                         do_generate_dungeons = false;
4756                 }*/
4757                 // Partly underground = cave
4758                 else if(!completely_underground)
4759                 {
4760                         //do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
4761                         do_generate_dungeons = false;
4762                 }
4763                 // Found existing dungeon underground
4764                 else if(found_existing && completely_underground)
4765                 {
4766                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
4767                 }
4768                 // Underground and no dungeons found
4769                 else
4770                 {
4771                         do_generate_dungeons = (rand() % 300 <= (s32)(caves_amount*100));
4772                 }
4773
4774                 if(do_generate_dungeons)
4775                 {
4776                         /*
4777                                 Generate some tunnel starting from orp and ors
4778                         */
4779                         for(u16 i=0; i<3; i++)
4780                         {
4781                                 v3f rp(
4782                                         (float)(myrand()%ued)+0.5,
4783                                         (float)(myrand()%ued)+0.5,
4784                                         (float)(myrand()%ued)+0.5
4785                                 );
4786                                 s16 min_d = 0;
4787                                 s16 max_d = 4;
4788                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
4789                                 
4790                                 v3f vec = rp - orp;
4791
4792                                 for(float f=0; f<1.0; f+=0.04)
4793                                 {
4794                                         v3f fp = orp + vec * f;
4795                                         v3s16 cp(fp.X, fp.Y, fp.Z);
4796                                         s16 d0 = -rs/2;
4797                                         s16 d1 = d0 + rs - 1;
4798                                         for(s16 z0=d0; z0<=d1; z0++)
4799                                         {
4800                                                 s16 si = rs - abs(z0);
4801                                                 for(s16 x0=-si; x0<=si-1; x0++)
4802                                                 {
4803                                                         s16 si2 = rs - abs(x0);
4804                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
4805                                                         {
4806                                                                 s16 z = cp.Z + z0;
4807                                                                 s16 y = cp.Y + y0;
4808                                                                 s16 x = cp.X + x0;
4809                                                                 v3s16 p(x,y,z);
4810                                                                 if(isInArea(p, ued) == false)
4811                                                                         continue;
4812                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
4813                                                         }
4814                                                 }
4815                                         }
4816                                 }
4817
4818                                 orp = rp;
4819                         }
4820                 }
4821         }
4822 #endif
4823
4824         /*
4825                 Apply temporary cave data to block
4826         */
4827
4828         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4829         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4830         {
4831                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4832                 {
4833                         MapNode n = block->getNode(v3s16(x0,y0,z0));
4834
4835                         // Create dungeons
4836                         if(underground_emptiness[
4837                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
4838                                         +ued*(y0*ued/MAP_BLOCKSIZE)
4839                                         +(x0*ued/MAP_BLOCKSIZE)])
4840                         {
4841                                 if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
4842                                 {
4843                                         // Has now caves
4844                                         has_dungeons = true;
4845                                         // Set air to node
4846                                         n.d = CONTENT_AIR;
4847                                 }
4848                         }
4849
4850                         block->setNode(v3s16(x0,y0,z0), n);
4851                 }
4852         }
4853 #endif
4854         
4855         /*
4856                 This is used for guessing whether or not the block should
4857                 receive sunlight from the top if the block above doesn't exist
4858         */
4859         block->setIsUnderground(completely_underground);
4860
4861         /*
4862                 Force lighting update if some part of block is partly
4863                 underground and has caves.
4864         */
4865         /*if(some_part_underground && !completely_underground && has_dungeons)
4866         {
4867                 //dstream<<"Half-ground caves"<<std::endl;
4868                 lighting_invalidated_blocks[block->getPos()] = block;
4869         }*/
4870         
4871         // DEBUG: Always update lighting
4872         //lighting_invalidated_blocks[block->getPos()] = block;
4873
4874         /*
4875                 Add some minerals
4876         */
4877
4878         if(some_part_underground)
4879         {
4880                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
4881
4882                 /*
4883                         Add meseblocks
4884                 */
4885                 for(s16 i=0; i<underground_level/4 + 1; i++)
4886                 {
4887                         if(myrand()%50 == 0)
4888                         {
4889                                 v3s16 cp(
4890                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4891                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4892                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4893                                 );
4894
4895                                 MapNode n;
4896                                 n.d = CONTENT_MESE;
4897                                 
4898                                 for(u16 i=0; i<27; i++)
4899                                 {
4900                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4901                                                 if(myrand()%8 == 0)
4902                                                         block->setNode(cp+g_27dirs[i], n);
4903                                 }
4904                         }
4905                 }
4906
4907                 /*
4908                         Add coal
4909                 */
4910                 u16 coal_amount = 60;
4911                 u16 coal_rareness = 120 / coal_amount;
4912                 if(coal_rareness == 0)
4913                         coal_rareness = 1;
4914                 if(myrand()%coal_rareness == 0)
4915                 {
4916                         u16 a = myrand() % 16;
4917                         u16 amount = coal_amount * a*a*a / 1000;
4918                         for(s16 i=0; i<amount; i++)
4919                         {
4920                                 v3s16 cp(
4921                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4922                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4923                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4924                                 );
4925
4926                                 MapNode n;
4927                                 n.d = CONTENT_STONE;
4928                                 n.param = MINERAL_COAL;
4929
4930                                 for(u16 i=0; i<27; i++)
4931                                 {
4932                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4933                                                 if(myrand()%8 == 0)
4934                                                         block->setNode(cp+g_27dirs[i], n);
4935                                 }
4936                         }
4937                 }
4938
4939                 /*
4940                         Add iron
4941                 */
4942                 u16 iron_amount = 40;
4943                 u16 iron_rareness = 80 / iron_amount;
4944                 if(iron_rareness == 0)
4945                         iron_rareness = 1;
4946                 if(myrand()%iron_rareness == 0)
4947                 {
4948                         u16 a = myrand() % 16;
4949                         u16 amount = iron_amount * a*a*a / 1000;
4950                         for(s16 i=0; i<amount; i++)
4951                         {
4952                                 v3s16 cp(
4953                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4954                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4955                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4956                                 );
4957
4958                                 MapNode n;
4959                                 n.d = CONTENT_STONE;
4960                                 n.param = MINERAL_IRON;
4961
4962                                 for(u16 i=0; i<27; i++)
4963                                 {
4964                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4965                                                 if(myrand()%8 == 0)
4966                                                         block->setNode(cp+g_27dirs[i], n);
4967                                 }
4968                         }
4969                 }
4970         }
4971         
4972         /*
4973                 Create a few rats in empty blocks underground
4974         */
4975         if(completely_underground)
4976         {
4977                 //for(u16 i=0; i<2; i++)
4978                 {
4979                         v3s16 cp(
4980                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4981                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4982                                 (myrand()%(MAP_BLOCKSIZE-2))+1
4983                         );
4984
4985                         // Check that the place is empty
4986                         //if(!is_ground_content(block->getNode(cp).d))
4987                         if(1)
4988                         {
4989                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp, BS));
4990                                 block->addObject(obj);
4991                         }
4992                 }
4993         }
4994         
4995         /*
4996                 Add block to sector
4997         */
4998         sector->insertBlock(block);
4999         
5000         // Lighting is invalid after generation for surface blocks
5001         if(block_type == BT_SURFACE)
5002         {
5003 #if 1
5004                 block->setLightingExpired(true);
5005                 lighting_invalidated_blocks.insert(p, block);
5006 #else
5007                 block->setLightingExpired(false);
5008 #endif
5009         }
5010         // Lighting is not invalid for other blocks
5011         else
5012         {
5013                 block->setLightingExpired(false);
5014         }
5015
5016         /*
5017                 Add trees
5018         */
5019 #if 1
5020         if(some_part_underground && !completely_underground)
5021         {
5022                 MapVoxelManipulator vm(this);
5023                 
5024                 double a = tree_amount_2d(m_seed, v2s16(p_nodes.X+8, p_nodes.Z+8));
5025                 u16 tree_count = (u16)(a*MAP_BLOCKSIZE*MAP_BLOCKSIZE);
5026                 for(u16 i=0; i<tree_count/2; i++)
5027                 {
5028                         v3s16 tree_p = p_nodes + v3s16(
5029                                 myrand_range(0,MAP_BLOCKSIZE-1),
5030                                 8,
5031                                 myrand_range(0,MAP_BLOCKSIZE-1)
5032                         );
5033                         double depth_guess;
5034                         /*bool is_ground =*/ is_base_ground(m_seed,
5035                                         intToFloat(tree_p, 1), &depth_guess);
5036                         tree_p.Y += (depth_guess - 0.5);
5037                         if(tree_p.Y <= WATER_LEVEL)
5038                                 continue;
5039                         make_tree(vm, tree_p);
5040                 }
5041
5042                 vm.blitBack(changed_blocks);
5043         }
5044 #endif
5045         
5046 #if 0
5047         /*
5048                 Debug information
5049         */
5050         dstream
5051         <<"lighting_invalidated_blocks.size()"
5052         <<", has_dungeons"
5053         <<", completely_ug"
5054         <<", some_part_ug"
5055         <<"  "<<lighting_invalidated_blocks.size()
5056         <<", "<<has_dungeons
5057         <<", "<<completely_underground
5058         <<", "<<some_part_underground
5059         <<std::endl;
5060 #endif
5061
5062         return block;
5063 }
5064
5065 MapBlock * ServerMap::createBlock(v3s16 p)
5066 {
5067         DSTACK("%s: p=(%d,%d,%d)",
5068                         __FUNCTION_NAME, p.X, p.Y, p.Z);
5069         
5070         /*
5071                 Do not create over-limit
5072         */
5073         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5074         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5075         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5076         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5077         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5078         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
5079                 throw InvalidPositionException("createBlock(): pos. over limit");
5080         
5081         v2s16 p2d(p.X, p.Z);
5082         s16 block_y = p.Y;
5083         /*
5084                 This will create or load a sector if not found in memory.
5085                 If block exists on disk, it will be loaded.
5086
5087                 NOTE: On old save formats, this will be slow, as it generates
5088                       lighting on blocks for them.
5089         */
5090         ServerMapSector *sector;
5091         try{
5092                 sector = (ServerMapSector*)createSector(p2d);
5093                 assert(sector->getId() == MAPSECTOR_SERVER);
5094         }
5095         catch(InvalidPositionException &e)
5096         {
5097                 dstream<<"createBlock: createSector() failed"<<std::endl;
5098                 throw e;
5099         }
5100         /*
5101                 NOTE: This should not be done, or at least the exception
5102                 should not be passed on as std::exception, because it
5103                 won't be catched at all.
5104         */
5105         /*catch(std::exception &e)
5106         {
5107                 dstream<<"createBlock: createSector() failed: "
5108                                 <<e.what()<<std::endl;
5109                 throw e;
5110         }*/
5111
5112         /*
5113                 Try to get a block from the sector
5114         */
5115
5116         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
5117         if(block)
5118                 return block;
5119         // Create blank
5120         block = sector->createBlankBlock(block_y);
5121         return block;
5122 }
5123
5124 MapBlock * ServerMap::emergeBlock(
5125                 v3s16 p,
5126                 bool only_from_disk,
5127                 core::map<v3s16, MapBlock*> &changed_blocks,
5128                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
5129 )
5130 {
5131         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
5132                         __FUNCTION_NAME,
5133                         p.X, p.Y, p.Z, only_from_disk);
5134         
5135         /*
5136                 Do not generate over-limit
5137         */
5138         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5139         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5140         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5141         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5142         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
5143         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
5144                 throw InvalidPositionException("emergeBlock(): pos. over limit");
5145         
5146         v2s16 p2d(p.X, p.Z);
5147         s16 block_y = p.Y;
5148         /*
5149                 This will create or load a sector if not found in memory.
5150                 If block exists on disk, it will be loaded.
5151         */
5152         ServerMapSector *sector;
5153         try{
5154                 sector = (ServerMapSector*)emergeSector(p2d, changed_blocks);
5155                 assert(sector->getId() == MAPSECTOR_SERVER);
5156         }
5157         catch(InvalidPositionException &e)
5158         {
5159                 dstream<<"emergeBlock: emergeSector() failed: "
5160                                 <<e.what()<<std::endl;
5161                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
5162                                 <<std::endl
5163                                 <<"You could try to delete it."<<std::endl;
5164                 throw e;
5165         }
5166         catch(VersionMismatchException &e)
5167         {
5168                 dstream<<"emergeBlock: emergeSector() failed: "
5169                                 <<e.what()<<std::endl;
5170                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
5171                                 <<std::endl
5172                                 <<"You could try to delete it."<<std::endl;
5173                 throw e;
5174         }
5175         /*
5176                 NOTE: This should not be done, or at least the exception
5177                 should not be passed on as std::exception, because it
5178                 won't be catched at all.
5179         */
5180         /*catch(std::exception &e)
5181         {
5182                 dstream<<"emergeBlock: emergeSector() failed: "
5183                                 <<e.what()<<std::endl;
5184                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
5185                                 <<std::endl
5186                                 <<"You could try to delete it."<<std::endl;
5187                 throw e;
5188         }*/
5189
5190         /*
5191                 Try to get a block from the sector
5192         */
5193
5194         bool does_not_exist = false;
5195         bool lighting_expired = false;
5196         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
5197
5198         if(block == NULL)
5199         {
5200                 does_not_exist = true;
5201         }
5202         else if(block->isDummy() == true)
5203         {
5204                 does_not_exist = true;
5205         }
5206         else if(block->getLightingExpired())
5207         {
5208                 lighting_expired = true;
5209         }
5210         else
5211         {
5212                 // Valid block
5213                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
5214                 return block;
5215         }
5216         
5217         /*
5218                 If block was not found on disk and not going to generate a
5219                 new one, make sure there is a dummy block in place.
5220         */
5221         if(only_from_disk && (does_not_exist || lighting_expired))
5222         {
5223                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
5224
5225                 if(block == NULL)
5226                 {
5227                         // Create dummy block
5228                         block = new MapBlock(this, p, true);
5229
5230                         // Add block to sector
5231                         sector->insertBlock(block);
5232                 }
5233                 // Done.
5234                 return block;
5235         }
5236
5237         //dstream<<"Not found on disk, generating."<<std::endl;
5238         // 0ms
5239         //TimeTaker("emergeBlock() generate");
5240
5241         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
5242
5243         /*
5244                 If the block doesn't exist, generate the block.
5245         */
5246         if(does_not_exist)
5247         {
5248                 block = generateBlock(p, block, sector, changed_blocks,
5249                                 lighting_invalidated_blocks);
5250
5251                 lighting_expired = block->getLightingExpired();
5252         }
5253
5254         if(lighting_expired)
5255         {
5256                 lighting_invalidated_blocks.insert(p, block);
5257         }
5258
5259         /*
5260                 Initially update sunlight
5261         */
5262         
5263         if(lighting_expired)
5264         {
5265                 core::map<v3s16, bool> light_sources;
5266                 bool black_air_left = false;
5267                 bool bottom_invalid =
5268                                 block->propagateSunlight(light_sources, true,
5269                                 &black_air_left, true);
5270
5271                 // If sunlight didn't reach everywhere and part of block is
5272                 // above ground, lighting has to be properly updated
5273                 //if(black_air_left && some_part_underground)
5274                 if(black_air_left)
5275                 {
5276                         lighting_invalidated_blocks[block->getPos()] = block;
5277                 }
5278
5279                 if(bottom_invalid)
5280                 {
5281                         lighting_invalidated_blocks[block->getPos()] = block;
5282                 }
5283         }
5284         
5285         return block;
5286 }
5287
5288 s16 ServerMap::findGroundLevel(v2s16 p2d)
5289 {
5290         /*
5291                 Uh, just do something random...
5292         */
5293         // Find existing map from top to down
5294         s16 max=63;
5295         s16 min=-64;
5296         v3s16 p(p2d.X, max, p2d.Y);
5297         for(; p.Y>min; p.Y--)
5298         {
5299                 MapNode n = getNodeNoEx(p);
5300                 if(n.d != CONTENT_IGNORE)
5301                         break;
5302         }
5303         if(p.Y == min)
5304                 goto plan_b;
5305         // If this node is not air, go to plan b
5306         if(getNodeNoEx(p).d != CONTENT_AIR)
5307                 goto plan_b;
5308         // Search existing walkable and return it
5309         for(; p.Y>min; p.Y--)
5310         {
5311                 MapNode n = getNodeNoEx(p);
5312                 if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
5313                         return p.Y;
5314         }
5315         // Move to plan b
5316 plan_b:
5317         /*
5318                 Plan B: Get from map generator perlin noise function
5319         */
5320         double level = base_rock_level_2d(m_seed, p2d);
5321         return (s16)level;
5322 }
5323
5324 void ServerMap::createDir(std::string path)
5325 {
5326         if(fs::CreateDir(path) == false)
5327         {
5328                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
5329                                 <<"\""<<path<<"\""<<std::endl;
5330                 throw BaseException("ServerMap failed to create directory");
5331         }
5332 }
5333
5334 std::string ServerMap::getSectorSubDir(v2s16 pos)
5335 {
5336         char cc[9];
5337         snprintf(cc, 9, "%.4x%.4x",
5338                         (unsigned int)pos.X&0xffff,
5339                         (unsigned int)pos.Y&0xffff);
5340
5341         return std::string(cc);
5342 }
5343
5344 std::string ServerMap::getSectorDir(v2s16 pos)
5345 {
5346         return m_savedir + "/sectors/" + getSectorSubDir(pos);
5347 }
5348
5349 v2s16 ServerMap::getSectorPos(std::string dirname)
5350 {
5351         if(dirname.size() != 8)
5352                 throw InvalidFilenameException("Invalid sector directory name");
5353         unsigned int x, y;
5354         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
5355         if(r != 2)
5356                 throw InvalidFilenameException("Invalid sector directory name");
5357         v2s16 pos((s16)x, (s16)y);
5358         return pos;
5359 }
5360
5361 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
5362 {
5363         v2s16 p2d = getSectorPos(sectordir);
5364
5365         if(blockfile.size() != 4){
5366                 throw InvalidFilenameException("Invalid block filename");
5367         }
5368         unsigned int y;
5369         int r = sscanf(blockfile.c_str(), "%4x", &y);
5370         if(r != 1)
5371                 throw InvalidFilenameException("Invalid block filename");
5372         return v3s16(p2d.X, y, p2d.Y);
5373 }
5374
5375 void ServerMap::save(bool only_changed)
5376 {
5377         DSTACK(__FUNCTION_NAME);
5378         if(m_map_saving_enabled == false)
5379         {
5380                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
5381                 return;
5382         }
5383         
5384         if(only_changed == false)
5385                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
5386                                 <<std::endl;
5387         
5388         saveMapMeta();
5389         saveChunkMeta();
5390         
5391         u32 sector_meta_count = 0;
5392         u32 block_count = 0;
5393         
5394         { //sectorlock
5395         JMutexAutoLock lock(m_sector_mutex);
5396         
5397         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
5398         for(; i.atEnd() == false; i++)
5399         {
5400                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
5401                 assert(sector->getId() == MAPSECTOR_SERVER);
5402         
5403                 if(sector->differs_from_disk || only_changed == false)
5404                 {
5405                         saveSectorMeta(sector);
5406                         sector_meta_count++;
5407                 }
5408                 core::list<MapBlock*> blocks;
5409                 sector->getBlocks(blocks);
5410                 core::list<MapBlock*>::Iterator j;
5411                 for(j=blocks.begin(); j!=blocks.end(); j++)
5412                 {
5413                         MapBlock *block = *j;
5414                         if(block->getChangedFlag() || only_changed == false)
5415                         {
5416                                 saveBlock(block);
5417                                 block_count++;
5418
5419                                 /*dstream<<"ServerMap: Written block ("
5420                                                 <<block->getPos().X<<","
5421                                                 <<block->getPos().Y<<","
5422                                                 <<block->getPos().Z<<")"
5423                                                 <<std::endl;*/
5424                         }
5425                 }
5426         }
5427
5428         }//sectorlock
5429         
5430         /*
5431                 Only print if something happened or saved whole map
5432         */
5433         if(only_changed == false || sector_meta_count != 0
5434                         || block_count != 0)
5435         {
5436                 dstream<<DTIME<<"ServerMap: Written: "
5437                                 <<sector_meta_count<<" sector metadata files, "
5438                                 <<block_count<<" block files"
5439                                 <<std::endl;
5440         }
5441 }
5442
5443 void ServerMap::loadAll()
5444 {
5445         DSTACK(__FUNCTION_NAME);
5446         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
5447         
5448         loadMapMeta();
5449         loadChunkMeta();
5450
5451         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
5452
5453         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
5454         
5455         JMutexAutoLock lock(m_sector_mutex);
5456         
5457         s32 counter = 0;
5458         s32 printed_counter = -100000;
5459         s32 count = list.size();
5460
5461         std::vector<fs::DirListNode>::iterator i;
5462         for(i=list.begin(); i!=list.end(); i++)
5463         {
5464                 if(counter > printed_counter + 10)
5465                 {
5466                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
5467                         printed_counter = counter;
5468                 }
5469                 counter++;
5470
5471                 MapSector *sector = NULL;
5472
5473                 // We want directories
5474                 if(i->dir == false)
5475                         continue;
5476                 try{
5477                         sector = loadSectorMeta(i->name);
5478                 }
5479                 catch(InvalidFilenameException &e)
5480                 {
5481                         // This catches unknown crap in directory
5482                 }
5483                 
5484                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
5485                                 (m_savedir+"/sectors/"+i->name);
5486                 std::vector<fs::DirListNode>::iterator i2;
5487                 for(i2=list2.begin(); i2!=list2.end(); i2++)
5488                 {
5489                         // We want files
5490                         if(i2->dir)
5491                                 continue;
5492                         try{
5493                                 loadBlock(i->name, i2->name, sector);
5494                         }
5495                         catch(InvalidFilenameException &e)
5496                         {
5497                                 // This catches unknown crap in directory
5498                         }
5499                 }
5500         }
5501         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
5502 }
5503
5504 #if 0
5505 void ServerMap::saveMasterHeightmap()
5506 {
5507         DSTACK(__FUNCTION_NAME);
5508         
5509         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
5510
5511         createDir(m_savedir);
5512         
5513         /*std::string fullpath = m_savedir + "/master_heightmap";
5514         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5515         if(o.good() == false)
5516                 throw FileNotGoodException("Cannot open master heightmap");*/
5517         
5518         // Format used for writing
5519         //u8 version = SER_FMT_VER_HIGHEST;
5520 }
5521
5522 void ServerMap::loadMasterHeightmap()
5523 {
5524         DSTACK(__FUNCTION_NAME);
5525         
5526         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
5527
5528         /*std::string fullpath = m_savedir + "/master_heightmap";
5529         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5530         if(is.good() == false)
5531                 throw FileNotGoodException("Cannot open master heightmap");*/
5532 }
5533 #endif
5534
5535 void ServerMap::saveMapMeta()
5536 {
5537         DSTACK(__FUNCTION_NAME);
5538         
5539         dstream<<"INFO: ServerMap::saveMapMeta(): "
5540                         <<"seed="<<m_seed<<", chunksize="<<m_chunksize
5541                         <<std::endl;
5542
5543         createDir(m_savedir);
5544         
5545         std::string fullpath = m_savedir + "/map_meta.txt";
5546         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
5547         if(os.good() == false)
5548         {
5549                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
5550                                 <<"could not open"<<fullpath<<std::endl;
5551                 throw FileNotGoodException("Cannot open chunk metadata");
5552         }
5553         
5554         Settings params;
5555         params.setU64("seed", m_seed);
5556         params.setS32("chunksize", m_chunksize);
5557
5558         params.writeLines(os);
5559
5560         os<<"[end_of_params]\n";
5561         
5562 }
5563
5564 void ServerMap::loadMapMeta()
5565 {
5566         DSTACK(__FUNCTION_NAME);
5567         
5568         dstream<<"INFO: ServerMap::loadMapMeta(): Loading chunk metadata"
5569                         <<std::endl;
5570
5571         std::string fullpath = m_savedir + "/map_meta.txt";
5572         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5573         if(is.good() == false)
5574         {
5575                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
5576                                 <<"could not open"<<fullpath<<std::endl;
5577                 throw FileNotGoodException("Cannot open chunk metadata");
5578         }
5579
5580         Settings params;
5581
5582         for(;;)
5583         {
5584                 if(is.eof())
5585                         throw SerializationError
5586                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
5587                 std::string line;
5588                 std::getline(is, line);
5589                 std::string trimmedline = trim(line);
5590                 if(trimmedline == "[end_of_params]")
5591                         break;
5592                 params.parseConfigLine(line);
5593         }
5594
5595         m_seed = params.getU64("seed");
5596         m_chunksize = params.getS32("chunksize");
5597
5598         dstream<<"INFO: ServerMap::loadMapMeta(): "
5599                         <<"seed="<<m_seed<<", chunksize="<<m_chunksize
5600                         <<std::endl;
5601 }
5602
5603 void ServerMap::saveChunkMeta()
5604 {
5605         DSTACK(__FUNCTION_NAME);
5606         
5607         u32 count = m_chunks.size();
5608
5609         dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
5610                         <<count<<" chunks"<<std::endl;
5611
5612         createDir(m_savedir);
5613         
5614         std::string fullpath = m_savedir + "/chunk_meta";
5615         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
5616         if(os.good() == false)
5617         {
5618                 dstream<<"ERROR: ServerMap::saveChunkMeta(): "
5619                                 <<"could not open"<<fullpath<<std::endl;
5620                 throw FileNotGoodException("Cannot open chunk metadata");
5621         }
5622         
5623         u8 version = 0;
5624         
5625         // Write version
5626         os.write((char*)&version, 1);
5627
5628         u8 buf[4];
5629         
5630         // Write count
5631         writeU32(buf, count);
5632         os.write((char*)buf, 4);
5633         
5634         for(core::map<v2s16, MapChunk*>::Iterator
5635                         i = m_chunks.getIterator();
5636                         i.atEnd()==false; i++)
5637         {
5638                 v2s16 p = i.getNode()->getKey();
5639                 MapChunk *chunk = i.getNode()->getValue();
5640                 // Write position
5641                 writeV2S16(buf, p);
5642                 os.write((char*)buf, 4);
5643                 // Write chunk data
5644                 chunk->serialize(os, version);
5645         }
5646 }
5647
5648 void ServerMap::loadChunkMeta()
5649 {
5650         DSTACK(__FUNCTION_NAME);
5651         
5652         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading chunk metadata"
5653                         <<std::endl;
5654
5655         std::string fullpath = m_savedir + "/chunk_meta";
5656         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5657         if(is.good() == false)
5658         {
5659                 dstream<<"ERROR: ServerMap::loadChunkMeta(): "
5660                                 <<"could not open"<<fullpath<<std::endl;
5661                 throw FileNotGoodException("Cannot open chunk metadata");
5662         }
5663
5664         u8 version = 0;
5665         
5666         // Read version
5667         is.read((char*)&version, 1);
5668
5669         u8 buf[4];
5670         
5671         // Read count
5672         is.read((char*)buf, 4);
5673         u32 count = readU32(buf);
5674
5675         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading metadata of "
5676                         <<count<<" chunks"<<std::endl;
5677         
5678         for(u32 i=0; i<count; i++)
5679         {
5680                 v2s16 p;
5681                 MapChunk *chunk = new MapChunk();
5682                 // Read position
5683                 is.read((char*)buf, 4);
5684                 p = readV2S16(buf);
5685                 // Read chunk data
5686                 chunk->deSerialize(is, version);
5687                 m_chunks.insert(p, chunk);
5688         }
5689 }
5690
5691 void ServerMap::saveSectorMeta(ServerMapSector *sector)
5692 {
5693         DSTACK(__FUNCTION_NAME);
5694         // Format used for writing
5695         u8 version = SER_FMT_VER_HIGHEST;
5696         // Get destination
5697         v2s16 pos = sector->getPos();
5698         createDir(m_savedir);
5699         createDir(m_savedir+"/sectors");
5700         std::string dir = getSectorDir(pos);
5701         createDir(dir);
5702         
5703         std::string fullpath = dir + "/meta";
5704         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5705         if(o.good() == false)
5706                 throw FileNotGoodException("Cannot open sector metafile");
5707
5708         sector->serialize(o, version);
5709         
5710         sector->differs_from_disk = false;
5711 }
5712
5713 MapSector* ServerMap::loadSectorMeta(std::string dirname)
5714 {
5715         DSTACK(__FUNCTION_NAME);
5716         // Get destination
5717         v2s16 p2d = getSectorPos(dirname);
5718         std::string dir = m_savedir + "/sectors/" + dirname;
5719         
5720         std::string fullpath = dir + "/meta";
5721         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5722         if(is.good() == false)
5723                 throw FileNotGoodException("Cannot open sector metafile");
5724
5725         ServerMapSector *sector = ServerMapSector::deSerialize
5726                         (is, this, p2d, m_sectors);
5727         
5728         sector->differs_from_disk = false;
5729
5730         return sector;
5731 }
5732
5733 bool ServerMap::loadSectorFull(v2s16 p2d)
5734 {
5735         DSTACK(__FUNCTION_NAME);
5736         std::string sectorsubdir = getSectorSubDir(p2d);
5737
5738         MapSector *sector = NULL;
5739
5740         JMutexAutoLock lock(m_sector_mutex);
5741
5742         try{
5743                 sector = loadSectorMeta(sectorsubdir);
5744         }
5745         catch(InvalidFilenameException &e)
5746         {
5747                 return false;
5748         }
5749         catch(FileNotGoodException &e)
5750         {
5751                 return false;
5752         }
5753         catch(std::exception &e)
5754         {
5755                 return false;
5756         }
5757         
5758         /*
5759                 Load blocks
5760         */
5761         std::vector<fs::DirListNode> list2 = fs::GetDirListing
5762                         (m_savedir+"/sectors/"+sectorsubdir);
5763         std::vector<fs::DirListNode>::iterator i2;
5764         for(i2=list2.begin(); i2!=list2.end(); i2++)
5765         {
5766                 // We want files
5767                 if(i2->dir)
5768                         continue;
5769                 try{
5770                         loadBlock(sectorsubdir, i2->name, sector);
5771                 }
5772                 catch(InvalidFilenameException &e)
5773                 {
5774                         // This catches unknown crap in directory
5775                 }
5776         }
5777         return true;
5778 }
5779
5780 void ServerMap::saveBlock(MapBlock *block)
5781 {
5782         DSTACK(__FUNCTION_NAME);
5783         /*
5784                 Dummy blocks are not written
5785         */
5786         if(block->isDummy())
5787         {
5788                 /*v3s16 p = block->getPos();
5789                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
5790                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
5791                 return;
5792         }
5793
5794         // Format used for writing
5795         u8 version = SER_FMT_VER_HIGHEST;
5796         // Get destination
5797         v3s16 p3d = block->getPos();
5798         v2s16 p2d(p3d.X, p3d.Z);
5799         createDir(m_savedir);
5800         createDir(m_savedir+"/sectors");
5801         std::string dir = getSectorDir(p2d);
5802         createDir(dir);
5803         
5804         // Block file is map/sectors/xxxxxxxx/xxxx
5805         char cc[5];
5806         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
5807         std::string fullpath = dir + "/" + cc;
5808         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5809         if(o.good() == false)
5810                 throw FileNotGoodException("Cannot open block data");
5811
5812         /*
5813                 [0] u8 serialization version
5814                 [1] data
5815         */
5816         o.write((char*)&version, 1);
5817         
5818         block->serialize(o, version);
5819
5820         /*
5821                 Versions up from 9 have block objects.
5822         */
5823         if(version >= 9)
5824         {
5825                 block->serializeObjects(o, version);
5826         }
5827         
5828         // We just wrote it to the disk
5829         block->resetChangedFlag();
5830 }
5831
5832 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
5833 {
5834         DSTACK(__FUNCTION_NAME);
5835
5836         try{
5837
5838                 // Block file is map/sectors/xxxxxxxx/xxxx
5839                 std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
5840                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5841                 if(is.good() == false)
5842                         throw FileNotGoodException("Cannot open block file");
5843
5844                 v3s16 p3d = getBlockPos(sectordir, blockfile);
5845                 v2s16 p2d(p3d.X, p3d.Z);
5846                 
5847                 assert(sector->getPos() == p2d);
5848                 
5849                 u8 version = SER_FMT_VER_INVALID;
5850                 is.read((char*)&version, 1);
5851
5852                 if(is.fail())
5853                         throw SerializationError("ServerMap::loadBlock(): Failed"
5854                                         " to read MapBlock version");
5855
5856                 /*u32 block_size = MapBlock::serializedLength(version);
5857                 SharedBuffer<u8> data(block_size);
5858                 is.read((char*)*data, block_size);*/
5859
5860                 // This will always return a sector because we're the server
5861                 //MapSector *sector = emergeSector(p2d);
5862
5863                 MapBlock *block = NULL;
5864                 bool created_new = false;
5865                 try{
5866                         block = sector->getBlockNoCreate(p3d.Y);
5867                 }
5868                 catch(InvalidPositionException &e)
5869                 {
5870                         block = sector->createBlankBlockNoInsert(p3d.Y);
5871                         created_new = true;
5872                 }
5873                 
5874                 // deserialize block data
5875                 block->deSerialize(is, version);
5876                 
5877                 /*
5878                         Versions up from 9 have block objects.
5879                 */
5880                 if(version >= 9)
5881                 {
5882                         block->updateObjects(is, version, NULL, 0);
5883                 }
5884
5885                 if(created_new)
5886                         sector->insertBlock(block);
5887                 
5888                 /*
5889                         Convert old formats to new and save
5890                 */
5891
5892                 // Save old format blocks in new format
5893                 if(version < SER_FMT_VER_HIGHEST)
5894                 {
5895                         saveBlock(block);
5896                 }
5897                 
5898                 // We just loaded it from the disk, so it's up-to-date.
5899                 block->resetChangedFlag();
5900
5901         }
5902         catch(SerializationError &e)
5903         {
5904                 dstream<<"WARNING: Invalid block data on disk "
5905                                 "(SerializationError). Ignoring. "
5906                                 "A new one will be generated."
5907                                 <<std::endl;
5908         }
5909 }
5910
5911 void ServerMap::PrintInfo(std::ostream &out)
5912 {
5913         out<<"ServerMap: ";
5914 }
5915
5916 #ifndef SERVER
5917
5918 /*
5919         ClientMap
5920 */
5921
5922 ClientMap::ClientMap(
5923                 Client *client,
5924                 MapDrawControl &control,
5925                 scene::ISceneNode* parent,
5926                 scene::ISceneManager* mgr,
5927                 s32 id
5928 ):
5929         Map(dout_client),
5930         scene::ISceneNode(parent, mgr, id),
5931         m_client(client),
5932         m_control(control),
5933         m_camera_position(0,0,0),
5934         m_camera_direction(0,0,1)
5935 {
5936         m_camera_mutex.Init();
5937         assert(m_camera_mutex.IsInitialized());
5938         
5939         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
5940                         BS*1000000,BS*1000000,BS*1000000);
5941 }
5942
5943 ClientMap::~ClientMap()
5944 {
5945         /*JMutexAutoLock lock(mesh_mutex);
5946         
5947         if(mesh != NULL)
5948         {
5949                 mesh->drop();
5950                 mesh = NULL;
5951         }*/
5952 }
5953
5954 MapSector * ClientMap::emergeSector(v2s16 p2d)
5955 {
5956         DSTACK(__FUNCTION_NAME);
5957         // Check that it doesn't exist already
5958         try{
5959                 return getSectorNoGenerate(p2d);
5960         }
5961         catch(InvalidPositionException &e)
5962         {
5963         }
5964         
5965         // Create a sector
5966         ClientMapSector *sector = new ClientMapSector(this, p2d);
5967         
5968         {
5969                 JMutexAutoLock lock(m_sector_mutex);
5970                 m_sectors.insert(p2d, sector);
5971         }
5972         
5973         return sector;
5974 }
5975
5976 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
5977 {
5978         DSTACK(__FUNCTION_NAME);
5979         ClientMapSector *sector = NULL;
5980
5981         JMutexAutoLock lock(m_sector_mutex);
5982         
5983         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
5984
5985         if(n != NULL)
5986         {
5987                 sector = (ClientMapSector*)n->getValue();
5988                 assert(sector->getId() == MAPSECTOR_CLIENT);
5989         }
5990         else
5991         {
5992                 sector = new ClientMapSector(this, p2d);
5993                 {
5994                         JMutexAutoLock lock(m_sector_mutex);
5995                         m_sectors.insert(p2d, sector);
5996                 }
5997         }
5998
5999         sector->deSerialize(is);
6000 }
6001
6002 void ClientMap::OnRegisterSceneNode()
6003 {
6004         if(IsVisible)
6005         {
6006                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
6007                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
6008         }
6009
6010         ISceneNode::OnRegisterSceneNode();
6011 }
6012
6013 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
6014 {
6015         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
6016         DSTACK(__FUNCTION_NAME);
6017
6018         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
6019
6020         /*
6021                 Get time for measuring timeout.
6022                 
6023                 Measuring time is very useful for long delays when the
6024                 machine is swapping a lot.
6025         */
6026         int time1 = time(0);
6027
6028         u32 daynight_ratio = m_client->getDayNightRatio();
6029
6030         m_camera_mutex.Lock();
6031         v3f camera_position = m_camera_position;
6032         v3f camera_direction = m_camera_direction;
6033         m_camera_mutex.Unlock();
6034
6035         /*
6036                 Get all blocks and draw all visible ones
6037         */
6038
6039         v3s16 cam_pos_nodes(
6040                         camera_position.X / BS,
6041                         camera_position.Y / BS,
6042                         camera_position.Z / BS);
6043
6044         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
6045
6046         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
6047         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
6048
6049         // Take a fair amount as we will be dropping more out later
6050         v3s16 p_blocks_min(
6051                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
6052                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
6053                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
6054         v3s16 p_blocks_max(
6055                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
6056                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
6057                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
6058         
6059         u32 vertex_count = 0;
6060         
6061         // For limiting number of mesh updates per frame
6062         u32 mesh_update_count = 0;
6063         
6064         u32 blocks_would_have_drawn = 0;
6065         u32 blocks_drawn = 0;
6066
6067         //NOTE: The sectors map should be locked but we're not doing it
6068         // because it'd cause too much delays
6069
6070         int timecheck_counter = 0;
6071         core::map<v2s16, MapSector*>::Iterator si;
6072         si = m_sectors.getIterator();
6073         for(; si.atEnd() == false; si++)
6074         {
6075                 {
6076                         timecheck_counter++;
6077                         if(timecheck_counter > 50)
6078                         {
6079                                 timecheck_counter = 0;
6080                                 int time2 = time(0);
6081                                 if(time2 > time1 + 4)
6082                                 {
6083                                         dstream<<"ClientMap::renderMap(): "
6084                                                 "Rendering takes ages, returning."
6085                                                 <<std::endl;
6086                                         return;
6087                                 }
6088                         }
6089                 }
6090
6091                 MapSector *sector = si.getNode()->getValue();
6092                 v2s16 sp = sector->getPos();
6093                 
6094                 if(m_control.range_all == false)
6095                 {
6096                         if(sp.X < p_blocks_min.X
6097                         || sp.X > p_blocks_max.X
6098                         || sp.Y < p_blocks_min.Z
6099                         || sp.Y > p_blocks_max.Z)
6100                                 continue;
6101                 }
6102
6103                 core::list< MapBlock * > sectorblocks;
6104                 sector->getBlocks(sectorblocks);
6105                 
6106                 /*
6107                         Draw blocks
6108                 */
6109
6110                 core::list< MapBlock * >::Iterator i;
6111                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
6112                 {
6113                         MapBlock *block = *i;
6114
6115                         /*
6116                                 Compare block position to camera position, skip
6117                                 if not seen on display
6118                         */
6119                         
6120                         float range = 100000 * BS;
6121                         if(m_control.range_all == false)
6122                                 range = m_control.wanted_range * BS;
6123                         
6124                         float d = 0.0;
6125                         if(isBlockInSight(block->getPos(), camera_position,
6126                                         camera_direction, range, &d) == false)
6127                         {
6128                                 continue;
6129                         }
6130                         
6131                         // This is ugly
6132                         /*if(m_control.range_all == false &&
6133                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
6134                                 continue;*/
6135
6136 #if 1
6137                         /*
6138                                 Update expired mesh (used for day/night change)
6139                         */
6140
6141                         bool mesh_expired = false;
6142                         
6143                         {
6144                                 JMutexAutoLock lock(block->mesh_mutex);
6145
6146                                 mesh_expired = block->getMeshExpired();
6147
6148                                 // Mesh has not been expired and there is no mesh:
6149                                 // block has no content
6150                                 if(block->mesh == NULL && mesh_expired == false)
6151                                         continue;
6152                         }
6153
6154                         f32 faraway = BS*50;
6155                         //f32 faraway = m_control.wanted_range * BS;
6156                         
6157                         /*
6158                                 This has to be done with the mesh_mutex unlocked
6159                         */
6160                         // Pretty random but this should work somewhat nicely
6161                         if(mesh_expired && (
6162                                         (mesh_update_count < 3
6163                                                 && (d < faraway || mesh_update_count < 2)
6164                                         )
6165                                         || 
6166                                         (m_control.range_all && mesh_update_count < 20)
6167                                 )
6168                         )
6169                         /*if(mesh_expired && mesh_update_count < 6
6170                                         && (d < faraway || mesh_update_count < 3))*/
6171                         {
6172                                 mesh_update_count++;
6173
6174                                 // Mesh has been expired: generate new mesh
6175                                 //block->updateMeshes(daynight_i);
6176                                 block->updateMesh(daynight_ratio);
6177
6178                                 mesh_expired = false;
6179                         }
6180                         
6181                         /*
6182                                 Don't draw an expired mesh that is far away
6183                         */
6184                         /*if(mesh_expired && d >= faraway)
6185                         //if(mesh_expired)
6186                         {
6187                                 // Instead, delete it
6188                                 JMutexAutoLock lock(block->mesh_mutex);
6189                                 if(block->mesh)
6190                                 {
6191                                         block->mesh->drop();
6192                                         block->mesh = NULL;
6193                                 }
6194                                 // And continue to next block
6195                                 continue;
6196                         }*/
6197 #endif
6198                         /*
6199                                 Draw the faces of the block
6200                         */
6201                         {
6202                                 JMutexAutoLock lock(block->mesh_mutex);
6203
6204                                 scene::SMesh *mesh = block->mesh;
6205
6206                                 if(mesh == NULL)
6207                                         continue;
6208                                 
6209                                 blocks_would_have_drawn++;
6210                                 if(blocks_drawn >= m_control.wanted_max_blocks
6211                                                 && m_control.range_all == false
6212                                                 && d > m_control.wanted_min_range * BS)
6213                                         continue;
6214                                 blocks_drawn++;
6215
6216                                 u32 c = mesh->getMeshBufferCount();
6217
6218                                 for(u32 i=0; i<c; i++)
6219                                 {
6220                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
6221                                         const video::SMaterial& material = buf->getMaterial();
6222                                         video::IMaterialRenderer* rnd =
6223                                                         driver->getMaterialRenderer(material.MaterialType);
6224                                         bool transparent = (rnd && rnd->isTransparent());
6225                                         // Render transparent on transparent pass and likewise.
6226                                         if(transparent == is_transparent_pass)
6227                                         {
6228                                                 /*
6229                                                         This *shouldn't* hurt too much because Irrlicht
6230                                                         doesn't change opengl textures if the old
6231                                                         material is set again.
6232                                                 */
6233                                                 driver->setMaterial(buf->getMaterial());
6234                                                 driver->drawMeshBuffer(buf);
6235                                                 vertex_count += buf->getVertexCount();
6236                                         }
6237                                 }
6238                         }
6239                 } // foreach sectorblocks
6240         }
6241         
6242         m_control.blocks_drawn = blocks_drawn;
6243         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
6244
6245         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
6246                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
6247 }
6248
6249 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
6250                 core::map<v3s16, MapBlock*> *affected_blocks)
6251 {
6252         bool changed = false;
6253         /*
6254                 Add it to all blocks touching it
6255         */
6256         v3s16 dirs[7] = {
6257                 v3s16(0,0,0), // this
6258                 v3s16(0,0,1), // back
6259                 v3s16(0,1,0), // top
6260                 v3s16(1,0,0), // right
6261                 v3s16(0,0,-1), // front
6262                 v3s16(0,-1,0), // bottom
6263                 v3s16(-1,0,0), // left
6264         };
6265         for(u16 i=0; i<7; i++)
6266         {
6267                 v3s16 p2 = p + dirs[i];
6268                 // Block position of neighbor (or requested) node
6269                 v3s16 blockpos = getNodeBlockPos(p2);
6270                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
6271                 if(blockref == NULL)
6272                         continue;
6273                 // Relative position of requested node
6274                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
6275                 if(blockref->setTempMod(relpos, mod))
6276                 {
6277                         changed = true;
6278                 }
6279         }
6280         if(changed && affected_blocks!=NULL)
6281         {
6282                 for(u16 i=0; i<7; i++)
6283                 {
6284                         v3s16 p2 = p + dirs[i];
6285                         // Block position of neighbor (or requested) node
6286                         v3s16 blockpos = getNodeBlockPos(p2);
6287                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
6288                         if(blockref == NULL)
6289                                 continue;
6290                         affected_blocks->insert(blockpos, blockref);
6291                 }
6292         }
6293         return changed;
6294 }
6295
6296 bool ClientMap::clearTempMod(v3s16 p,
6297                 core::map<v3s16, MapBlock*> *affected_blocks)
6298 {
6299         bool changed = false;
6300         v3s16 dirs[7] = {
6301                 v3s16(0,0,0), // this
6302                 v3s16(0,0,1), // back
6303                 v3s16(0,1,0), // top
6304                 v3s16(1,0,0), // right
6305                 v3s16(0,0,-1), // front
6306                 v3s16(0,-1,0), // bottom
6307                 v3s16(-1,0,0), // left
6308         };
6309         for(u16 i=0; i<7; i++)
6310         {
6311                 v3s16 p2 = p + dirs[i];
6312                 // Block position of neighbor (or requested) node
6313                 v3s16 blockpos = getNodeBlockPos(p2);
6314                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
6315                 if(blockref == NULL)
6316                         continue;
6317                 // Relative position of requested node
6318                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
6319                 if(blockref->clearTempMod(relpos))
6320                 {
6321                         changed = true;
6322                 }
6323         }
6324         if(changed && affected_blocks!=NULL)
6325         {
6326                 for(u16 i=0; i<7; i++)
6327                 {
6328                         v3s16 p2 = p + dirs[i];
6329                         // Block position of neighbor (or requested) node
6330                         v3s16 blockpos = getNodeBlockPos(p2);
6331                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
6332                         if(blockref == NULL)
6333                                 continue;
6334                         affected_blocks->insert(blockpos, blockref);
6335                 }
6336         }
6337         return changed;
6338 }
6339
6340 void ClientMap::expireMeshes(bool only_daynight_diffed)
6341 {
6342         TimeTaker timer("expireMeshes()");
6343
6344         core::map<v2s16, MapSector*>::Iterator si;
6345         si = m_sectors.getIterator();
6346         for(; si.atEnd() == false; si++)
6347         {
6348                 MapSector *sector = si.getNode()->getValue();
6349
6350                 core::list< MapBlock * > sectorblocks;
6351                 sector->getBlocks(sectorblocks);
6352                 
6353                 core::list< MapBlock * >::Iterator i;
6354                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
6355                 {
6356                         MapBlock *block = *i;
6357
6358                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
6359                         {
6360                                 continue;
6361                         }
6362                         
6363                         {
6364                                 JMutexAutoLock lock(block->mesh_mutex);
6365                                 if(block->mesh != NULL)
6366                                 {
6367                                         /*block->mesh->drop();
6368                                         block->mesh = NULL;*/
6369                                         block->setMeshExpired(true);
6370                                 }
6371                         }
6372                 }
6373         }
6374 }
6375
6376 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
6377 {
6378         assert(mapType() == MAPTYPE_CLIENT);
6379
6380         try{
6381                 v3s16 p = blockpos + v3s16(0,0,0);
6382                 MapBlock *b = getBlockNoCreate(p);
6383                 b->updateMesh(daynight_ratio);
6384         }
6385         catch(InvalidPositionException &e){}
6386         // Leading edge
6387         try{
6388                 v3s16 p = blockpos + v3s16(-1,0,0);
6389                 MapBlock *b = getBlockNoCreate(p);
6390                 b->updateMesh(daynight_ratio);
6391         }
6392         catch(InvalidPositionException &e){}
6393         try{
6394                 v3s16 p = blockpos + v3s16(0,-1,0);
6395                 MapBlock *b = getBlockNoCreate(p);
6396                 b->updateMesh(daynight_ratio);
6397         }
6398         catch(InvalidPositionException &e){}
6399         try{
6400                 v3s16 p = blockpos + v3s16(0,0,-1);
6401                 MapBlock *b = getBlockNoCreate(p);
6402                 b->updateMesh(daynight_ratio);
6403         }
6404         catch(InvalidPositionException &e){}
6405         /*// Trailing edge
6406         try{
6407                 v3s16 p = blockpos + v3s16(1,0,0);
6408                 MapBlock *b = getBlockNoCreate(p);
6409                 b->updateMesh(daynight_ratio);
6410         }
6411         catch(InvalidPositionException &e){}
6412         try{
6413                 v3s16 p = blockpos + v3s16(0,1,0);
6414                 MapBlock *b = getBlockNoCreate(p);
6415                 b->updateMesh(daynight_ratio);
6416         }
6417         catch(InvalidPositionException &e){}
6418         try{
6419                 v3s16 p = blockpos + v3s16(0,0,1);
6420                 MapBlock *b = getBlockNoCreate(p);
6421                 b->updateMesh(daynight_ratio);
6422         }
6423         catch(InvalidPositionException &e){}*/
6424 }
6425
6426 void ClientMap::PrintInfo(std::ostream &out)
6427 {
6428         out<<"ClientMap: ";
6429 }
6430
6431 #endif // !SERVER
6432
6433 /*
6434         MapVoxelManipulator
6435 */
6436
6437 MapVoxelManipulator::MapVoxelManipulator(Map *map)
6438 {
6439         m_map = map;
6440 }
6441
6442 MapVoxelManipulator::~MapVoxelManipulator()
6443 {
6444         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
6445                         <<std::endl;*/
6446 }
6447
6448 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
6449 {
6450         TimeTaker timer1("emerge", &emerge_time);
6451
6452         // Units of these are MapBlocks
6453         v3s16 p_min = getNodeBlockPos(a.MinEdge);
6454         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
6455
6456         VoxelArea block_area_nodes
6457                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6458
6459         addArea(block_area_nodes);
6460
6461         for(s32 z=p_min.Z; z<=p_max.Z; z++)
6462         for(s32 y=p_min.Y; y<=p_max.Y; y++)
6463         for(s32 x=p_min.X; x<=p_max.X; x++)
6464         {
6465                 v3s16 p(x,y,z);
6466                 core::map<v3s16, bool>::Node *n;
6467                 n = m_loaded_blocks.find(p);
6468                 if(n != NULL)
6469                         continue;
6470                 
6471                 bool block_data_inexistent = false;
6472                 try
6473                 {
6474                         TimeTaker timer1("emerge load", &emerge_load_time);
6475
6476                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
6477                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
6478                                         <<" wanted area: ";
6479                         a.print(dstream);
6480                         dstream<<std::endl;*/
6481                         
6482                         MapBlock *block = m_map->getBlockNoCreate(p);
6483                         if(block->isDummy())
6484                                 block_data_inexistent = true;
6485                         else
6486                                 block->copyTo(*this);
6487                 }
6488                 catch(InvalidPositionException &e)
6489                 {
6490                         block_data_inexistent = true;
6491                 }
6492
6493                 if(block_data_inexistent)
6494                 {
6495                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6496                         // Fill with VOXELFLAG_INEXISTENT
6497                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
6498                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
6499                         {
6500                                 s32 i = m_area.index(a.MinEdge.X,y,z);
6501                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
6502                         }
6503                 }
6504
6505                 m_loaded_blocks.insert(p, !block_data_inexistent);
6506         }
6507
6508         //dstream<<"emerge done"<<std::endl;
6509 }
6510
6511 /*
6512         SUGG: Add an option to only update eg. water and air nodes.
6513               This will make it interfere less with important stuff if
6514                   run on background.
6515 */
6516 void MapVoxelManipulator::blitBack
6517                 (core::map<v3s16, MapBlock*> & modified_blocks)
6518 {
6519         if(m_area.getExtent() == v3s16(0,0,0))
6520                 return;
6521         
6522         //TimeTaker timer1("blitBack");
6523
6524         /*dstream<<"blitBack(): m_loaded_blocks.size()="
6525                         <<m_loaded_blocks.size()<<std::endl;*/
6526         
6527         /*
6528                 Initialize block cache
6529         */
6530         v3s16 blockpos_last;
6531         MapBlock *block = NULL;
6532         bool block_checked_in_modified = false;
6533
6534         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
6535         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
6536         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
6537         {
6538                 v3s16 p(x,y,z);
6539
6540                 u8 f = m_flags[m_area.index(p)];
6541                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
6542                         continue;
6543
6544                 MapNode &n = m_data[m_area.index(p)];
6545                         
6546                 v3s16 blockpos = getNodeBlockPos(p);
6547                 
6548                 try
6549                 {
6550                         // Get block
6551                         if(block == NULL || blockpos != blockpos_last){
6552                                 block = m_map->getBlockNoCreate(blockpos);
6553                                 blockpos_last = blockpos;
6554                                 block_checked_in_modified = false;
6555                         }
6556                         
6557                         // Calculate relative position in block
6558                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
6559
6560                         // Don't continue if nothing has changed here
6561                         if(block->getNode(relpos) == n)
6562                                 continue;
6563
6564                         //m_map->setNode(m_area.MinEdge + p, n);
6565                         block->setNode(relpos, n);
6566                         
6567                         /*
6568                                 Make sure block is in modified_blocks
6569                         */
6570                         if(block_checked_in_modified == false)
6571                         {
6572                                 modified_blocks[blockpos] = block;
6573                                 block_checked_in_modified = true;
6574                         }
6575                 }
6576                 catch(InvalidPositionException &e)
6577                 {
6578                 }
6579         }
6580 }
6581
6582 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
6583                 MapVoxelManipulator(map)
6584 {
6585 }
6586
6587 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
6588 {
6589 }
6590
6591 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
6592 {
6593         // Just create the area so that it can be pointed to
6594         VoxelManipulator::emerge(a, caller_id);
6595 }
6596
6597 void ManualMapVoxelManipulator::initialEmerge(
6598                 v3s16 blockpos_min, v3s16 blockpos_max)
6599 {
6600         TimeTaker timer1("initialEmerge", &emerge_time);
6601
6602         // Units of these are MapBlocks
6603         v3s16 p_min = blockpos_min;
6604         v3s16 p_max = blockpos_max;
6605
6606         VoxelArea block_area_nodes
6607                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6608         
6609         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
6610         if(size_MB >= 1)
6611         {
6612                 dstream<<"initialEmerge: area: ";
6613                 block_area_nodes.print(dstream);
6614                 dstream<<" ("<<size_MB<<"MB)";
6615                 dstream<<std::endl;
6616         }
6617
6618         addArea(block_area_nodes);
6619
6620         for(s32 z=p_min.Z; z<=p_max.Z; z++)
6621         for(s32 y=p_min.Y; y<=p_max.Y; y++)
6622         for(s32 x=p_min.X; x<=p_max.X; x++)
6623         {
6624                 v3s16 p(x,y,z);
6625                 core::map<v3s16, bool>::Node *n;
6626                 n = m_loaded_blocks.find(p);
6627                 if(n != NULL)
6628                         continue;
6629                 
6630                 bool block_data_inexistent = false;
6631                 try
6632                 {
6633                         TimeTaker timer1("emerge load", &emerge_load_time);
6634
6635                         MapBlock *block = m_map->getBlockNoCreate(p);
6636                         if(block->isDummy())
6637                                 block_data_inexistent = true;
6638                         else
6639                                 block->copyTo(*this);
6640                 }
6641                 catch(InvalidPositionException &e)
6642                 {
6643                         block_data_inexistent = true;
6644                 }
6645
6646                 if(block_data_inexistent)
6647                 {
6648                         /*
6649                                 Mark area inexistent
6650                         */
6651                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6652                         // Fill with VOXELFLAG_INEXISTENT
6653                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
6654                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
6655                         {
6656                                 s32 i = m_area.index(a.MinEdge.X,y,z);
6657                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
6658                         }
6659                 }
6660
6661                 m_loaded_blocks.insert(p, !block_data_inexistent);
6662         }
6663 }
6664
6665 void ManualMapVoxelManipulator::blitBackAll(
6666                 core::map<v3s16, MapBlock*> * modified_blocks)
6667 {
6668         if(m_area.getExtent() == v3s16(0,0,0))
6669                 return;
6670         
6671         /*
6672                 Copy data of all blocks
6673         */
6674         for(core::map<v3s16, bool>::Iterator
6675                         i = m_loaded_blocks.getIterator();
6676                         i.atEnd() == false; i++)
6677         {
6678                 bool existed = i.getNode()->getValue();
6679                 if(existed == false)
6680                         continue;
6681                 v3s16 p = i.getNode()->getKey();
6682                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
6683                 if(block == NULL)
6684                 {
6685                         dstream<<"WARNING: "<<__FUNCTION_NAME
6686                                         <<": got NULL block "
6687                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
6688                                         <<std::endl;
6689                         continue;
6690                 }
6691
6692                 block->copyFrom(*this);
6693
6694                 if(modified_blocks)
6695                         modified_blocks->insert(p, block);
6696         }
6697 }
6698
6699 //END