]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
Map generation is now properly threaded and doesn't block block placement and other...
[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                 If node lets sunlight through and is under sunlight, it has
945                 sunlight too.
946         */
947         if(node_under_sunlight && content_features(n.d).sunlight_propagates)
948         {
949                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
950         }
951         
952         /*
953                 Set the node on the map
954         */
955         
956         setNode(p, n);
957
958         /*
959                 Add intial metadata
960         */
961
962         NodeMetadata *meta_proto = content_features(n.d).initial_metadata;
963         if(meta_proto)
964         {
965                 NodeMetadata *meta = meta_proto->clone();
966                 setNodeMetadata(p, meta);
967         }
968         
969         /*
970                 If node is under sunlight and doesn't let sunlight through,
971                 take all sunlighted nodes under it and clear light from them
972                 and from where the light has been spread.
973                 TODO: This could be optimized by mass-unlighting instead
974                       of looping
975         */
976         if(node_under_sunlight && !content_features(n.d).sunlight_propagates)
977         {
978                 s16 y = p.Y - 1;
979                 for(;; y--){
980                         //m_dout<<DTIME<<"y="<<y<<std::endl;
981                         v3s16 n2pos(p.X, y, p.Z);
982                         
983                         MapNode n2;
984                         try{
985                                 n2 = getNode(n2pos);
986                         }
987                         catch(InvalidPositionException &e)
988                         {
989                                 break;
990                         }
991
992                         if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
993                         {
994                                 unLightNeighbors(LIGHTBANK_DAY,
995                                                 n2pos, n2.getLight(LIGHTBANK_DAY),
996                                                 light_sources, modified_blocks);
997                                 n2.setLight(LIGHTBANK_DAY, 0);
998                                 setNode(n2pos, n2);
999                         }
1000                         else
1001                                 break;
1002                 }
1003         }
1004
1005         for(s32 i=0; i<2; i++)
1006         {
1007                 enum LightBank bank = banks[i];
1008                 
1009                 /*
1010                         Spread light from all nodes that might be capable of doing so
1011                 */
1012                 spreadLight(bank, light_sources, modified_blocks);
1013         }
1014
1015         /*
1016                 Update information about whether day and night light differ
1017         */
1018         for(core::map<v3s16, MapBlock*>::Iterator
1019                         i = modified_blocks.getIterator();
1020                         i.atEnd() == false; i++)
1021         {
1022                 MapBlock *block = i.getNode()->getValue();
1023                 block->updateDayNightDiff();
1024         }
1025
1026         /*
1027                 Add neighboring liquid nodes and the node itself if it is
1028                 liquid (=water node was added) to transform queue.
1029         */
1030         v3s16 dirs[7] = {
1031                 v3s16(0,0,0), // self
1032                 v3s16(0,0,1), // back
1033                 v3s16(0,1,0), // top
1034                 v3s16(1,0,0), // right
1035                 v3s16(0,0,-1), // front
1036                 v3s16(0,-1,0), // bottom
1037                 v3s16(-1,0,0), // left
1038         };
1039         for(u16 i=0; i<7; i++)
1040         {
1041                 try
1042                 {
1043
1044                 v3s16 p2 = p + dirs[i];
1045                 
1046                 MapNode n2 = getNode(p2);
1047                 if(content_liquid(n2.d))
1048                 {
1049                         m_transforming_liquid.push_back(p2);
1050                 }
1051                 
1052                 }catch(InvalidPositionException &e)
1053                 {
1054                 }
1055         }
1056 }
1057
1058 /*
1059 */
1060 void Map::removeNodeAndUpdate(v3s16 p,
1061                 core::map<v3s16, MapBlock*> &modified_blocks)
1062 {
1063         /*PrintInfo(m_dout);
1064         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1065                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1066         
1067         bool node_under_sunlight = true;
1068         
1069         v3s16 toppos = p + v3s16(0,1,0);
1070
1071         // Node will be replaced with this
1072         u8 replace_material = CONTENT_AIR;
1073         
1074         /*
1075                 If there is a node at top and it doesn't have sunlight,
1076                 there will be no sunlight going down.
1077         */
1078         try{
1079                 MapNode topnode = getNode(toppos);
1080
1081                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1082                         node_under_sunlight = false;
1083         }
1084         catch(InvalidPositionException &e)
1085         {
1086         }
1087
1088         core::map<v3s16, bool> light_sources;
1089
1090         enum LightBank banks[] =
1091         {
1092                 LIGHTBANK_DAY,
1093                 LIGHTBANK_NIGHT
1094         };
1095         for(s32 i=0; i<2; i++)
1096         {
1097                 enum LightBank bank = banks[i];
1098         
1099                 /*
1100                         Unlight neighbors (in case the node is a light source)
1101                 */
1102                 unLightNeighbors(bank, p,
1103                                 getNode(p).getLight(bank),
1104                                 light_sources, modified_blocks);
1105         }
1106
1107         /*
1108                 Remove node metadata
1109         */
1110
1111         removeNodeMetadata(p);
1112
1113         /*
1114                 Remove the node.
1115                 This also clears the lighting.
1116         */
1117
1118         MapNode n;
1119         n.d = replace_material;
1120         setNode(p, n);
1121         
1122         for(s32 i=0; i<2; i++)
1123         {
1124                 enum LightBank bank = banks[i];
1125         
1126                 /*
1127                         Recalculate lighting
1128                 */
1129                 spreadLight(bank, light_sources, modified_blocks);
1130         }
1131
1132         // Add the block of the removed node to modified_blocks
1133         v3s16 blockpos = getNodeBlockPos(p);
1134         MapBlock * block = getBlockNoCreate(blockpos);
1135         assert(block != NULL);
1136         modified_blocks.insert(blockpos, block);
1137
1138         /*
1139                 If the removed node was under sunlight, propagate the
1140                 sunlight down from it and then light all neighbors
1141                 of the propagated blocks.
1142         */
1143         if(node_under_sunlight)
1144         {
1145                 s16 ybottom = propagateSunlight(p, modified_blocks);
1146                 /*m_dout<<DTIME<<"Node was under sunlight. "
1147                                 "Propagating sunlight";
1148                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1149                 s16 y = p.Y;
1150                 for(; y >= ybottom; y--)
1151                 {
1152                         v3s16 p2(p.X, y, p.Z);
1153                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1154                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1155                                         <<std::endl;*/
1156                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1157                 }
1158         }
1159         else
1160         {
1161                 // Set the lighting of this node to 0
1162                 // TODO: Is this needed? Lighting is cleared up there already.
1163                 try{
1164                         MapNode n = getNode(p);
1165                         n.setLight(LIGHTBANK_DAY, 0);
1166                         setNode(p, n);
1167                 }
1168                 catch(InvalidPositionException &e)
1169                 {
1170                         assert(0);
1171                 }
1172         }
1173
1174         for(s32 i=0; i<2; i++)
1175         {
1176                 enum LightBank bank = banks[i];
1177         
1178                 // Get the brightest neighbour node and propagate light from it
1179                 v3s16 n2p = getBrightestNeighbour(bank, p);
1180                 try{
1181                         MapNode n2 = getNode(n2p);
1182                         lightNeighbors(bank, n2p, modified_blocks);
1183                 }
1184                 catch(InvalidPositionException &e)
1185                 {
1186                 }
1187         }
1188
1189         /*
1190                 Update information about whether day and night light differ
1191         */
1192         for(core::map<v3s16, MapBlock*>::Iterator
1193                         i = modified_blocks.getIterator();
1194                         i.atEnd() == false; i++)
1195         {
1196                 MapBlock *block = i.getNode()->getValue();
1197                 block->updateDayNightDiff();
1198         }
1199
1200         /*
1201                 Add neighboring liquid nodes to transform queue.
1202         */
1203         v3s16 dirs[6] = {
1204                 v3s16(0,0,1), // back
1205                 v3s16(0,1,0), // top
1206                 v3s16(1,0,0), // right
1207                 v3s16(0,0,-1), // front
1208                 v3s16(0,-1,0), // bottom
1209                 v3s16(-1,0,0), // left
1210         };
1211         for(u16 i=0; i<6; i++)
1212         {
1213                 try
1214                 {
1215
1216                 v3s16 p2 = p + dirs[i];
1217                 
1218                 MapNode n2 = getNode(p2);
1219                 if(content_liquid(n2.d))
1220                 {
1221                         m_transforming_liquid.push_back(p2);
1222                 }
1223                 
1224                 }catch(InvalidPositionException &e)
1225                 {
1226                 }
1227         }
1228 }
1229
1230 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1231 {
1232         MapEditEvent event;
1233         event.type = MEET_ADDNODE;
1234         event.p = p;
1235         event.n = n;
1236
1237         bool succeeded = true;
1238         try{
1239                 core::map<v3s16, MapBlock*> modified_blocks;
1240                 addNodeAndUpdate(p, n, modified_blocks);
1241
1242                 // Copy modified_blocks to event
1243                 for(core::map<v3s16, MapBlock*>::Iterator
1244                                 i = modified_blocks.getIterator();
1245                                 i.atEnd()==false; i++)
1246                 {
1247                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1248                 }
1249         }
1250         catch(InvalidPositionException &e){
1251                 succeeded = false;
1252         }
1253
1254         dispatchEvent(&event);
1255
1256         return succeeded;
1257 }
1258
1259 bool Map::removeNodeWithEvent(v3s16 p)
1260 {
1261         MapEditEvent event;
1262         event.type = MEET_REMOVENODE;
1263         event.p = p;
1264
1265         bool succeeded = true;
1266         try{
1267                 core::map<v3s16, MapBlock*> modified_blocks;
1268                 removeNodeAndUpdate(p, modified_blocks);
1269
1270                 // Copy modified_blocks to event
1271                 for(core::map<v3s16, MapBlock*>::Iterator
1272                                 i = modified_blocks.getIterator();
1273                                 i.atEnd()==false; i++)
1274                 {
1275                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1276                 }
1277         }
1278         catch(InvalidPositionException &e){
1279                 succeeded = false;
1280         }
1281
1282         dispatchEvent(&event);
1283
1284         return succeeded;
1285 }
1286
1287 bool Map::dayNightDiffed(v3s16 blockpos)
1288 {
1289         try{
1290                 v3s16 p = blockpos + v3s16(0,0,0);
1291                 MapBlock *b = getBlockNoCreate(p);
1292                 if(b->dayNightDiffed())
1293                         return true;
1294         }
1295         catch(InvalidPositionException &e){}
1296         // Leading edges
1297         try{
1298                 v3s16 p = blockpos + v3s16(-1,0,0);
1299                 MapBlock *b = getBlockNoCreate(p);
1300                 if(b->dayNightDiffed())
1301                         return true;
1302         }
1303         catch(InvalidPositionException &e){}
1304         try{
1305                 v3s16 p = blockpos + v3s16(0,-1,0);
1306                 MapBlock *b = getBlockNoCreate(p);
1307                 if(b->dayNightDiffed())
1308                         return true;
1309         }
1310         catch(InvalidPositionException &e){}
1311         try{
1312                 v3s16 p = blockpos + v3s16(0,0,-1);
1313                 MapBlock *b = getBlockNoCreate(p);
1314                 if(b->dayNightDiffed())
1315                         return true;
1316         }
1317         catch(InvalidPositionException &e){}
1318         // Trailing edges
1319         try{
1320                 v3s16 p = blockpos + v3s16(1,0,0);
1321                 MapBlock *b = getBlockNoCreate(p);
1322                 if(b->dayNightDiffed())
1323                         return true;
1324         }
1325         catch(InvalidPositionException &e){}
1326         try{
1327                 v3s16 p = blockpos + v3s16(0,1,0);
1328                 MapBlock *b = getBlockNoCreate(p);
1329                 if(b->dayNightDiffed())
1330                         return true;
1331         }
1332         catch(InvalidPositionException &e){}
1333         try{
1334                 v3s16 p = blockpos + v3s16(0,0,1);
1335                 MapBlock *b = getBlockNoCreate(p);
1336                 if(b->dayNightDiffed())
1337                         return true;
1338         }
1339         catch(InvalidPositionException &e){}
1340
1341         return false;
1342 }
1343
1344 /*
1345         Updates usage timers
1346 */
1347 void Map::timerUpdate(float dtime)
1348 {
1349         JMutexAutoLock lock(m_sector_mutex);
1350
1351         core::map<v2s16, MapSector*>::Iterator si;
1352
1353         si = m_sectors.getIterator();
1354         for(; si.atEnd() == false; si++)
1355         {
1356                 MapSector *sector = si.getNode()->getValue();
1357                 sector->usage_timer += dtime;
1358         }
1359 }
1360
1361 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
1362 {
1363         /*
1364                 Wait for caches to be removed before continuing.
1365                 
1366                 This disables the existence of caches while locked
1367         */
1368         //SharedPtr<JMutexAutoLock> cachelock(m_blockcachelock.waitCaches());
1369
1370         core::list<v2s16>::Iterator j;
1371         for(j=list.begin(); j!=list.end(); j++)
1372         {
1373                 MapSector *sector = m_sectors[*j];
1374                 if(only_blocks)
1375                 {
1376                         sector->deleteBlocks();
1377                 }
1378                 else
1379                 {
1380                         /*
1381                                 If sector is in sector cache, remove it from there
1382                         */
1383                         if(m_sector_cache == sector)
1384                         {
1385                                 m_sector_cache = NULL;
1386                         }
1387                         /*
1388                                 Remove from map and delete
1389                         */
1390                         m_sectors.remove(*j);
1391                         delete sector;
1392                 }
1393         }
1394 }
1395
1396 u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
1397                 core::list<v3s16> *deleted_blocks)
1398 {
1399         JMutexAutoLock lock(m_sector_mutex);
1400
1401         core::list<v2s16> sector_deletion_queue;
1402         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
1403         for(; i.atEnd() == false; i++)
1404         {
1405                 MapSector *sector = i.getNode()->getValue();
1406                 /*
1407                         Delete sector from memory if it hasn't been used in a long time
1408                 */
1409                 if(sector->usage_timer > timeout)
1410                 {
1411                         sector_deletion_queue.push_back(i.getNode()->getKey());
1412                         
1413                         if(deleted_blocks != NULL)
1414                         {
1415                                 // Collect positions of blocks of sector
1416                                 MapSector *sector = i.getNode()->getValue();
1417                                 core::list<MapBlock*> blocks;
1418                                 sector->getBlocks(blocks);
1419                                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1420                                                 i != blocks.end(); i++)
1421                                 {
1422                                         deleted_blocks->push_back((*i)->getPos());
1423                                 }
1424                         }
1425                 }
1426         }
1427         deleteSectors(sector_deletion_queue, only_blocks);
1428         return sector_deletion_queue.getSize();
1429 }
1430
1431 void Map::PrintInfo(std::ostream &out)
1432 {
1433         out<<"Map: ";
1434 }
1435
1436 #define WATER_DROP_BOOST 4
1437
1438 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1439 {
1440         DSTACK(__FUNCTION_NAME);
1441         //TimeTaker timer("transformLiquids()");
1442
1443         u32 loopcount = 0;
1444         u32 initial_size = m_transforming_liquid.size();
1445         
1446         /*if(initial_size != 0)
1447                 dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1448
1449         while(m_transforming_liquid.size() != 0)
1450         {
1451                 /*
1452                         Get a queued transforming liquid node
1453                 */
1454                 v3s16 p0 = m_transforming_liquid.pop_front();
1455
1456                 MapNode n0 = getNode(p0);
1457                 
1458                 // Don't deal with non-liquids
1459                 if(content_liquid(n0.d) == false)
1460                         continue;
1461
1462                 bool is_source = !content_flowing_liquid(n0.d);
1463                 
1464                 u8 liquid_level = 8;
1465                 if(is_source == false)
1466                         liquid_level = n0.param2 & 0x0f;
1467                 
1468                 // Turn possible source into non-source
1469                 u8 nonsource_c = make_liquid_flowing(n0.d);
1470
1471                 /*
1472                         If not source, check that some node flows into this one
1473                         and what is the level of liquid in this one
1474                 */
1475                 if(is_source == false)
1476                 {
1477                         s8 new_liquid_level_max = -1;
1478
1479                         v3s16 dirs_from[5] = {
1480                                 v3s16(0,1,0), // top
1481                                 v3s16(0,0,1), // back
1482                                 v3s16(1,0,0), // right
1483                                 v3s16(0,0,-1), // front
1484                                 v3s16(-1,0,0), // left
1485                         };
1486                         for(u16 i=0; i<5; i++)
1487                         {
1488                                 try
1489                                 {
1490
1491                                 bool from_top = (i==0);
1492
1493                                 v3s16 p2 = p0 + dirs_from[i];
1494                                 MapNode n2 = getNode(p2);
1495
1496                                 if(content_liquid(n2.d))
1497                                 {
1498                                         u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1499                                         // Check that the liquids are the same type
1500                                         if(n2_nonsource_c != nonsource_c)
1501                                         {
1502                                                 dstream<<"WARNING: Not handling: different liquids"
1503                                                                 " collide"<<std::endl;
1504                                                 continue;
1505                                         }
1506                                         bool n2_is_source = !content_flowing_liquid(n2.d);
1507                                         s8 n2_liquid_level = 8;
1508                                         if(n2_is_source == false)
1509                                                 n2_liquid_level = n2.param2 & 0x07;
1510                                         
1511                                         s8 new_liquid_level = -1;
1512                                         if(from_top)
1513                                         {
1514                                                 //new_liquid_level = 7;
1515                                                 if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
1516                                                         new_liquid_level = 7;
1517                                                 else
1518                                                         new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
1519                                         }
1520                                         else if(n2_liquid_level > 0)
1521                                         {
1522                                                 new_liquid_level = n2_liquid_level - 1;
1523                                         }
1524
1525                                         if(new_liquid_level > new_liquid_level_max)
1526                                                 new_liquid_level_max = new_liquid_level;
1527                                 }
1528
1529                                 }catch(InvalidPositionException &e)
1530                                 {
1531                                 }
1532                         } //for
1533                         
1534                         /*
1535                                 If liquid level should be something else, update it and
1536                                 add all the neighboring water nodes to the transform queue.
1537                         */
1538                         if(new_liquid_level_max != liquid_level)
1539                         {
1540                                 if(new_liquid_level_max == -1)
1541                                 {
1542                                         // Remove water alltoghether
1543                                         n0.d = CONTENT_AIR;
1544                                         n0.param2 = 0;
1545                                         setNode(p0, n0);
1546                                 }
1547                                 else
1548                                 {
1549                                         n0.param2 = new_liquid_level_max;
1550                                         setNode(p0, n0);
1551                                 }
1552                                 
1553                                 // Block has been modified
1554                                 {
1555                                         v3s16 blockpos = getNodeBlockPos(p0);
1556                                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1557                                         if(block != NULL)
1558                                                 modified_blocks.insert(blockpos, block);
1559                                 }
1560                                 
1561                                 /*
1562                                         Add neighboring non-source liquid nodes to transform queue.
1563                                 */
1564                                 v3s16 dirs[6] = {
1565                                         v3s16(0,0,1), // back
1566                                         v3s16(0,1,0), // top
1567                                         v3s16(1,0,0), // right
1568                                         v3s16(0,0,-1), // front
1569                                         v3s16(0,-1,0), // bottom
1570                                         v3s16(-1,0,0), // left
1571                                 };
1572                                 for(u16 i=0; i<6; i++)
1573                                 {
1574                                         try
1575                                         {
1576
1577                                         v3s16 p2 = p0 + dirs[i];
1578                                         
1579                                         MapNode n2 = getNode(p2);
1580                                         if(content_flowing_liquid(n2.d))
1581                                         {
1582                                                 m_transforming_liquid.push_back(p2);
1583                                         }
1584                                         
1585                                         }catch(InvalidPositionException &e)
1586                                         {
1587                                         }
1588                                 }
1589                         }
1590                 }
1591                 
1592                 // Get a new one from queue if the node has turned into non-water
1593                 if(content_liquid(n0.d) == false)
1594                         continue;
1595
1596                 /*
1597                         Flow water from this node
1598                 */
1599                 v3s16 dirs_to[5] = {
1600                         v3s16(0,-1,0), // bottom
1601                         v3s16(0,0,1), // back
1602                         v3s16(1,0,0), // right
1603                         v3s16(0,0,-1), // front
1604                         v3s16(-1,0,0), // left
1605                 };
1606                 for(u16 i=0; i<5; i++)
1607                 {
1608                         try
1609                         {
1610
1611                         bool to_bottom = (i == 0);
1612
1613                         // If liquid is at lowest possible height, it's not going
1614                         // anywhere except down
1615                         if(liquid_level == 0 && to_bottom == false)
1616                                 continue;
1617                         
1618                         u8 liquid_next_level = 0;
1619                         // If going to bottom
1620                         if(to_bottom)
1621                         {
1622                                 //liquid_next_level = 7;
1623                                 if(liquid_level >= 7 - WATER_DROP_BOOST)
1624                                         liquid_next_level = 7;
1625                                 else
1626                                         liquid_next_level = liquid_level + WATER_DROP_BOOST;
1627                         }
1628                         else
1629                                 liquid_next_level = liquid_level - 1;
1630
1631                         bool n2_changed = false;
1632                         bool flowed = false;
1633                         
1634                         v3s16 p2 = p0 + dirs_to[i];
1635
1636                         MapNode n2 = getNode(p2);
1637                         //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
1638
1639                         if(content_liquid(n2.d))
1640                         {
1641                                 u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1642                                 // Check that the liquids are the same type
1643                                 if(n2_nonsource_c != nonsource_c)
1644                                 {
1645                                         dstream<<"WARNING: Not handling: different liquids"
1646                                                         " collide"<<std::endl;
1647                                         continue;
1648                                 }
1649                                 bool n2_is_source = !content_flowing_liquid(n2.d);
1650                                 u8 n2_liquid_level = 8;
1651                                 if(n2_is_source == false)
1652                                         n2_liquid_level = n2.param2 & 0x07;
1653                                 
1654                                 if(to_bottom)
1655                                 {
1656                                         flowed = true;
1657                                 }
1658
1659                                 if(n2_is_source)
1660                                 {
1661                                         // Just flow into the source, nothing changes.
1662                                         // n2_changed is not set because destination didn't change
1663                                         flowed = true;
1664                                 }
1665                                 else
1666                                 {
1667                                         if(liquid_next_level > liquid_level)
1668                                         {
1669                                                 n2.param2 = liquid_next_level;
1670                                                 setNode(p2, n2);
1671
1672                                                 n2_changed = true;
1673                                                 flowed = true;
1674                                         }
1675                                 }
1676                         }
1677                         else if(n2.d == CONTENT_AIR)
1678                         {
1679                                 n2.d = nonsource_c;
1680                                 n2.param2 = liquid_next_level;
1681                                 setNode(p2, n2);
1682                                 
1683                                 n2_changed = true;
1684                                 flowed = true;
1685                         }
1686                         
1687                         //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl;
1688
1689                         if(n2_changed)
1690                         {
1691                                 m_transforming_liquid.push_back(p2);
1692                                 
1693                                 v3s16 blockpos = getNodeBlockPos(p2);
1694                                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1695                                 if(block != NULL)
1696                                         modified_blocks.insert(blockpos, block);
1697                         }
1698                         
1699                         // If n2_changed to bottom, don't flow anywhere else
1700                         if(to_bottom && flowed && !is_source)
1701                                 break;
1702                                 
1703                         }catch(InvalidPositionException &e)
1704                         {
1705                         }
1706                 }
1707
1708                 loopcount++;
1709                 //if(loopcount >= 100000)
1710                 if(loopcount >= initial_size * 1)
1711                         break;
1712         }
1713         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1714 }
1715
1716 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1717 {
1718         v3s16 blockpos = getNodeBlockPos(p);
1719         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1720         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1721         if(block == NULL)
1722         {
1723                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1724                                 <<std::endl;
1725                 return NULL;
1726         }
1727         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1728         return meta;
1729 }
1730
1731 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1732 {
1733         v3s16 blockpos = getNodeBlockPos(p);
1734         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1735         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1736         if(block == NULL)
1737         {
1738                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1739                                 <<std::endl;
1740                 return;
1741         }
1742         block->m_node_metadata.set(p_rel, meta);
1743 }
1744
1745 void Map::removeNodeMetadata(v3s16 p)
1746 {
1747         v3s16 blockpos = getNodeBlockPos(p);
1748         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1749         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1750         if(block == NULL)
1751         {
1752                 dstream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1753                                 <<std::endl;
1754                 return;
1755         }
1756         block->m_node_metadata.remove(p_rel);
1757 }
1758
1759 void Map::nodeMetadataStep(float dtime,
1760                 core::map<v3s16, MapBlock*> &changed_blocks)
1761 {
1762         /*
1763                 NOTE:
1764                 Currently there is no way to ensure that all the necessary
1765                 blocks are loaded when this is run. (They might get unloaded)
1766                 NOTE: ^- Actually, that might not be so. In a quick test it
1767                 reloaded a block with a furnace when I walked back to it from
1768                 a distance.
1769         */
1770         core::map<v2s16, MapSector*>::Iterator si;
1771         si = m_sectors.getIterator();
1772         for(; si.atEnd() == false; si++)
1773         {
1774                 MapSector *sector = si.getNode()->getValue();
1775                 core::list< MapBlock * > sectorblocks;
1776                 sector->getBlocks(sectorblocks);
1777                 core::list< MapBlock * >::Iterator i;
1778                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1779                 {
1780                         MapBlock *block = *i;
1781                         bool changed = block->m_node_metadata.step(dtime);
1782                         if(changed)
1783                                 changed_blocks[block->getPos()] = block;
1784                 }
1785         }
1786 }
1787
1788 /*
1789         ServerMap
1790 */
1791
1792 ServerMap::ServerMap(std::string savedir):
1793         Map(dout_server),
1794         m_seed(0)
1795 {
1796         
1797         //m_chunksize = 64;
1798         //m_chunksize = 16; // Too slow
1799         m_chunksize = 8; // Takes a few seconds
1800         //m_chunksize = 4;
1801         //m_chunksize = 2;
1802         
1803         // TODO: Save to and load from a file
1804         m_seed = (((u64)(myrand()%0xffff)<<0)
1805                         + ((u64)(myrand()%0xffff)<<16)
1806                         + ((u64)(myrand()%0xffff)<<32)
1807                         + ((u64)(myrand()%0xffff)<<48));
1808
1809         /*
1810                 Experimental and debug stuff
1811         */
1812         
1813         {
1814         }
1815         
1816         /*
1817                 Try to load map; if not found, create a new one.
1818         */
1819
1820         m_savedir = savedir;
1821         m_map_saving_enabled = false;
1822         
1823         try
1824         {
1825                 // If directory exists, check contents and load if possible
1826                 if(fs::PathExists(m_savedir))
1827                 {
1828                         // If directory is empty, it is safe to save into it.
1829                         if(fs::GetDirListing(m_savedir).size() == 0)
1830                         {
1831                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1832                                                 <<std::endl;
1833                                 m_map_saving_enabled = true;
1834                         }
1835                         else
1836                         {
1837                                 // Load map metadata (seed, chunksize)
1838                                 loadMapMeta();
1839                                 
1840                                 // Load chunk metadata
1841                                 loadChunkMeta();
1842                         
1843                                 /*// Load sector (0,0) and throw and exception on fail
1844                                 if(loadSectorFull(v2s16(0,0)) == false)
1845                                         throw LoadError("Failed to load sector (0,0)");*/
1846
1847                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1848                                                 "metadata and sector (0,0) from "<<savedir<<
1849                                                 ", assuming valid save directory."
1850                                                 <<std::endl;*/
1851
1852                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1853                                                 <<"and chunk metadata from "<<savedir
1854                                                 <<", assuming valid save directory."
1855                                                 <<std::endl;
1856
1857                                 m_map_saving_enabled = true;
1858                                 // Map loaded, not creating new one
1859                                 return;
1860                         }
1861                 }
1862                 // If directory doesn't exist, it is safe to save to it
1863                 else{
1864                         m_map_saving_enabled = true;
1865                 }
1866         }
1867         catch(std::exception &e)
1868         {
1869                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1870                                 <<", exception: "<<e.what()<<std::endl;
1871                 dstream<<"Please remove the map or fix it."<<std::endl;
1872                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1873         }
1874
1875         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1876         
1877         // Create zero sector
1878         emergeSector(v2s16(0,0));
1879
1880         // Initially write whole map
1881         save(false);
1882 }
1883
1884 ServerMap::~ServerMap()
1885 {
1886         try
1887         {
1888                 if(m_map_saving_enabled)
1889                 {
1890                         //save(false);
1891                         // Save only changed parts
1892                         save(true);
1893                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1894                 }
1895                 else
1896                 {
1897                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1898                 }
1899         }
1900         catch(std::exception &e)
1901         {
1902                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1903                                 <<", exception: "<<e.what()<<std::endl;
1904         }
1905         
1906         /*
1907                 Free all MapChunks
1908         */
1909         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1910         for(; i.atEnd() == false; i++)
1911         {
1912                 MapChunk *chunk = i.getNode()->getValue();
1913                 delete chunk;
1914         }
1915 }
1916
1917 /*
1918         Some helper functions for the map generator
1919 */
1920
1921 s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
1922 {
1923         v3s16 em = vmanip.m_area.getExtent();
1924         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1925         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1926         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1927         s16 y;
1928         for(y=y_nodes_max; y>=y_nodes_min; y--)
1929         {
1930                 MapNode &n = vmanip.m_data[i];
1931                 if(content_walkable(n.d))
1932                         break;
1933                         
1934                 vmanip.m_area.add_y(em, i, -1);
1935         }
1936         if(y >= y_nodes_min)
1937                 return y;
1938         else
1939                 return y_nodes_min;
1940 }
1941
1942 s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
1943 {
1944         v3s16 em = vmanip.m_area.getExtent();
1945         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1946         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1947         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1948         s16 y;
1949         for(y=y_nodes_max; y>=y_nodes_min; y--)
1950         {
1951                 MapNode &n = vmanip.m_data[i];
1952                 if(content_walkable(n.d)
1953                                 && n.d != CONTENT_TREE
1954                                 && n.d != CONTENT_LEAVES)
1955                         break;
1956                         
1957                 vmanip.m_area.add_y(em, i, -1);
1958         }
1959         if(y >= y_nodes_min)
1960                 return y;
1961         else
1962                 return y_nodes_min;
1963 }
1964
1965 void make_tree(VoxelManipulator &vmanip, v3s16 p0)
1966 {
1967         MapNode treenode(CONTENT_TREE);
1968         MapNode leavesnode(CONTENT_LEAVES);
1969
1970         s16 trunk_h = myrand_range(3, 6);
1971         v3s16 p1 = p0;
1972         for(s16 ii=0; ii<trunk_h; ii++)
1973         {
1974                 if(vmanip.m_area.contains(p1))
1975                         vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
1976                 p1.Y++;
1977         }
1978         
1979         // p1 is now the last piece of the trunk
1980         p1.Y -= 1;
1981
1982         VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
1983         //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
1984         Buffer<u8> leaves_d(leaves_a.getVolume());
1985         for(s32 i=0; i<leaves_a.getVolume(); i++)
1986                 leaves_d[i] = 0;
1987         
1988         // Force leaves at near the end of the trunk
1989         {
1990                 s16 d = 1;
1991                 for(s16 z=-d; z<=d; z++)
1992                 for(s16 y=-d; y<=d; y++)
1993                 for(s16 x=-d; x<=d; x++)
1994                 {
1995                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
1996                 }
1997         }
1998         
1999         // Add leaves randomly
2000         for(u32 iii=0; iii<7; iii++)
2001         {
2002                 s16 d = 1;
2003
2004                 v3s16 p(
2005                         myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
2006                         myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
2007                         myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
2008                 );
2009                 
2010                 for(s16 z=0; z<=d; z++)
2011                 for(s16 y=0; y<=d; y++)
2012                 for(s16 x=0; x<=d; x++)
2013                 {
2014                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
2015                 }
2016         }
2017         
2018         // Blit leaves to vmanip
2019         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
2020         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
2021         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
2022         {
2023                 v3s16 p(x,y,z);
2024                 p += p1;
2025                 if(vmanip.m_area.contains(p) == false)
2026                         continue;
2027                 u32 vi = vmanip.m_area.index(p);
2028                 if(vmanip.m_data[vi].d != CONTENT_AIR)
2029                         continue;
2030                 u32 i = leaves_a.index(x,y,z);
2031                 if(leaves_d[i] == 1)
2032                         vmanip.m_data[vi] = leavesnode;
2033         }
2034 }
2035
2036 /*
2037         Noise functions. Make sure seed is mangled differently in each one.
2038 */
2039
2040 // Amount of trees per area in nodes
2041 double tree_amount_2d(u64 seed, v2s16 p)
2042 {
2043         double noise = noise2d_perlin(
2044                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
2045                         seed+2, 5, 0.66);
2046         double zeroval = -0.3;
2047         if(noise < zeroval)
2048                 return 0;
2049         else
2050                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
2051 }
2052
2053 #define AVERAGE_MUD_AMOUNT 4
2054
2055 double base_rock_level_2d(u64 seed, v2s16 p)
2056 {
2057         // The base ground level
2058         double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
2059                         + 25. * noise2d_perlin(
2060                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2061                         (seed>>32)+654879876, 6, 0.6);
2062         
2063         /*// A bit hillier one
2064         double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
2065                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2066                         (seed>>27)+90340, 6, 0.69);
2067         if(base2 > base)
2068                 base = base2;*/
2069 #if 1
2070         // Higher ground level
2071         double higher = (double)WATER_LEVEL + 25. + 45. * noise2d_perlin(
2072                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2073                         seed+85039, 5, 0.69);
2074         //higher = 30; // For debugging
2075
2076         // Limit higher to at least base
2077         if(higher < base)
2078                 higher = base;
2079                 
2080         // Steepness factor of cliffs
2081         double b = 1.0 + 1.0 * noise2d_perlin(
2082                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2083                         seed-932, 7, 0.7);
2084         b = rangelim(b, 0.0, 1000.0);
2085         b = pow(b, 5);
2086         b *= 7;
2087         b = rangelim(b, 3.0, 1000.0);
2088         //dstream<<"b="<<b<<std::endl;
2089         //double b = 20;
2090
2091         // Offset to more low
2092         double a_off = -0.2;
2093         // High/low selector
2094         /*double a = 0.5 + b * (a_off + noise2d_perlin(
2095                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2096                         seed-359, 6, 0.7));*/
2097         double a = (double)0.5 + b * (a_off + noise2d_perlin(
2098                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2099                         seed-359, 5, 0.60));
2100         // Limit
2101         a = rangelim(a, 0.0, 1.0);
2102
2103         //dstream<<"a="<<a<<std::endl;
2104         
2105         double h = base*(1.0-a) + higher*a;
2106 #else
2107         double h = base;
2108 #endif
2109         return h;
2110 }
2111
2112 /*
2113         Adds random objects to block, depending on the content of the block
2114 */
2115 void addRandomObjects(MapBlock *block)
2116 {
2117         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2118         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2119         {
2120                 bool last_node_walkable = false;
2121                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2122                 {
2123                         v3s16 p(x0,y0,z0);
2124                         MapNode n = block->getNodeNoEx(p);
2125                         if(n.d == CONTENT_IGNORE)
2126                                 continue;
2127                         if(content_features(n.d).liquid_type != LIQUID_NONE)
2128                                 continue;
2129                         if(content_features(n.d).walkable)
2130                         {
2131                                 last_node_walkable = true;
2132                                 continue;
2133                         }
2134                         if(last_node_walkable)
2135                         {
2136                                 // If block contains light information
2137                                 if(content_features(n.d).param_type == CPT_LIGHT)
2138                                 {
2139                                         if(n.getLight(LIGHTBANK_DAY) <= 3)
2140                                         {
2141                                                 if(myrand() % 300 == 0)
2142                                                 {
2143                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
2144                                                         pos_f.Y -= BS*0.4;
2145                                                         ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
2146                                                         std::string data = obj->getStaticData();
2147                                                         StaticObject s_obj(obj->getType(),
2148                                                                         obj->getBasePosition(), data);
2149                                                         // Add some
2150                                                         block->m_static_objects.insert(0, s_obj);
2151                                                         block->m_static_objects.insert(0, s_obj);
2152                                                         block->m_static_objects.insert(0, s_obj);
2153                                                         block->m_static_objects.insert(0, s_obj);
2154                                                         block->m_static_objects.insert(0, s_obj);
2155                                                         block->m_static_objects.insert(0, s_obj);
2156                                                         delete obj;
2157                                                 }
2158                                         }
2159                                 }
2160                         }
2161                         last_node_walkable = false;
2162                 }
2163         }
2164         block->setChangedFlag();
2165 }
2166
2167 #define VMANIP_FLAG_DUNGEON VOXELFLAG_CHECKED1
2168
2169 /*
2170         This is the main map generation method
2171 */
2172
2173 void makeChunk(ChunkMakeData *data)
2174 {
2175         s16 y_nodes_min = data->y_blocks_min * MAP_BLOCKSIZE;
2176         s16 y_nodes_max = data->y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
2177         s16 h_blocks = data->y_blocks_max - data->y_blocks_min + 1;
2178         u32 relative_volume = (u32)data->sectorpos_base_size*MAP_BLOCKSIZE
2179                         *(u32)data->sectorpos_base_size*MAP_BLOCKSIZE
2180                         *(u32)h_blocks*MAP_BLOCKSIZE;
2181         v3s16 bigarea_blocks_min(
2182                 data->sectorpos_bigbase.X,
2183                 data->y_blocks_min,
2184                 data->sectorpos_bigbase.Y
2185         );
2186         v3s16 bigarea_blocks_max(
2187                 data->sectorpos_bigbase.X + data->sectorpos_bigbase_size - 1,
2188                 data->y_blocks_max,
2189                 data->sectorpos_bigbase.Y + data->sectorpos_bigbase_size - 1
2190         );
2191         s16 lighting_min_d = 0-data->max_spread_amount;
2192         s16 lighting_max_d = data->sectorpos_base_size*MAP_BLOCKSIZE
2193                         + data->max_spread_amount-1;
2194
2195         // Clear all flags
2196         data->vmanip.clearFlag(0xff);
2197
2198         TimeTaker timer_generate("makeChunk() generate");
2199
2200         // Maximum height of the stone surface and obstacles.
2201         // This is used to disable cave generation from going too high.
2202         s16 stone_surface_max_y = 0;
2203
2204         /*
2205                 Generate general ground level to full area
2206         */
2207         
2208         {
2209         // 22ms @cs=8
2210         //TimeTaker timer1("ground level");
2211
2212         for(s16 x=0; x<data->sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
2213         for(s16 z=0; z<data->sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
2214         {
2215                 // Node position
2216                 v2s16 p2d = data->sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2217                 
2218                 /*
2219                         Skip of already generated
2220                 */
2221                 /*{
2222                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2223                         if(data->vmanip.m_data[data->vmanip.m_area.index(p)].d != CONTENT_AIR)
2224                                 continue;
2225                 }*/
2226
2227                 // Ground height at this point
2228                 float surface_y_f = 0.0;
2229
2230                 // Use perlin noise for ground height
2231                 surface_y_f = base_rock_level_2d(data->seed, p2d);
2232                 
2233                 /*// Experimental stuff
2234                 {
2235                         float a = highlands_level_2d(data->seed, p2d);
2236                         if(a > surface_y_f)
2237                                 surface_y_f = a;
2238                 }*/
2239
2240                 // Convert to integer
2241                 s16 surface_y = (s16)surface_y_f;
2242                 
2243                 // Log it
2244                 if(surface_y > stone_surface_max_y)
2245                         stone_surface_max_y = surface_y;
2246
2247                 /*
2248                         Fill ground with stone
2249                 */
2250                 {
2251                         // Use fast index incrementing
2252                         v3s16 em = data->vmanip.m_area.getExtent();
2253                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
2254                         for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++)
2255                         {
2256                                 // Skip if already generated.
2257                                 // This is done here because there might be a cave at
2258                                 // any point in ground, which could look like it
2259                                 // wasn't generated.
2260                                 if(data->vmanip.m_data[i].d != CONTENT_AIR)
2261                                         break;
2262
2263                                 data->vmanip.m_data[i].d = CONTENT_STONE;
2264
2265                                 data->vmanip.m_area.add_y(em, i, 1);
2266                         }
2267                 }
2268         }
2269         
2270         }//timer1
2271
2272         /*
2273                 Randomize some parameters
2274         */
2275         
2276         //s32 stone_obstacle_count = 0;
2277         /*s32 stone_obstacle_count =
2278                         rangelim((1.0+noise2d(data->seed+897,
2279                         data->sectorpos_base.X, data->sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2280         
2281         //s16 stone_obstacle_max_height = 0;
2282         /*s16 stone_obstacle_max_height =
2283                         rangelim((1.0+noise2d(data->seed+5902,
2284                         data->sectorpos_base.X, data->sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2285
2286         /*
2287                 Loop this part, it will make stuff look older and newer nicely
2288         */
2289         //for(u32 i_age=0; i_age<1; i_age++)
2290         for(u32 i_age=0; i_age<2; i_age++)
2291         { // Aging loop
2292         /******************************
2293                 BEGINNING OF AGING LOOP
2294         ******************************/
2295
2296         {
2297         // 24ms @cs=8
2298         //TimeTaker timer1("caves");
2299
2300         /*
2301                 Make caves
2302         */
2303         u32 caves_count = relative_volume / 400000;
2304         u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
2305         if(stone_surface_max_y < WATER_LEVEL)
2306                 bruises_count = 0;
2307         /*u32 caves_count = 0;
2308         u32 bruises_count = 0;*/
2309         for(u32 jj=0; jj<caves_count+bruises_count; jj++)
2310         {
2311                 s16 min_tunnel_diameter = 3;
2312                 s16 max_tunnel_diameter = 5;
2313                 u16 tunnel_routepoints = 20;
2314                 
2315                 v3f main_direction(0,0,0);
2316
2317                 bool bruise_surface = (jj > caves_count);
2318
2319                 if(bruise_surface)
2320                 {
2321                         min_tunnel_diameter = 5;
2322                         max_tunnel_diameter = myrand_range(10, 20);
2323                         /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
2324                         max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
2325                         
2326                         /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(data->seed+42,
2327                                         data->sectorpos_base.X, data->sectorpos_base.Y)), 0, 15);*/
2328
2329                         tunnel_routepoints = 5;
2330                 }
2331                 else
2332                 {
2333                 }
2334
2335                 // Allowed route area size in nodes
2336                 v3s16 ar(
2337                         data->sectorpos_base_size*MAP_BLOCKSIZE,
2338                         h_blocks*MAP_BLOCKSIZE,
2339                         data->sectorpos_base_size*MAP_BLOCKSIZE
2340                 );
2341
2342                 // Area starting point in nodes
2343                 v3s16 of(
2344                         data->sectorpos_base.X*MAP_BLOCKSIZE,
2345                         data->y_blocks_min*MAP_BLOCKSIZE,
2346                         data->sectorpos_base.Y*MAP_BLOCKSIZE
2347                 );
2348
2349                 // Allow a bit more
2350                 //(this should be more than the maximum radius of the tunnel)
2351                 //s16 insure = 5; // Didn't work with max_d = 20
2352                 s16 insure = 10;
2353                 s16 more = data->max_spread_amount - max_tunnel_diameter/2 - insure;
2354                 ar += v3s16(1,0,1) * more * 2;
2355                 of -= v3s16(1,0,1) * more;
2356                 
2357                 s16 route_y_min = 0;
2358                 // Allow half a diameter + 7 over stone surface
2359                 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
2360
2361                 /*// If caves, don't go through surface too often
2362                 if(bruise_surface == false)
2363                         route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
2364
2365                 // Limit maximum to area
2366                 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
2367
2368                 if(bruise_surface)
2369                 {
2370                         /*// Minimum is at y=0
2371                         route_y_min = -of.Y - 0;*/
2372                         // Minimum is at y=max_tunnel_diameter/4
2373                         //route_y_min = -of.Y + max_tunnel_diameter/4;
2374                         //s16 min = -of.Y + max_tunnel_diameter/4;
2375                         s16 min = -of.Y + 0;
2376                         route_y_min = myrand_range(min, min + max_tunnel_diameter);
2377                         route_y_min = rangelim(route_y_min, 0, route_y_max);
2378                 }
2379
2380                 /*dstream<<"route_y_min = "<<route_y_min
2381                                 <<", route_y_max = "<<route_y_max<<std::endl;*/
2382
2383                 s16 route_start_y_min = route_y_min;
2384                 s16 route_start_y_max = route_y_max;
2385
2386                 // Start every 2nd cave from surface
2387                 bool coming_from_surface = (jj % 2 == 0 && bruise_surface == false);
2388
2389                 if(coming_from_surface)
2390                 {
2391                         route_start_y_min = -of.Y + stone_surface_max_y + 10;
2392                 }
2393                 
2394                 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
2395                 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
2396
2397                 // Randomize starting position
2398                 v3f orp(
2399                         (float)(myrand()%ar.X)+0.5,
2400                         (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
2401                         (float)(myrand()%ar.Z)+0.5
2402                 );
2403
2404                 MapNode airnode(CONTENT_AIR);
2405                 
2406                 /*
2407                         Generate some tunnel starting from orp
2408                 */
2409                 
2410                 for(u16 j=0; j<tunnel_routepoints; j++)
2411                 {
2412                         if(j%7==0 && bruise_surface == false)
2413                         {
2414                                 main_direction = v3f(
2415                                         ((float)(myrand()%20)-(float)10)/10,
2416                                         ((float)(myrand()%20)-(float)10)/30,
2417                                         ((float)(myrand()%20)-(float)10)/10
2418                                 );
2419                                 main_direction *= (float)myrand_range(1, 3);
2420                         }
2421
2422                         // Randomize size
2423                         s16 min_d = min_tunnel_diameter;
2424                         s16 max_d = max_tunnel_diameter;
2425                         s16 rs = myrand_range(min_d, max_d);
2426                         
2427                         v3s16 maxlen;
2428                         if(bruise_surface)
2429                         {
2430                                 maxlen = v3s16(rs*7,rs*7,rs*7);
2431                         }
2432                         else
2433                         {
2434                                 maxlen = v3s16(rs*4, myrand_range(1, rs*3), rs*4);
2435                         }
2436
2437                         v3f vec;
2438                         
2439                         if(coming_from_surface && j < 3)
2440                         {
2441                                 vec = v3f(
2442                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2443                                         (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
2444                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2445                                 );
2446                         }
2447                         else
2448                         {
2449                                 vec = v3f(
2450                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2451                                         (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
2452                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2453                                 );
2454                         }
2455                         
2456                         vec += main_direction;
2457
2458                         v3f rp = orp + vec;
2459                         if(rp.X < 0)
2460                                 rp.X = 0;
2461                         else if(rp.X >= ar.X)
2462                                 rp.X = ar.X-1;
2463                         if(rp.Y < route_y_min)
2464                                 rp.Y = route_y_min;
2465                         else if(rp.Y >= route_y_max)
2466                                 rp.Y = route_y_max-1;
2467                         if(rp.Z < 0)
2468                                 rp.Z = 0;
2469                         else if(rp.Z >= ar.Z)
2470                                 rp.Z = ar.Z-1;
2471                         vec = rp - orp;
2472
2473                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
2474                         {
2475                                 v3f fp = orp + vec * f;
2476                                 v3s16 cp(fp.X, fp.Y, fp.Z);
2477
2478                                 s16 d0 = -rs/2;
2479                                 s16 d1 = d0 + rs - 1;
2480                                 for(s16 z0=d0; z0<=d1; z0++)
2481                                 {
2482                                         //s16 si = rs - MYMAX(0, abs(z0)-rs/4);
2483                                         s16 si = rs - MYMAX(0, abs(z0)-rs/7);
2484                                         for(s16 x0=-si; x0<=si-1; x0++)
2485                                         {
2486                                                 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
2487                                                 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
2488                                                 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
2489                                                 //s16 si2 = rs - abs(x0);
2490                                                 for(s16 y0=-si2+1+2; y0<=si2-1; y0++)
2491                                                 {
2492                                                         s16 z = cp.Z + z0;
2493                                                         s16 y = cp.Y + y0;
2494                                                         s16 x = cp.X + x0;
2495                                                         v3s16 p(x,y,z);
2496                                                         /*if(isInArea(p, ar) == false)
2497                                                                 continue;*/
2498                                                         // Check only height
2499                                                         if(y < 0 || y >= ar.Y)
2500                                                                 continue;
2501                                                         p += of;
2502                                                         
2503                                                         //assert(data->vmanip.m_area.contains(p));
2504                                                         if(data->vmanip.m_area.contains(p) == false)
2505                                                         {
2506                                                                 dstream<<"WARNING: "<<__FUNCTION_NAME
2507                                                                                 <<":"<<__LINE__<<": "
2508                                                                                 <<"point not in area"
2509                                                                                 <<std::endl;
2510                                                                 continue;
2511                                                         }
2512                                                         
2513                                                         // Just set it to air, it will be changed to
2514                                                         // water afterwards
2515                                                         u32 i = data->vmanip.m_area.index(p);
2516                                                         data->vmanip.m_data[i] = airnode;
2517
2518                                                         if(bruise_surface == false)
2519                                                         {
2520                                                                 // Set tunnel flag
2521                                                                 data->vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON;
2522                                                         }
2523                                                 }
2524                                         }
2525                                 }
2526                         }
2527
2528                         orp = rp;
2529                 }
2530         
2531         }
2532
2533         }//timer1
2534         {
2535         // 46ms @cs=8
2536         //TimeTaker timer1("ore veins");
2537
2538         /*
2539                 Make ore veins
2540         */
2541         for(u32 jj=0; jj<relative_volume/1000; jj++)
2542         {
2543                 s16 max_vein_diameter = 3;
2544
2545                 // Allowed route area size in nodes
2546                 v3s16 ar(
2547                         data->sectorpos_base_size*MAP_BLOCKSIZE,
2548                         h_blocks*MAP_BLOCKSIZE,
2549                         data->sectorpos_base_size*MAP_BLOCKSIZE
2550                 );
2551
2552                 // Area starting point in nodes
2553                 v3s16 of(
2554                         data->sectorpos_base.X*MAP_BLOCKSIZE,
2555                         data->y_blocks_min*MAP_BLOCKSIZE,
2556                         data->sectorpos_base.Y*MAP_BLOCKSIZE
2557                 );
2558
2559                 // Allow a bit more
2560                 //(this should be more than the maximum radius of the tunnel)
2561                 s16 insure = 3;
2562                 s16 more = data->max_spread_amount - max_vein_diameter/2 - insure;
2563                 ar += v3s16(1,0,1) * more * 2;
2564                 of -= v3s16(1,0,1) * more;
2565                 
2566                 // Randomize starting position
2567                 v3f orp(
2568                         (float)(myrand()%ar.X)+0.5,
2569                         (float)(myrand()%ar.Y)+0.5,
2570                         (float)(myrand()%ar.Z)+0.5
2571                 );
2572
2573                 // Randomize mineral
2574                 u8 mineral;
2575                 if(myrand()%3 != 0)
2576                         mineral = MINERAL_COAL;
2577                 else
2578                         mineral = MINERAL_IRON;
2579
2580                 /*
2581                         Generate some vein starting from orp
2582                 */
2583
2584                 for(u16 j=0; j<2; j++)
2585                 {
2586                         /*v3f rp(
2587                                 (float)(myrand()%ar.X)+0.5,
2588                                 (float)(myrand()%ar.Y)+0.5,
2589                                 (float)(myrand()%ar.Z)+0.5
2590                         );
2591                         v3f vec = rp - orp;*/
2592                         
2593                         v3s16 maxlen(5, 5, 5);
2594                         v3f vec(
2595                                 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2596                                 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
2597                                 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2598                         );
2599                         v3f rp = orp + vec;
2600                         if(rp.X < 0)
2601                                 rp.X = 0;
2602                         else if(rp.X >= ar.X)
2603                                 rp.X = ar.X;
2604                         if(rp.Y < 0)
2605                                 rp.Y = 0;
2606                         else if(rp.Y >= ar.Y)
2607                                 rp.Y = ar.Y;
2608                         if(rp.Z < 0)
2609                                 rp.Z = 0;
2610                         else if(rp.Z >= ar.Z)
2611                                 rp.Z = ar.Z;
2612                         vec = rp - orp;
2613
2614                         // Randomize size
2615                         s16 min_d = 0;
2616                         s16 max_d = max_vein_diameter;
2617                         s16 rs = myrand_range(min_d, max_d);
2618                         
2619                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
2620                         {
2621                                 v3f fp = orp + vec * f;
2622                                 v3s16 cp(fp.X, fp.Y, fp.Z);
2623                                 s16 d0 = -rs/2;
2624                                 s16 d1 = d0 + rs - 1;
2625                                 for(s16 z0=d0; z0<=d1; z0++)
2626                                 {
2627                                         s16 si = rs - abs(z0);
2628                                         for(s16 x0=-si; x0<=si-1; x0++)
2629                                         {
2630                                                 s16 si2 = rs - abs(x0);
2631                                                 for(s16 y0=-si2+1; y0<=si2-1; y0++)
2632                                                 {
2633                                                         // Don't put mineral to every place
2634                                                         if(myrand()%5 != 0)
2635                                                                 continue;
2636
2637                                                         s16 z = cp.Z + z0;
2638                                                         s16 y = cp.Y + y0;
2639                                                         s16 x = cp.X + x0;
2640                                                         v3s16 p(x,y,z);
2641                                                         /*if(isInArea(p, ar) == false)
2642                                                                 continue;*/
2643                                                         // Check only height
2644                                                         if(y < 0 || y >= ar.Y)
2645                                                                 continue;
2646                                                         p += of;
2647                                                         
2648                                                         assert(data->vmanip.m_area.contains(p));
2649                                                         
2650                                                         // Just set it to air, it will be changed to
2651                                                         // water afterwards
2652                                                         u32 i = data->vmanip.m_area.index(p);
2653                                                         MapNode *n = &data->vmanip.m_data[i];
2654                                                         if(n->d == CONTENT_STONE)
2655                                                                 n->param = mineral;
2656                                                 }
2657                                         }
2658                                 }
2659                         }
2660
2661                         orp = rp;
2662                 }
2663         
2664         }
2665
2666         }//timer1
2667         {
2668         // 15ms @cs=8
2669         //TimeTaker timer1("add mud");
2670
2671         /*
2672                 Add mud to the central chunk
2673         */
2674         
2675         for(s16 x=0; x<data->sectorpos_base_size*MAP_BLOCKSIZE; x++)
2676         for(s16 z=0; z<data->sectorpos_base_size*MAP_BLOCKSIZE; z++)
2677         {
2678                 // Node position in 2d
2679                 v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2680                 
2681                 // Randomize mud amount
2682                 s16 mud_add_amount = (s16)(2.5 + 2.0 * noise2d_perlin(
2683                                 0.5+(float)p2d.X/200, 0.5+(float)p2d.Y/200,
2684                                 data->seed+1, 3, 0.55));
2685
2686                 // Find ground level
2687                 s16 surface_y = find_ground_level_clever(data->vmanip, p2d);
2688
2689                 /*
2690                         If topmost node is grass, change it to mud.
2691                         It might be if it was flown to there from a neighboring
2692                         chunk and then converted.
2693                 */
2694                 {
2695                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
2696                         MapNode *n = &data->vmanip.m_data[i];
2697                         if(n->d == CONTENT_GRASS)
2698                                 n->d = CONTENT_MUD;
2699                 }
2700
2701                 /*
2702                         Add mud on ground
2703                 */
2704                 {
2705                         s16 mudcount = 0;
2706                         v3s16 em = data->vmanip.m_area.getExtent();
2707                         s16 y_start = surface_y+1;
2708                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2709                         for(s16 y=y_start; y<=y_nodes_max; y++)
2710                         {
2711                                 if(mudcount >= mud_add_amount)
2712                                         break;
2713                                         
2714                                 MapNode &n = data->vmanip.m_data[i];
2715                                 n.d = CONTENT_MUD;
2716                                 mudcount++;
2717
2718                                 data->vmanip.m_area.add_y(em, i, 1);
2719                         }
2720                 }
2721
2722         }
2723
2724         }//timer1
2725         {
2726         // 340ms @cs=8
2727         TimeTaker timer1("flow mud");
2728
2729         /*
2730                 Flow mud away from steep edges
2731         */
2732
2733         // Limit area by 1 because mud is flown into neighbors.
2734         s16 mudflow_minpos = 0-data->max_spread_amount+1;
2735         s16 mudflow_maxpos = data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-2;
2736
2737         // Iterate a few times
2738         for(s16 k=0; k<3; k++)
2739         {
2740
2741         for(s16 x=mudflow_minpos;
2742                         x<=mudflow_maxpos;
2743                         x++)
2744         for(s16 z=mudflow_minpos;
2745                         z<=mudflow_maxpos;
2746                         z++)
2747         {
2748                 // Invert coordinates every 2nd iteration
2749                 if(k%2 == 0)
2750                 {
2751                         x = mudflow_maxpos - (x-mudflow_minpos);
2752                         z = mudflow_maxpos - (z-mudflow_minpos);
2753                 }
2754
2755                 // Node position in 2d
2756                 v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2757                 
2758                 v3s16 em = data->vmanip.m_area.getExtent();
2759                 u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2760                 s16 y=y_nodes_max;
2761
2762                 for(;; y--)
2763                 {
2764                         MapNode *n = NULL;
2765                         // Find mud
2766                         for(; y>=y_nodes_min; y--)
2767                         {
2768                                 n = &data->vmanip.m_data[i];
2769                                 //if(content_walkable(n->d))
2770                                 //      break;
2771                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
2772                                         break;
2773                                         
2774                                 data->vmanip.m_area.add_y(em, i, -1);
2775                         }
2776
2777                         // Stop if out of area
2778                         //if(data->vmanip.m_area.contains(i) == false)
2779                         if(y < y_nodes_min)
2780                                 break;
2781
2782                         /*// If not mud, do nothing to it
2783                         MapNode *n = &data->vmanip.m_data[i];
2784                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2785                                 continue;*/
2786
2787                         /*
2788                                 Don't flow it if the stuff under it is not mud
2789                         */
2790                         {
2791                                 u32 i2 = i;
2792                                 data->vmanip.m_area.add_y(em, i2, -1);
2793                                 // Cancel if out of area
2794                                 if(data->vmanip.m_area.contains(i2) == false)
2795                                         continue;
2796                                 MapNode *n2 = &data->vmanip.m_data[i2];
2797                                 if(n2->d != CONTENT_MUD && n2->d != CONTENT_GRASS)
2798                                         continue;
2799                         }
2800
2801                         // Make it exactly mud
2802                         n->d = CONTENT_MUD;
2803                         
2804                         /*s16 recurse_count = 0;
2805         mudflow_recurse:*/
2806
2807                         v3s16 dirs4[4] = {
2808                                 v3s16(0,0,1), // back
2809                                 v3s16(1,0,0), // right
2810                                 v3s16(0,0,-1), // front
2811                                 v3s16(-1,0,0), // left
2812                         };
2813
2814                         // Theck that upper is air or doesn't exist.
2815                         // Cancel dropping if upper keeps it in place
2816                         u32 i3 = i;
2817                         data->vmanip.m_area.add_y(em, i3, 1);
2818                         if(data->vmanip.m_area.contains(i3) == true
2819                                         && content_walkable(data->vmanip.m_data[i3].d) == true)
2820                         {
2821                                 continue;
2822                         }
2823
2824                         // Drop mud on side
2825                         
2826                         for(u32 di=0; di<4; di++)
2827                         {
2828                                 v3s16 dirp = dirs4[di];
2829                                 u32 i2 = i;
2830                                 // Move to side
2831                                 data->vmanip.m_area.add_p(em, i2, dirp);
2832                                 // Fail if out of area
2833                                 if(data->vmanip.m_area.contains(i2) == false)
2834                                         continue;
2835                                 // Check that side is air
2836                                 MapNode *n2 = &data->vmanip.m_data[i2];
2837                                 if(content_walkable(n2->d))
2838                                         continue;
2839                                 // Check that under side is air
2840                                 data->vmanip.m_area.add_y(em, i2, -1);
2841                                 if(data->vmanip.m_area.contains(i2) == false)
2842                                         continue;
2843                                 n2 = &data->vmanip.m_data[i2];
2844                                 if(content_walkable(n2->d))
2845                                         continue;
2846                                 /*// Check that under that is air (need a drop of 2)
2847                                 data->vmanip.m_area.add_y(em, i2, -1);
2848                                 if(data->vmanip.m_area.contains(i2) == false)
2849                                         continue;
2850                                 n2 = &data->vmanip.m_data[i2];
2851                                 if(content_walkable(n2->d))
2852                                         continue;*/
2853                                 // Loop further down until not air
2854                                 do{
2855                                         data->vmanip.m_area.add_y(em, i2, -1);
2856                                         // Fail if out of area
2857                                         if(data->vmanip.m_area.contains(i2) == false)
2858                                                 continue;
2859                                         n2 = &data->vmanip.m_data[i2];
2860                                 }while(content_walkable(n2->d) == false);
2861                                 // Loop one up so that we're in air
2862                                 data->vmanip.m_area.add_y(em, i2, 1);
2863                                 n2 = &data->vmanip.m_data[i2];
2864
2865                                 // Move mud to new place
2866                                 *n2 = *n;
2867                                 // Set old place to be air
2868                                 *n = MapNode(CONTENT_AIR);
2869
2870                                 // Done
2871                                 break;
2872                         }
2873                 }
2874         }
2875         
2876         }
2877
2878         }//timer1
2879         {
2880         // 50ms @cs=8
2881         //TimeTaker timer1("add water");
2882
2883         /*
2884                 Add water to the central chunk (and a bit more)
2885         */
2886         
2887         for(s16 x=0-data->max_spread_amount;
2888                         x<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount;
2889                         x++)
2890         for(s16 z=0-data->max_spread_amount;
2891                         z<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount;
2892                         z++)
2893         {
2894                 // Node position in 2d
2895                 v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2896                 
2897                 // Find ground level
2898                 //s16 surface_y = find_ground_level(data->vmanip, p2d);
2899
2900                 /*
2901                         If ground level is over water level, skip.
2902                         NOTE: This leaves caves near water without water,
2903                         which looks especially crappy when the nearby water
2904                         won't start flowing either for some reason
2905                 */
2906                 /*if(surface_y > WATER_LEVEL)
2907                         continue;*/
2908
2909                 /*
2910                         Add water on ground
2911                 */
2912                 {
2913                         v3s16 em = data->vmanip.m_area.getExtent();
2914                         u8 light = LIGHT_MAX;
2915                         // Start at global water surface level
2916                         s16 y_start = WATER_LEVEL;
2917                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2918                         MapNode *n = &data->vmanip.m_data[i];
2919
2920                         for(s16 y=y_start; y>=y_nodes_min; y--)
2921                         {
2922                                 n = &data->vmanip.m_data[i];
2923                                 
2924                                 // Stop when there is no water and no air
2925                                 if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
2926                                                 && n->d != CONTENT_WATER)
2927                                 {
2928
2929                                         break;
2930                                 }
2931                                 
2932                                 // Make water only not in caves
2933                                 if(!(data->vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
2934                                 {
2935                                         n->d = CONTENT_WATERSOURCE;
2936                                         //n->setLight(LIGHTBANK_DAY, light);
2937
2938                                         // Add to transforming liquid queue (in case it'd
2939                                         // start flowing)
2940                                         /*v3s16 p = v3s16(p2d.X, y, p2d.Y);
2941                                         m_transforming_liquid.push_back(p);*/
2942                                 }
2943                                 
2944                                 // Next one
2945                                 data->vmanip.m_area.add_y(em, i, -1);
2946                                 if(light > 0)
2947                                         light--;
2948                         }
2949                 }
2950
2951         }
2952
2953         }//timer1
2954         
2955         } // Aging loop
2956         /***********************
2957                 END OF AGING LOOP
2958         ************************/
2959
2960         {
2961         //TimeTaker timer1("convert mud to sand");
2962
2963         /*
2964                 Convert mud to sand
2965         */
2966         
2967         //s16 mud_add_amount = myrand_range(2, 4);
2968         //s16 mud_add_amount = 0;
2969         
2970         /*for(s16 x=0; x<data->sectorpos_base_size*MAP_BLOCKSIZE; x++)
2971         for(s16 z=0; z<data->sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
2972         for(s16 x=0-data->max_spread_amount+1;
2973                         x<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-1;
2974                         x++)
2975         for(s16 z=0-data->max_spread_amount+1;
2976                         z<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-1;
2977                         z++)
2978         {
2979                 // Node position in 2d
2980                 v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2981                 
2982                 // Determine whether to have sand here
2983                 double sandnoise = noise2d_perlin(
2984                                 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2985                                 data->seed+59420, 3, 0.50);
2986
2987                 bool have_sand = (sandnoise > -0.15);
2988
2989                 if(have_sand == false)
2990                         continue;
2991
2992                 // Find ground level
2993                 s16 surface_y = find_ground_level_clever(data->vmanip, p2d);
2994                 
2995                 if(surface_y > WATER_LEVEL + 2)
2996                         continue;
2997
2998                 {
2999                         v3s16 em = data->vmanip.m_area.getExtent();
3000                         s16 y_start = surface_y;
3001                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3002                         u32 not_sand_counter = 0;
3003                         for(s16 y=y_start; y>=y_nodes_min; y--)
3004                         {
3005                                 MapNode *n = &data->vmanip.m_data[i];
3006                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
3007                                 {
3008                                         n->d = CONTENT_SAND;
3009                                 }
3010                                 else
3011                                 {
3012                                         not_sand_counter++;
3013                                         if(not_sand_counter > 3)
3014                                                 break;
3015                                 }
3016
3017                                 data->vmanip.m_area.add_y(em, i, -1);
3018                         }
3019                 }
3020
3021         }
3022
3023         }//timer1
3024         {
3025         // 1ms @cs=8
3026         //TimeTaker timer1("generate trees");
3027
3028         /*
3029                 Generate some trees
3030         */
3031         {
3032                 // Divide area into parts
3033                 s16 div = 8;
3034                 s16 sidelen = data->sectorpos_base_size*MAP_BLOCKSIZE / div;
3035                 double area = sidelen * sidelen;
3036                 for(s16 x0=0; x0<div; x0++)
3037                 for(s16 z0=0; z0<div; z0++)
3038                 {
3039                         // Center position of part of division
3040                         v2s16 p2d_center(
3041                                 data->sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
3042                                 data->sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
3043                         );
3044                         // Minimum edge of part of division
3045                         v2s16 p2d_min(
3046                                 data->sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
3047                                 data->sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
3048                         );
3049                         // Maximum edge of part of division
3050                         v2s16 p2d_max(
3051                                 data->sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
3052                                 data->sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
3053                         );
3054                         // Amount of trees
3055                         u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
3056                         // Put trees in random places on part of division
3057                         for(u32 i=0; i<tree_count; i++)
3058                         {
3059                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
3060                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
3061                                 s16 y = find_ground_level(data->vmanip, v2s16(x,z));
3062                                 // Don't make a tree under water level
3063                                 if(y < WATER_LEVEL)
3064                                         continue;
3065                                 // Don't make a tree so high that it doesn't fit
3066                                 if(y > y_nodes_max - 6)
3067                                         continue;
3068                                 v3s16 p(x,y,z);
3069                                 /*
3070                                         Trees grow only on mud and grass
3071                                 */
3072                                 {
3073                                         u32 i = data->vmanip.m_area.index(v3s16(p));
3074                                         MapNode *n = &data->vmanip.m_data[i];
3075                                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3076                                                 continue;
3077                                 }
3078                                 p.Y++;
3079                                 // Make a tree
3080                                 make_tree(data->vmanip, p);
3081                         }
3082                 }
3083                 /*u32 tree_max = relative_area / 60;
3084                 //u32 count = myrand_range(0, tree_max);
3085                 for(u32 i=0; i<count; i++)
3086                 {
3087                         s16 x = myrand_range(0, data->sectorpos_base_size*MAP_BLOCKSIZE-1);
3088                         s16 z = myrand_range(0, data->sectorpos_base_size*MAP_BLOCKSIZE-1);
3089                         x += data->sectorpos_base.X*MAP_BLOCKSIZE;
3090                         z += data->sectorpos_base.Y*MAP_BLOCKSIZE;
3091                         s16 y = find_ground_level(data->vmanip, v2s16(x,z));
3092                         // Don't make a tree under water level
3093                         if(y < WATER_LEVEL)
3094                                 continue;
3095                         v3s16 p(x,y+1,z);
3096                         // Make a tree
3097                         make_tree(data->vmanip, p);
3098                 }*/
3099         }
3100
3101         }//timer1
3102
3103         {
3104         // 19ms @cs=8
3105         //TimeTaker timer1("grow grass");
3106
3107         /*
3108                 Grow grass
3109         */
3110
3111         /*for(s16 x=0-4; x<data->sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
3112         for(s16 z=0-4; z<data->sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
3113         for(s16 x=0-data->max_spread_amount;
3114                         x<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount;
3115                         x++)
3116         for(s16 z=0-data->max_spread_amount;
3117                         z<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount;
3118                         z++)
3119         {
3120                 // Node position in 2d
3121                 v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3122                 
3123                 /*
3124                         Find the lowest surface to which enough light ends up
3125                         to make grass grow.
3126
3127                         Basically just wait until not air and not leaves.
3128                 */
3129                 s16 surface_y = 0;
3130                 {
3131                         v3s16 em = data->vmanip.m_area.getExtent();
3132                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3133                         s16 y;
3134                         // Go to ground level
3135                         for(y=y_nodes_max; y>=y_nodes_min; y--)
3136                         {
3137                                 MapNode &n = data->vmanip.m_data[i];
3138                                 if(n.d != CONTENT_AIR
3139                                                 && n.d != CONTENT_LEAVES)
3140                                         break;
3141                                 data->vmanip.m_area.add_y(em, i, -1);
3142                         }
3143                         if(y >= y_nodes_min)
3144                                 surface_y = y;
3145                         else
3146                                 surface_y = y_nodes_min;
3147                 }
3148                 
3149                 u32 i = data->vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
3150                 MapNode *n = &data->vmanip.m_data[i];
3151                 if(n->d == CONTENT_MUD)
3152                         n->d = CONTENT_GRASS;
3153         }
3154
3155         }//timer1
3156
3157         /*
3158                 Initial lighting (sunlight)
3159         */
3160
3161         core::map<v3s16, bool> light_sources;
3162
3163         {
3164         // 750ms @cs=8, can't optimize more
3165         TimeTaker timer1("initial lighting");
3166
3167 #if 0
3168         /*
3169                 Go through the edges and add all nodes that have light to light_sources
3170         */
3171         
3172         // Four edges
3173         for(s16 i=0; i<4; i++)
3174         // Edge length
3175         for(s16 j=lighting_min_d;
3176                         j<=lighting_max_d;
3177                         j++)
3178         {
3179                 s16 x;
3180                 s16 z;
3181                 // +-X
3182                 if(i == 0 || i == 1)
3183                 {
3184                         x = (i==0) ? lighting_min_d : lighting_max_d;
3185                         if(i == 0)
3186                                 z = lighting_min_d;
3187                         else
3188                                 z = lighting_max_d;
3189                 }
3190                 // +-Z
3191                 else
3192                 {
3193                         z = (i==0) ? lighting_min_d : lighting_max_d;
3194                         if(i == 0)
3195                                 x = lighting_min_d;
3196                         else
3197                                 x = lighting_max_d;
3198                 }
3199                 
3200                 // Node position in 2d
3201                 v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3202
3203                 {
3204                         v3s16 em = data->vmanip.m_area.getExtent();
3205                         s16 y_start = y_nodes_max;
3206                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3207                         for(s16 y=y_start; y>=y_nodes_min; y--)
3208                         {
3209                                 MapNode *n = &data->vmanip.m_data[i];
3210                                 if(n->getLight(LIGHTBANK_DAY) != 0)
3211                                 {
3212                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3213                                 }
3214                                 //NOTE: This is broken, at least the index has to
3215                                 // be incremented
3216                         }
3217                 }
3218         }
3219 #endif
3220
3221 #if 1
3222         /*
3223                 Go through the edges and apply sunlight to them, not caring
3224                 about neighbors
3225         */
3226         
3227         // Four edges
3228         for(s16 i=0; i<4; i++)
3229         // Edge length
3230         for(s16 j=lighting_min_d;
3231                         j<=lighting_max_d;
3232                         j++)
3233         {
3234                 s16 x;
3235                 s16 z;
3236                 // +-X
3237                 if(i == 0 || i == 1)
3238                 {
3239                         x = (i==0) ? lighting_min_d : lighting_max_d;
3240                         if(i == 0)
3241                                 z = lighting_min_d;
3242                         else
3243                                 z = lighting_max_d;
3244                 }
3245                 // +-Z
3246                 else
3247                 {
3248                         z = (i==0) ? lighting_min_d : lighting_max_d;
3249                         if(i == 0)
3250                                 x = lighting_min_d;
3251                         else
3252                                 x = lighting_max_d;
3253                 }
3254                 
3255                 // Node position in 2d
3256                 v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3257                 
3258                 // Loop from top to down
3259                 {
3260                         u8 light = LIGHT_SUN;
3261                         v3s16 em = data->vmanip.m_area.getExtent();
3262                         s16 y_start = y_nodes_max;
3263                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3264                         for(s16 y=y_start; y>=y_nodes_min; y--)
3265                         {
3266                                 MapNode *n = &data->vmanip.m_data[i];
3267                                 if(light_propagates_content(n->d) == false)
3268                                 {
3269                                         light = 0;
3270                                 }
3271                                 else if(light != LIGHT_SUN
3272                                         || sunlight_propagates_content(n->d) == false)
3273                                 {
3274                                         if(light > 0)
3275                                                 light--;
3276                                 }
3277                                 
3278                                 n->setLight(LIGHTBANK_DAY, light);
3279                                 n->setLight(LIGHTBANK_NIGHT, 0);
3280                                 
3281                                 if(light != 0)
3282                                 {
3283                                         // Insert light source
3284                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3285                                 }
3286                                 
3287                                 // Increment index by y
3288                                 data->vmanip.m_area.add_y(em, i, -1);
3289                         }
3290                 }
3291         }
3292 #endif
3293
3294         /*for(s16 x=0; x<data->sectorpos_base_size*MAP_BLOCKSIZE; x++)
3295         for(s16 z=0; z<data->sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3296         /*for(s16 x=0-data->max_spread_amount+1;
3297                         x<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-1;
3298                         x++)
3299         for(s16 z=0-data->max_spread_amount+1;
3300                         z<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-1;
3301                         z++)*/
3302 #if 1
3303         /*
3304                 This has to be 1 smaller than the actual area, because
3305                 neighboring nodes are checked.
3306         */
3307         for(s16 x=lighting_min_d+1;
3308                         x<=lighting_max_d-1;
3309                         x++)
3310         for(s16 z=lighting_min_d+1;
3311                         z<=lighting_max_d-1;
3312                         z++)
3313         {
3314                 // Node position in 2d
3315                 v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3316                 
3317                 /*
3318                         Apply initial sunlight
3319                 */
3320                 {
3321                         u8 light = LIGHT_SUN;
3322                         bool add_to_sources = false;
3323                         v3s16 em = data->vmanip.m_area.getExtent();
3324                         s16 y_start = y_nodes_max;
3325                         u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3326                         for(s16 y=y_start; y>=y_nodes_min; y--)
3327                         {
3328                                 MapNode *n = &data->vmanip.m_data[i];
3329
3330                                 if(light_propagates_content(n->d) == false)
3331                                 {
3332                                         light = 0;
3333                                 }
3334                                 else if(light != LIGHT_SUN
3335                                         || sunlight_propagates_content(n->d) == false)
3336                                 {
3337                                         if(light > 0)
3338                                                 light--;
3339                                 }
3340                                 
3341                                 // This doesn't take much time
3342                                 if(add_to_sources == false)
3343                                 {
3344                                         /*
3345                                                 Check sides. If side is not air or water, start
3346                                                 adding to light_sources.
3347                                         */
3348                                         v3s16 dirs4[4] = {
3349                                                 v3s16(0,0,1), // back
3350                                                 v3s16(1,0,0), // right
3351                                                 v3s16(0,0,-1), // front
3352                                                 v3s16(-1,0,0), // left
3353                                         };
3354                                         for(u32 di=0; di<4; di++)
3355                                         {
3356                                                 v3s16 dirp = dirs4[di];
3357                                                 u32 i2 = i;
3358                                                 data->vmanip.m_area.add_p(em, i2, dirp);
3359                                                 MapNode *n2 = &data->vmanip.m_data[i2];
3360                                                 if(
3361                                                         n2->d != CONTENT_AIR
3362                                                         && n2->d != CONTENT_WATERSOURCE
3363                                                         && n2->d != CONTENT_WATER
3364                                                 ){
3365                                                         add_to_sources = true;
3366                                                         break;
3367                                                 }
3368                                         }
3369                                 }
3370                                 
3371                                 n->setLight(LIGHTBANK_DAY, light);
3372                                 n->setLight(LIGHTBANK_NIGHT, 0);
3373                                 
3374                                 // This doesn't take much time
3375                                 if(light != 0 && add_to_sources)
3376                                 {
3377                                         // Insert light source
3378                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3379                                 }
3380                                 
3381                                 // Increment index by y
3382                                 data->vmanip.m_area.add_y(em, i, -1);
3383                         }
3384                 }
3385         }
3386 #endif
3387
3388         }//timer1
3389
3390         // Spread light around
3391         {
3392                 TimeTaker timer("makeChunk() spreadLight");
3393                 data->vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
3394         }
3395         
3396         /*
3397                 Generation ended
3398         */
3399
3400         timer_generate.stop();
3401 }
3402
3403 //###################################################################
3404 //###################################################################
3405 //###################################################################
3406 //###################################################################
3407 //###################################################################
3408 //###################################################################
3409 //###################################################################
3410 //###################################################################
3411 //###################################################################
3412 //###################################################################
3413 //###################################################################
3414 //###################################################################
3415 //###################################################################
3416 //###################################################################
3417 //###################################################################
3418
3419 void ServerMap::initChunkMake(ChunkMakeData &data, v2s16 chunkpos)
3420 {
3421         // The distance how far into the neighbors the generator is allowed to go.
3422         s16 max_spread_amount_sectors = 2;
3423         assert(max_spread_amount_sectors <= m_chunksize);
3424         s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
3425
3426         s16 y_blocks_min = -4;
3427         s16 y_blocks_max = 3;
3428
3429         v2s16 sectorpos_base = chunk_to_sector(chunkpos);
3430         s16 sectorpos_base_size = m_chunksize;
3431
3432         v2s16 sectorpos_bigbase =
3433                         sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
3434         s16 sectorpos_bigbase_size =
3435                         sectorpos_base_size + 2 * max_spread_amount_sectors;
3436                         
3437         data.seed = m_seed;
3438         data.chunkpos = chunkpos;
3439         data.y_blocks_min = y_blocks_min;
3440         data.y_blocks_max = y_blocks_max;
3441         data.sectorpos_base = sectorpos_base;
3442         data.sectorpos_base_size = sectorpos_base_size;
3443         data.sectorpos_bigbase = sectorpos_bigbase;
3444         data.sectorpos_bigbase_size = sectorpos_bigbase_size;
3445         data.max_spread_amount = max_spread_amount;
3446
3447         /*
3448                 Create the whole area of this and the neighboring chunks
3449         */
3450         {
3451                 TimeTaker timer("generateChunkRaw() create area");
3452                 
3453                 for(s16 x=0; x<sectorpos_bigbase_size; x++)
3454                 for(s16 z=0; z<sectorpos_bigbase_size; z++)
3455                 {
3456                         v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
3457                         ServerMapSector *sector = createSector(sectorpos);
3458                         assert(sector);
3459
3460                         for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
3461                         {
3462                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
3463                                 MapBlock *block = createBlock(blockpos);
3464
3465                                 // Lighting won't be calculated
3466                                 //block->setLightingExpired(true);
3467                                 // Lighting will be calculated
3468                                 block->setLightingExpired(false);
3469
3470                                 /*
3471                                         Block gets sunlight if this is true.
3472
3473                                         This should be set to true when the top side of a block
3474                                         is completely exposed to the sky.
3475
3476                                         Actually this doesn't matter now because the
3477                                         initial lighting is done here.
3478                                 */
3479                                 block->setIsUnderground(y != y_blocks_max);
3480                         }
3481                 }
3482         }
3483         
3484         /*
3485                 Now we have a big empty area.
3486
3487                 Make a ManualMapVoxelManipulator that contains this and the
3488                 neighboring chunks
3489         */
3490         
3491         v3s16 bigarea_blocks_min(
3492                 sectorpos_bigbase.X,
3493                 y_blocks_min,
3494                 sectorpos_bigbase.Y
3495         );
3496         v3s16 bigarea_blocks_max(
3497                 sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
3498                 y_blocks_max,
3499                 sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
3500         );
3501         
3502         data.vmanip.setMap(this);
3503         // Add the area
3504         {
3505                 TimeTaker timer("generateChunkRaw() initialEmerge");
3506                 data.vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
3507         }
3508         
3509 }
3510
3511 MapChunk* ServerMap::finishChunkMake(ChunkMakeData &data,
3512                 core::map<v3s16, MapBlock*> &changed_blocks)
3513 {
3514         /*
3515                 Blit generated stuff to map
3516         */
3517         {
3518                 // 70ms @cs=8
3519                 //TimeTaker timer("generateChunkRaw() blitBackAll");
3520                 data.vmanip.blitBackAll(&changed_blocks);
3521         }
3522
3523         /*
3524                 Update day/night difference cache of the MapBlocks
3525         */
3526         {
3527                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
3528                                 i.atEnd() == false; i++)
3529                 {
3530                         MapBlock *block = i.getNode()->getValue();
3531                         block->updateDayNightDiff();
3532                 }
3533         }
3534
3535         /*
3536                 Add random objects to blocks
3537         */
3538         {
3539                 for(s16 x=0; x<data.sectorpos_base_size; x++)
3540                 for(s16 z=0; z<data.sectorpos_base_size; z++)
3541                 {
3542                         v2s16 sectorpos = data.sectorpos_base + v2s16(x,z);
3543                         ServerMapSector *sector = createSector(sectorpos);
3544                         assert(sector);
3545
3546                         for(s16 y=data.y_blocks_min; y<=data.y_blocks_max; y++)
3547                         {
3548                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
3549                                 MapBlock *block = createBlock(blockpos);
3550                                 addRandomObjects(block);
3551                         }
3552                 }
3553         }
3554
3555         /*
3556                 Create chunk metadata
3557         */
3558
3559         for(s16 x=-1; x<=1; x++)
3560         for(s16 y=-1; y<=1; y++)
3561         {
3562                 v2s16 chunkpos0 = data.chunkpos + v2s16(x,y);
3563                 // Add chunk meta information
3564                 MapChunk *chunk = getChunk(chunkpos0);
3565                 if(chunk == NULL)
3566                 {
3567                         chunk = new MapChunk();
3568                         m_chunks.insert(chunkpos0, chunk);
3569                 }
3570                 //chunk->setIsVolatile(true);
3571                 if(chunk->getGenLevel() > GENERATED_PARTLY)
3572                         chunk->setGenLevel(GENERATED_PARTLY);
3573         }
3574
3575         /*
3576                 Set central chunk non-volatile
3577         */
3578         MapChunk *chunk = getChunk(data.chunkpos);
3579         assert(chunk);
3580         // Set non-volatile
3581         //chunk->setIsVolatile(false);
3582         chunk->setGenLevel(GENERATED_FULLY);
3583         
3584         /*
3585                 Save changed parts of map
3586         */
3587         save(true);
3588         
3589         return chunk;
3590 }
3591
3592 // NOTE: Deprecated
3593 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
3594                 core::map<v3s16, MapBlock*> &changed_blocks,
3595                 bool force)
3596 {
3597         DSTACK(__FUNCTION_NAME);
3598
3599         /*
3600                 Don't generate if already fully generated
3601         */
3602         if(force == false)
3603         {
3604                 MapChunk *chunk = getChunk(chunkpos);
3605                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
3606                 {
3607                         dstream<<"generateChunkRaw(): Chunk "
3608                                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
3609                                         <<" already generated"<<std::endl;
3610                         return chunk;
3611                 }
3612         }
3613
3614         dstream<<"generateChunkRaw(): Generating chunk "
3615                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
3616                         <<std::endl;
3617         
3618         TimeTaker timer("generateChunkRaw()");
3619
3620         ChunkMakeData data;
3621         
3622         // Initialize generation
3623         initChunkMake(data, chunkpos);
3624         
3625         // Generate stuff
3626         makeChunk(&data);
3627
3628         // Finalize generation
3629         MapChunk *chunk = finishChunkMake(data, changed_blocks);
3630
3631         /*
3632                 Return central chunk (which was requested)
3633         */
3634         return chunk;
3635 }
3636
3637 // NOTE: Deprecated
3638 MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
3639                 core::map<v3s16, MapBlock*> &changed_blocks)
3640 {
3641         dstream<<"generateChunk(): Generating chunk "
3642                         <<"("<<chunkpos1.X<<","<<chunkpos1.Y<<")"
3643                         <<std::endl;
3644         
3645         /*for(s16 x=-1; x<=1; x++)
3646         for(s16 y=-1; y<=1; y++)*/
3647         for(s16 x=-0; x<=0; x++)
3648         for(s16 y=-0; y<=0; y++)
3649         {
3650                 v2s16 chunkpos0 = chunkpos1 + v2s16(x,y);
3651                 MapChunk *chunk = getChunk(chunkpos0);
3652                 // Skip if already generated
3653                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
3654                         continue;
3655                 generateChunkRaw(chunkpos0, changed_blocks);
3656         }
3657         
3658         assert(chunkNonVolatile(chunkpos1));
3659
3660         MapChunk *chunk = getChunk(chunkpos1);
3661         return chunk;
3662 }
3663
3664 ServerMapSector * ServerMap::createSector(v2s16 p2d)
3665 {
3666         DSTACK("%s: p2d=(%d,%d)",
3667                         __FUNCTION_NAME,
3668                         p2d.X, p2d.Y);
3669         
3670         /*
3671                 Check if it exists already in memory
3672         */
3673         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3674         if(sector != NULL)
3675                 return sector;
3676         
3677         /*
3678                 Try to load it from disk (with blocks)
3679         */
3680         if(loadSectorFull(p2d) == true)
3681         {
3682                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3683                 if(sector == NULL)
3684                 {
3685                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
3686                         throw InvalidPositionException("");
3687                 }
3688                 return sector;
3689         }
3690
3691         /*
3692                 Do not create over-limit
3693         */
3694         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3695         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3696         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3697         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
3698                 throw InvalidPositionException("createSector(): pos. over limit");
3699
3700         /*
3701                 Generate blank sector
3702         */
3703         
3704         sector = new ServerMapSector(this, p2d);
3705         
3706         // Sector position on map in nodes
3707         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
3708
3709         /*
3710                 Insert to container
3711         */
3712         m_sectors.insert(p2d, sector);
3713         
3714         return sector;
3715 }
3716
3717 MapSector * ServerMap::emergeSector(v2s16 p2d,
3718                 core::map<v3s16, MapBlock*> &changed_blocks)
3719 {
3720         DSTACK("%s: p2d=(%d,%d)",
3721                         __FUNCTION_NAME,
3722                         p2d.X, p2d.Y);
3723         
3724         /*
3725                 Check chunk status
3726         */
3727         v2s16 chunkpos = sector_to_chunk(p2d);
3728         /*bool chunk_nonvolatile = false;
3729         MapChunk *chunk = getChunk(chunkpos);
3730         if(chunk && chunk->getIsVolatile() == false)
3731                 chunk_nonvolatile = true;*/
3732         bool chunk_nonvolatile = chunkNonVolatile(chunkpos);
3733
3734         /*
3735                 If chunk is not fully generated, generate chunk
3736         */
3737         if(chunk_nonvolatile == false)
3738         {
3739                 // Generate chunk and neighbors
3740                 generateChunk(chunkpos, changed_blocks);
3741         }
3742         
3743         /*
3744                 Return sector if it exists now
3745         */
3746         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3747         if(sector != NULL)
3748                 return sector;
3749         
3750         /*
3751                 Try to load it from disk
3752         */
3753         if(loadSectorFull(p2d) == true)
3754         {
3755                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
3756                 if(sector == NULL)
3757                 {
3758                         dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<<std::endl;
3759                         throw InvalidPositionException("");
3760                 }
3761                 return sector;
3762         }
3763
3764         /*
3765                 generateChunk should have generated the sector
3766         */
3767         //assert(0);
3768         
3769         dstream<<"WARNING: ServerMap::emergeSector: Cannot find sector ("
3770                         <<p2d.X<<","<<p2d.Y<<" and chunk is already generated. "
3771                         <<std::endl;
3772
3773 #if 0
3774         dstream<<"WARNING: Creating an empty sector."<<std::endl;
3775
3776         return createSector(p2d);
3777         
3778 #endif
3779         
3780 #if 1
3781         dstream<<"WARNING: Forcing regeneration of chunk."<<std::endl;
3782
3783         // Generate chunk
3784         generateChunkRaw(chunkpos, changed_blocks, true);
3785
3786         /*
3787                 Return sector if it exists now
3788         */
3789         sector = getSectorNoGenerateNoEx(p2d);
3790         if(sector != NULL)
3791                 return sector;
3792         
3793         dstream<<"ERROR: Could not get sector from anywhere."<<std::endl;
3794         
3795         assert(0);
3796 #endif
3797         
3798         /*
3799                 Generate directly
3800         */
3801         //return generateSector();
3802 }
3803
3804 /*
3805         NOTE: This is not used for main map generation, only for blocks
3806         that are very high or low
3807 */
3808 MapBlock * ServerMap::generateBlock(
3809                 v3s16 p,
3810                 MapBlock *original_dummy,
3811                 ServerMapSector *sector,
3812                 core::map<v3s16, MapBlock*> &changed_blocks,
3813                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
3814 )
3815 {
3816         DSTACK("%s: p=(%d,%d,%d)",
3817                         __FUNCTION_NAME,
3818                         p.X, p.Y, p.Z);
3819         
3820         /*dstream<<"generateBlock(): "
3821                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3822                         <<std::endl;*/
3823         
3824         MapBlock *block = original_dummy;
3825                         
3826         v2s16 p2d(p.X, p.Z);
3827         s16 block_y = p.Y;
3828         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
3829         
3830         /*
3831                 Do not generate over-limit
3832         */
3833         if(blockpos_over_limit(p))
3834         {
3835                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
3836                 throw InvalidPositionException("generateBlock(): pos. over limit");
3837         }
3838
3839         /*
3840                 If block doesn't exist, create one.
3841                 If it exists, it is a dummy. In that case unDummify() it.
3842
3843                 NOTE: This already sets the map as the parent of the block
3844         */
3845         if(block == NULL)
3846         {
3847                 block = sector->createBlankBlockNoInsert(block_y);
3848         }
3849         else
3850         {
3851                 // Remove the block so that nobody can get a half-generated one.
3852                 sector->removeBlock(block);
3853                 // Allocate the block to contain the generated data
3854                 block->unDummify();
3855         }
3856         
3857         u8 water_material = CONTENT_WATERSOURCE;
3858         
3859         s32 lowest_ground_y = 32767;
3860         s32 highest_ground_y = -32768;
3861         
3862         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3863         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3864         {
3865                 //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
3866
3867                 //s16 surface_y = 0;
3868
3869                 s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
3870                                 + AVERAGE_MUD_AMOUNT;
3871
3872                 if(surface_y < lowest_ground_y)
3873                         lowest_ground_y = surface_y;
3874                 if(surface_y > highest_ground_y)
3875                         highest_ground_y = surface_y;
3876
3877                 s32 surface_depth = AVERAGE_MUD_AMOUNT;
3878                 
3879                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3880                 {
3881                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
3882                         MapNode n;
3883                         /*
3884                                 Calculate lighting
3885                                 
3886                                 NOTE: If there are some man-made structures above the
3887                                 newly created block, they won't be taken into account.
3888                         */
3889                         if(real_y > surface_y)
3890                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
3891
3892                         /*
3893                                 Calculate material
3894                         */
3895
3896                         // If node is over heightmap y, it's air or water
3897                         if(real_y > surface_y)
3898                         {
3899                                 // If under water level, it's water
3900                                 if(real_y < WATER_LEVEL)
3901                                 {
3902                                         n.d = water_material;
3903                                         n.setLight(LIGHTBANK_DAY,
3904                                                         diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
3905                                         /*
3906                                                 Add to transforming liquid queue (in case it'd
3907                                                 start flowing)
3908                                         */
3909                                         v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
3910                                         m_transforming_liquid.push_back(real_pos);
3911                                 }
3912                                 // else air
3913                                 else
3914                                         n.d = CONTENT_AIR;
3915                         }
3916                         // Else it's ground or caves (air)
3917                         else
3918                         {
3919                                 // If it's surface_depth under ground, it's stone
3920                                 if(real_y <= surface_y - surface_depth)
3921                                 {
3922                                         n.d = CONTENT_STONE;
3923                                 }
3924                                 else
3925                                 {
3926                                         // It is mud if it is under the first ground
3927                                         // level or under water
3928                                         if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
3929                                         {
3930                                                 n.d = CONTENT_MUD;
3931                                         }
3932                                         else
3933                                         {
3934                                                 n.d = CONTENT_GRASS;
3935                                         }
3936
3937                                         //n.d = CONTENT_MUD;
3938                                         
3939                                         /*// If under water level, it's mud
3940                                         if(real_y < WATER_LEVEL)
3941                                                 n.d = CONTENT_MUD;
3942                                         // Only the topmost node is grass
3943                                         else if(real_y <= surface_y - 1)
3944                                                 n.d = CONTENT_MUD;
3945                                         else
3946                                                 n.d = CONTENT_GRASS;*/
3947                                 }
3948                         }
3949
3950                         block->setNode(v3s16(x0,y0,z0), n);
3951                 }
3952         }
3953         
3954         /*
3955                 Calculate some helper variables
3956         */
3957         
3958         // Completely underground if the highest part of block is under lowest
3959         // ground height.
3960         // This has to be very sure; it's probably one too strict now but
3961         // that's just better.
3962         bool completely_underground =
3963                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
3964
3965         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
3966
3967         bool mostly_underwater_surface = false;
3968         if(highest_ground_y < WATER_LEVEL
3969                         && some_part_underground && !completely_underground)
3970                 mostly_underwater_surface = true;
3971
3972         /*
3973                 Get local attributes
3974         */
3975
3976         //dstream<<"generateBlock(): Getting local attributes"<<std::endl;
3977
3978         float caves_amount = 0.5;
3979
3980 #if 0
3981         {
3982                 /*
3983                         NOTE: BEWARE: Too big amount of attribute points slows verything
3984                         down by a lot.
3985                         1 interpolation from 5000 points takes 2-3ms.
3986                 */
3987                 //TimeTaker timer("generateBlock() local attribute retrieval");
3988                 v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
3989                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
3990                 caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
3991         }
3992 #endif
3993
3994         //dstream<<"generateBlock(): Done"<<std::endl;
3995
3996         /*
3997                 Generate caves
3998         */
3999
4000         // Initialize temporary table
4001         const s32 ued = MAP_BLOCKSIZE;
4002         bool underground_emptiness[ued*ued*ued];
4003         for(s32 i=0; i<ued*ued*ued; i++)
4004         {
4005                 underground_emptiness[i] = 0;
4006         }
4007         
4008         // Fill table
4009 #if 1
4010         {
4011                 /*
4012                         Initialize orp and ors. Try to find if some neighboring
4013                         MapBlock has a tunnel ended in its side
4014                 */
4015
4016                 v3f orp(
4017                         (float)(myrand()%ued)+0.5,
4018                         (float)(myrand()%ued)+0.5,
4019                         (float)(myrand()%ued)+0.5
4020                 );
4021                 
4022                 bool found_existing = false;
4023
4024                 // Check z-
4025                 try
4026                 {
4027                         s16 z = -1;
4028                         for(s16 y=0; y<ued; y++)
4029                         for(s16 x=0; x<ued; x++)
4030                         {
4031                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4032                                 if(getNode(ap).d == CONTENT_AIR)
4033                                 {
4034                                         orp = v3f(x+1,y+1,0);
4035                                         found_existing = true;
4036                                         goto continue_generating;
4037                                 }
4038                         }
4039                 }
4040                 catch(InvalidPositionException &e){}
4041                 
4042                 // Check z+
4043                 try
4044                 {
4045                         s16 z = ued;
4046                         for(s16 y=0; y<ued; y++)
4047                         for(s16 x=0; x<ued; x++)
4048                         {
4049                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4050                                 if(getNode(ap).d == CONTENT_AIR)
4051                                 {
4052                                         orp = v3f(x+1,y+1,ued-1);
4053                                         found_existing = true;
4054                                         goto continue_generating;
4055                                 }
4056                         }
4057                 }
4058                 catch(InvalidPositionException &e){}
4059                 
4060                 // Check x-
4061                 try
4062                 {
4063                         s16 x = -1;
4064                         for(s16 y=0; y<ued; y++)
4065                         for(s16 z=0; z<ued; z++)
4066                         {
4067                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4068                                 if(getNode(ap).d == CONTENT_AIR)
4069                                 {
4070                                         orp = v3f(0,y+1,z+1);
4071                                         found_existing = true;
4072                                         goto continue_generating;
4073                                 }
4074                         }
4075                 }
4076                 catch(InvalidPositionException &e){}
4077                 
4078                 // Check x+
4079                 try
4080                 {
4081                         s16 x = ued;
4082                         for(s16 y=0; y<ued; y++)
4083                         for(s16 z=0; z<ued; z++)
4084                         {
4085                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4086                                 if(getNode(ap).d == CONTENT_AIR)
4087                                 {
4088                                         orp = v3f(ued-1,y+1,z+1);
4089                                         found_existing = true;
4090                                         goto continue_generating;
4091                                 }
4092                         }
4093                 }
4094                 catch(InvalidPositionException &e){}
4095
4096                 // Check y-
4097                 try
4098                 {
4099                         s16 y = -1;
4100                         for(s16 x=0; x<ued; x++)
4101                         for(s16 z=0; z<ued; z++)
4102                         {
4103                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4104                                 if(getNode(ap).d == CONTENT_AIR)
4105                                 {
4106                                         orp = v3f(x+1,0,z+1);
4107                                         found_existing = true;
4108                                         goto continue_generating;
4109                                 }
4110                         }
4111                 }
4112                 catch(InvalidPositionException &e){}
4113                 
4114                 // Check y+
4115                 try
4116                 {
4117                         s16 y = ued;
4118                         for(s16 x=0; x<ued; x++)
4119                         for(s16 z=0; z<ued; z++)
4120                         {
4121                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4122                                 if(getNode(ap).d == CONTENT_AIR)
4123                                 {
4124                                         orp = v3f(x+1,ued-1,z+1);
4125                                         found_existing = true;
4126                                         goto continue_generating;
4127                                 }
4128                         }
4129                 }
4130                 catch(InvalidPositionException &e){}
4131
4132 continue_generating:
4133                 
4134                 /*
4135                         Choose whether to actually generate cave
4136                 */
4137                 bool do_generate_caves = true;
4138                 // Don't generate if no part is underground
4139                 if(!some_part_underground)
4140                 {
4141                         do_generate_caves = false;
4142                 }
4143                 // Don't generate if mostly underwater surface
4144                 /*else if(mostly_underwater_surface)
4145                 {
4146                         do_generate_caves = false;
4147                 }*/
4148                 // Partly underground = cave
4149                 else if(!completely_underground)
4150                 {
4151                         do_generate_caves = (rand() % 100 <= (s32)(caves_amount*100));
4152                 }
4153                 // Found existing cave underground
4154                 else if(found_existing && completely_underground)
4155                 {
4156                         do_generate_caves = (rand() % 100 <= (s32)(caves_amount*100));
4157                 }
4158                 // Underground and no caves found
4159                 else
4160                 {
4161                         do_generate_caves = (rand() % 300 <= (s32)(caves_amount*100));
4162                 }
4163
4164                 if(do_generate_caves)
4165                 {
4166                         /*
4167                                 Generate some tunnel starting from orp and ors
4168                         */
4169                         for(u16 i=0; i<3; i++)
4170                         {
4171                                 v3f rp(
4172                                         (float)(myrand()%ued)+0.5,
4173                                         (float)(myrand()%ued)+0.5,
4174                                         (float)(myrand()%ued)+0.5
4175                                 );
4176                                 s16 min_d = 0;
4177                                 s16 max_d = 4;
4178                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
4179                                 
4180                                 v3f vec = rp - orp;
4181
4182                                 for(float f=0; f<1.0; f+=0.04)
4183                                 {
4184                                         v3f fp = orp + vec * f;
4185                                         v3s16 cp(fp.X, fp.Y, fp.Z);
4186                                         s16 d0 = -rs/2;
4187                                         s16 d1 = d0 + rs - 1;
4188                                         for(s16 z0=d0; z0<=d1; z0++)
4189                                         {
4190                                                 s16 si = rs - abs(z0);
4191                                                 for(s16 x0=-si; x0<=si-1; x0++)
4192                                                 {
4193                                                         s16 si2 = rs - abs(x0);
4194                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
4195                                                         {
4196                                                                 s16 z = cp.Z + z0;
4197                                                                 s16 y = cp.Y + y0;
4198                                                                 s16 x = cp.X + x0;
4199                                                                 v3s16 p(x,y,z);
4200                                                                 if(isInArea(p, ued) == false)
4201                                                                         continue;
4202                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
4203                                                         }
4204                                                 }
4205                                         }
4206                                 }
4207
4208                                 orp = rp;
4209                         }
4210                 }
4211         }
4212 #endif
4213
4214         // Set to true if has caves.
4215         // Set when some non-air is changed to air when making caves.
4216         bool has_caves = false;
4217
4218         /*
4219                 Apply temporary cave data to block
4220         */
4221
4222         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4223         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4224         {
4225                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4226                 {
4227                         MapNode n = block->getNode(v3s16(x0,y0,z0));
4228
4229                         // Create caves
4230                         if(underground_emptiness[
4231                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
4232                                         +ued*(y0*ued/MAP_BLOCKSIZE)
4233                                         +(x0*ued/MAP_BLOCKSIZE)])
4234                         {
4235                                 if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
4236                                 {
4237                                         // Has now caves
4238                                         has_caves = true;
4239                                         // Set air to node
4240                                         n.d = CONTENT_AIR;
4241                                 }
4242                         }
4243
4244                         block->setNode(v3s16(x0,y0,z0), n);
4245                 }
4246         }
4247         
4248         /*
4249                 This is used for guessing whether or not the block should
4250                 receive sunlight from the top if the block above doesn't exist
4251         */
4252         block->setIsUnderground(completely_underground);
4253
4254         /*
4255                 Force lighting update if some part of block is partly
4256                 underground and has caves.
4257         */
4258         /*if(some_part_underground && !completely_underground && has_caves)
4259         {
4260                 //dstream<<"Half-ground caves"<<std::endl;
4261                 lighting_invalidated_blocks[block->getPos()] = block;
4262         }*/
4263         
4264         // DEBUG: Always update lighting
4265         //lighting_invalidated_blocks[block->getPos()] = block;
4266
4267         /*
4268                 Add some minerals
4269         */
4270
4271         if(some_part_underground)
4272         {
4273                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
4274
4275                 /*
4276                         Add meseblocks
4277                 */
4278                 for(s16 i=0; i<underground_level/4 + 1; i++)
4279                 {
4280                         if(myrand()%50 == 0)
4281                         {
4282                                 v3s16 cp(
4283                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4284                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4285                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4286                                 );
4287
4288                                 MapNode n;
4289                                 n.d = CONTENT_MESE;
4290                                 
4291                                 for(u16 i=0; i<27; i++)
4292                                 {
4293                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4294                                                 if(myrand()%8 == 0)
4295                                                         block->setNode(cp+g_27dirs[i], n);
4296                                 }
4297                         }
4298                 }
4299
4300                 /*
4301                         Add coal
4302                 */
4303                 u16 coal_amount = 30;
4304                 u16 coal_rareness = 60 / coal_amount;
4305                 if(coal_rareness == 0)
4306                         coal_rareness = 1;
4307                 if(myrand()%coal_rareness == 0)
4308                 {
4309                         u16 a = myrand() % 16;
4310                         u16 amount = coal_amount * a*a*a / 1000;
4311                         for(s16 i=0; i<amount; i++)
4312                         {
4313                                 v3s16 cp(
4314                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4315                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4316                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4317                                 );
4318
4319                                 MapNode n;
4320                                 n.d = CONTENT_STONE;
4321                                 n.param = MINERAL_COAL;
4322
4323                                 for(u16 i=0; i<27; i++)
4324                                 {
4325                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4326                                                 if(myrand()%8 == 0)
4327                                                         block->setNode(cp+g_27dirs[i], n);
4328                                 }
4329                         }
4330                 }
4331
4332                 /*
4333                         Add iron
4334                 */
4335                 //TODO: change to iron_amount or whatever
4336                 u16 iron_amount = 15;
4337                 u16 iron_rareness = 60 / iron_amount;
4338                 if(iron_rareness == 0)
4339                         iron_rareness = 1;
4340                 if(myrand()%iron_rareness == 0)
4341                 {
4342                         u16 a = myrand() % 16;
4343                         u16 amount = iron_amount * a*a*a / 1000;
4344                         for(s16 i=0; i<amount; i++)
4345                         {
4346                                 v3s16 cp(
4347                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4348                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4349                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4350                                 );
4351
4352                                 MapNode n;
4353                                 n.d = CONTENT_STONE;
4354                                 n.param = MINERAL_IRON;
4355
4356                                 for(u16 i=0; i<27; i++)
4357                                 {
4358                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4359                                                 if(myrand()%8 == 0)
4360                                                         block->setNode(cp+g_27dirs[i], n);
4361                                 }
4362                         }
4363                 }
4364         }
4365         
4366         /*
4367                 Create a few rats in empty blocks underground
4368         */
4369         if(completely_underground)
4370         {
4371                 //for(u16 i=0; i<2; i++)
4372                 {
4373                         v3s16 cp(
4374                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4375                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4376                                 (myrand()%(MAP_BLOCKSIZE-2))+1
4377                         );
4378
4379                         // Check that the place is empty
4380                         //if(!is_ground_content(block->getNode(cp).d))
4381                         if(1)
4382                         {
4383                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp, BS));
4384                                 block->addObject(obj);
4385                         }
4386                 }
4387         }
4388         
4389         /*
4390                 Add block to sector.
4391         */
4392         sector->insertBlock(block);
4393         
4394         // Lighting is invalid after generation.
4395         block->setLightingExpired(true);
4396         
4397 #if 0
4398         /*
4399                 Debug information
4400         */
4401         dstream
4402         <<"lighting_invalidated_blocks.size()"
4403         <<", has_caves"
4404         <<", completely_ug"
4405         <<", some_part_ug"
4406         <<"  "<<lighting_invalidated_blocks.size()
4407         <<", "<<has_caves
4408         <<", "<<completely_underground
4409         <<", "<<some_part_underground
4410         <<std::endl;
4411 #endif
4412
4413         return block;
4414 }
4415
4416 MapBlock * ServerMap::createBlock(v3s16 p)
4417 {
4418         DSTACK("%s: p=(%d,%d,%d)",
4419                         __FUNCTION_NAME, p.X, p.Y, p.Z);
4420         
4421         /*
4422                 Do not create over-limit
4423         */
4424         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4425         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4426         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4427         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4428         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4429         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4430                 throw InvalidPositionException("createBlock(): pos. over limit");
4431         
4432         v2s16 p2d(p.X, p.Z);
4433         s16 block_y = p.Y;
4434         /*
4435                 This will create or load a sector if not found in memory.
4436                 If block exists on disk, it will be loaded.
4437
4438                 NOTE: On old save formats, this will be slow, as it generates
4439                       lighting on blocks for them.
4440         */
4441         ServerMapSector *sector;
4442         try{
4443                 sector = (ServerMapSector*)createSector(p2d);
4444                 assert(sector->getId() == MAPSECTOR_SERVER);
4445         }
4446         catch(InvalidPositionException &e)
4447         {
4448                 dstream<<"createBlock: createSector() failed"<<std::endl;
4449                 throw e;
4450         }
4451         /*
4452                 NOTE: This should not be done, or at least the exception
4453                 should not be passed on as std::exception, because it
4454                 won't be catched at all.
4455         */
4456         /*catch(std::exception &e)
4457         {
4458                 dstream<<"createBlock: createSector() failed: "
4459                                 <<e.what()<<std::endl;
4460                 throw e;
4461         }*/
4462
4463         /*
4464                 Try to get a block from the sector
4465         */
4466
4467         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4468         if(block)
4469                 return block;
4470         // Create blank
4471         block = sector->createBlankBlock(block_y);
4472         return block;
4473 }
4474
4475 MapBlock * ServerMap::emergeBlock(
4476                 v3s16 p,
4477                 bool only_from_disk,
4478                 core::map<v3s16, MapBlock*> &changed_blocks,
4479                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
4480 )
4481 {
4482         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
4483                         __FUNCTION_NAME,
4484                         p.X, p.Y, p.Z, only_from_disk);
4485         
4486         /*
4487                 Do not generate over-limit
4488         */
4489         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4490         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4491         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4492         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4493         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4494         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4495                 throw InvalidPositionException("emergeBlock(): pos. over limit");
4496         
4497         v2s16 p2d(p.X, p.Z);
4498         s16 block_y = p.Y;
4499         /*
4500                 This will create or load a sector if not found in memory.
4501                 If block exists on disk, it will be loaded.
4502         */
4503         ServerMapSector *sector;
4504         try{
4505                 sector = (ServerMapSector*)emergeSector(p2d, changed_blocks);
4506                 assert(sector->getId() == MAPSECTOR_SERVER);
4507         }
4508         catch(InvalidPositionException &e)
4509         {
4510                 dstream<<"emergeBlock: emergeSector() failed: "
4511                                 <<e.what()<<std::endl;
4512                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4513                                 <<std::endl
4514                                 <<"You could try to delete it."<<std::endl;
4515                 throw e;
4516         }
4517         catch(VersionMismatchException &e)
4518         {
4519                 dstream<<"emergeBlock: emergeSector() failed: "
4520                                 <<e.what()<<std::endl;
4521                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4522                                 <<std::endl
4523                                 <<"You could try to delete it."<<std::endl;
4524                 throw e;
4525         }
4526         /*
4527                 NOTE: This should not be done, or at least the exception
4528                 should not be passed on as std::exception, because it
4529                 won't be catched at all.
4530         */
4531         /*catch(std::exception &e)
4532         {
4533                 dstream<<"emergeBlock: emergeSector() failed: "
4534                                 <<e.what()<<std::endl;
4535                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4536                                 <<std::endl
4537                                 <<"You could try to delete it."<<std::endl;
4538                 throw e;
4539         }*/
4540
4541         /*
4542                 Try to get a block from the sector
4543         */
4544
4545         bool does_not_exist = false;
4546         bool lighting_expired = false;
4547         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4548
4549         if(block == NULL)
4550         {
4551                 does_not_exist = true;
4552         }
4553         else if(block->isDummy() == true)
4554         {
4555                 does_not_exist = true;
4556         }
4557         else if(block->getLightingExpired())
4558         {
4559                 lighting_expired = true;
4560         }
4561         else
4562         {
4563                 // Valid block
4564                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
4565                 return block;
4566         }
4567         
4568         /*
4569                 If block was not found on disk and not going to generate a
4570                 new one, make sure there is a dummy block in place.
4571         */
4572         if(only_from_disk && (does_not_exist || lighting_expired))
4573         {
4574                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
4575
4576                 if(block == NULL)
4577                 {
4578                         // Create dummy block
4579                         block = new MapBlock(this, p, true);
4580
4581                         // Add block to sector
4582                         sector->insertBlock(block);
4583                 }
4584                 // Done.
4585                 return block;
4586         }
4587
4588         //dstream<<"Not found on disk, generating."<<std::endl;
4589         // 0ms
4590         //TimeTaker("emergeBlock() generate");
4591
4592         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
4593
4594         /*
4595                 If the block doesn't exist, generate the block.
4596         */
4597         if(does_not_exist)
4598         {
4599                 block = generateBlock(p, block, sector, changed_blocks,
4600                                 lighting_invalidated_blocks); 
4601         }
4602
4603         if(lighting_expired)
4604         {
4605                 lighting_invalidated_blocks.insert(p, block);
4606         }
4607
4608         /*
4609                 Initially update sunlight
4610         */
4611         
4612         {
4613                 core::map<v3s16, bool> light_sources;
4614                 bool black_air_left = false;
4615                 bool bottom_invalid =
4616                                 block->propagateSunlight(light_sources, true,
4617                                 &black_air_left, true);
4618
4619                 // If sunlight didn't reach everywhere and part of block is
4620                 // above ground, lighting has to be properly updated
4621                 //if(black_air_left && some_part_underground)
4622                 if(black_air_left)
4623                 {
4624                         lighting_invalidated_blocks[block->getPos()] = block;
4625                 }
4626
4627                 if(bottom_invalid)
4628                 {
4629                         lighting_invalidated_blocks[block->getPos()] = block;
4630                 }
4631         }
4632         
4633         return block;
4634 }
4635
4636 s16 ServerMap::findGroundLevel(v2s16 p2d)
4637 {
4638         /*
4639                 Uh, just do something random...
4640         */
4641         // Find existing map from top to down
4642         s16 max=63;
4643         s16 min=-64;
4644         v3s16 p(p2d.X, max, p2d.Y);
4645         for(; p.Y>min; p.Y--)
4646         {
4647                 MapNode n = getNodeNoEx(p);
4648                 if(n.d != CONTENT_IGNORE)
4649                         break;
4650         }
4651         if(p.Y == min)
4652                 goto plan_b;
4653         // If this node is not air, go to plan b
4654         if(getNodeNoEx(p).d != CONTENT_AIR)
4655                 goto plan_b;
4656         // Search existing walkable and return it
4657         for(; p.Y>min; p.Y--)
4658         {
4659                 MapNode n = getNodeNoEx(p);
4660                 if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
4661                         return p.Y;
4662         }
4663         // Move to plan b
4664 plan_b:
4665         /*
4666                 Plan B: Get from map generator perlin noise function
4667         */
4668         double level = base_rock_level_2d(m_seed, p2d);
4669         return (s16)level;
4670 }
4671
4672 void ServerMap::createDir(std::string path)
4673 {
4674         if(fs::CreateDir(path) == false)
4675         {
4676                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
4677                                 <<"\""<<path<<"\""<<std::endl;
4678                 throw BaseException("ServerMap failed to create directory");
4679         }
4680 }
4681
4682 std::string ServerMap::getSectorSubDir(v2s16 pos)
4683 {
4684         char cc[9];
4685         snprintf(cc, 9, "%.4x%.4x",
4686                         (unsigned int)pos.X&0xffff,
4687                         (unsigned int)pos.Y&0xffff);
4688
4689         return std::string(cc);
4690 }
4691
4692 std::string ServerMap::getSectorDir(v2s16 pos)
4693 {
4694         return m_savedir + "/sectors/" + getSectorSubDir(pos);
4695 }
4696
4697 v2s16 ServerMap::getSectorPos(std::string dirname)
4698 {
4699         if(dirname.size() != 8)
4700                 throw InvalidFilenameException("Invalid sector directory name");
4701         unsigned int x, y;
4702         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
4703         if(r != 2)
4704                 throw InvalidFilenameException("Invalid sector directory name");
4705         v2s16 pos((s16)x, (s16)y);
4706         return pos;
4707 }
4708
4709 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
4710 {
4711         v2s16 p2d = getSectorPos(sectordir);
4712
4713         if(blockfile.size() != 4){
4714                 throw InvalidFilenameException("Invalid block filename");
4715         }
4716         unsigned int y;
4717         int r = sscanf(blockfile.c_str(), "%4x", &y);
4718         if(r != 1)
4719                 throw InvalidFilenameException("Invalid block filename");
4720         return v3s16(p2d.X, y, p2d.Y);
4721 }
4722
4723 void ServerMap::save(bool only_changed)
4724 {
4725         DSTACK(__FUNCTION_NAME);
4726         if(m_map_saving_enabled == false)
4727         {
4728                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
4729                 return;
4730         }
4731         
4732         if(only_changed == false)
4733                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
4734                                 <<std::endl;
4735         
4736         saveMapMeta();
4737         saveChunkMeta();
4738         
4739         u32 sector_meta_count = 0;
4740         u32 block_count = 0;
4741         
4742         { //sectorlock
4743         JMutexAutoLock lock(m_sector_mutex);
4744         
4745         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
4746         for(; i.atEnd() == false; i++)
4747         {
4748                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
4749                 assert(sector->getId() == MAPSECTOR_SERVER);
4750         
4751                 if(sector->differs_from_disk || only_changed == false)
4752                 {
4753                         saveSectorMeta(sector);
4754                         sector_meta_count++;
4755                 }
4756                 core::list<MapBlock*> blocks;
4757                 sector->getBlocks(blocks);
4758                 core::list<MapBlock*>::Iterator j;
4759                 for(j=blocks.begin(); j!=blocks.end(); j++)
4760                 {
4761                         MapBlock *block = *j;
4762                         if(block->getChangedFlag() || only_changed == false)
4763                         {
4764                                 saveBlock(block);
4765                                 block_count++;
4766
4767                                 /*dstream<<"ServerMap: Written block ("
4768                                                 <<block->getPos().X<<","
4769                                                 <<block->getPos().Y<<","
4770                                                 <<block->getPos().Z<<")"
4771                                                 <<std::endl;*/
4772                         }
4773                 }
4774         }
4775
4776         }//sectorlock
4777         
4778         /*
4779                 Only print if something happened or saved whole map
4780         */
4781         if(only_changed == false || sector_meta_count != 0
4782                         || block_count != 0)
4783         {
4784                 dstream<<DTIME<<"ServerMap: Written: "
4785                                 <<sector_meta_count<<" sector metadata files, "
4786                                 <<block_count<<" block files"
4787                                 <<std::endl;
4788         }
4789 }
4790
4791 void ServerMap::loadAll()
4792 {
4793         DSTACK(__FUNCTION_NAME);
4794         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
4795         
4796         loadMapMeta();
4797         loadChunkMeta();
4798
4799         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
4800
4801         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
4802         
4803         JMutexAutoLock lock(m_sector_mutex);
4804         
4805         s32 counter = 0;
4806         s32 printed_counter = -100000;
4807         s32 count = list.size();
4808
4809         std::vector<fs::DirListNode>::iterator i;
4810         for(i=list.begin(); i!=list.end(); i++)
4811         {
4812                 if(counter > printed_counter + 10)
4813                 {
4814                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
4815                         printed_counter = counter;
4816                 }
4817                 counter++;
4818
4819                 MapSector *sector = NULL;
4820
4821                 // We want directories
4822                 if(i->dir == false)
4823                         continue;
4824                 try{
4825                         sector = loadSectorMeta(i->name);
4826                 }
4827                 catch(InvalidFilenameException &e)
4828                 {
4829                         // This catches unknown crap in directory
4830                 }
4831                 
4832                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
4833                                 (m_savedir+"/sectors/"+i->name);
4834                 std::vector<fs::DirListNode>::iterator i2;
4835                 for(i2=list2.begin(); i2!=list2.end(); i2++)
4836                 {
4837                         // We want files
4838                         if(i2->dir)
4839                                 continue;
4840                         try{
4841                                 loadBlock(i->name, i2->name, sector);
4842                         }
4843                         catch(InvalidFilenameException &e)
4844                         {
4845                                 // This catches unknown crap in directory
4846                         }
4847                 }
4848         }
4849         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
4850 }
4851
4852 #if 0
4853 void ServerMap::saveMasterHeightmap()
4854 {
4855         DSTACK(__FUNCTION_NAME);
4856         
4857         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
4858
4859         createDir(m_savedir);
4860         
4861         /*std::string fullpath = m_savedir + "/master_heightmap";
4862         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4863         if(o.good() == false)
4864                 throw FileNotGoodException("Cannot open master heightmap");*/
4865         
4866         // Format used for writing
4867         //u8 version = SER_FMT_VER_HIGHEST;
4868 }
4869
4870 void ServerMap::loadMasterHeightmap()
4871 {
4872         DSTACK(__FUNCTION_NAME);
4873         
4874         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
4875
4876         /*std::string fullpath = m_savedir + "/master_heightmap";
4877         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4878         if(is.good() == false)
4879                 throw FileNotGoodException("Cannot open master heightmap");*/
4880 }
4881 #endif
4882
4883 void ServerMap::saveMapMeta()
4884 {
4885         DSTACK(__FUNCTION_NAME);
4886         
4887         dstream<<"INFO: ServerMap::saveMapMeta(): "
4888                         <<"seed="<<m_seed<<", chunksize="<<m_chunksize
4889                         <<std::endl;
4890
4891         createDir(m_savedir);
4892         
4893         std::string fullpath = m_savedir + "/map_meta.txt";
4894         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
4895         if(os.good() == false)
4896         {
4897                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
4898                                 <<"could not open"<<fullpath<<std::endl;
4899                 throw FileNotGoodException("Cannot open chunk metadata");
4900         }
4901         
4902         Settings params;
4903         params.setU64("seed", m_seed);
4904         params.setS32("chunksize", m_chunksize);
4905
4906         params.writeLines(os);
4907
4908         os<<"[end_of_params]\n";
4909         
4910 }
4911
4912 void ServerMap::loadMapMeta()
4913 {
4914         DSTACK(__FUNCTION_NAME);
4915         
4916         dstream<<"INFO: ServerMap::loadMapMeta(): Loading chunk metadata"
4917                         <<std::endl;
4918
4919         std::string fullpath = m_savedir + "/map_meta.txt";
4920         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4921         if(is.good() == false)
4922         {
4923                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
4924                                 <<"could not open"<<fullpath<<std::endl;
4925                 throw FileNotGoodException("Cannot open chunk metadata");
4926         }
4927
4928         Settings params;
4929
4930         for(;;)
4931         {
4932                 if(is.eof())
4933                         throw SerializationError
4934                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
4935                 std::string line;
4936                 std::getline(is, line);
4937                 std::string trimmedline = trim(line);
4938                 if(trimmedline == "[end_of_params]")
4939                         break;
4940                 params.parseConfigLine(line);
4941         }
4942
4943         m_seed = params.getU64("seed");
4944         m_chunksize = params.getS32("chunksize");
4945
4946         dstream<<"INFO: ServerMap::loadMapMeta(): "
4947                         <<"seed="<<m_seed<<", chunksize="<<m_chunksize
4948                         <<std::endl;
4949 }
4950
4951 void ServerMap::saveChunkMeta()
4952 {
4953         DSTACK(__FUNCTION_NAME);
4954         
4955         u32 count = m_chunks.size();
4956
4957         dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
4958                         <<count<<" chunks"<<std::endl;
4959
4960         createDir(m_savedir);
4961         
4962         std::string fullpath = m_savedir + "/chunk_meta";
4963         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
4964         if(os.good() == false)
4965         {
4966                 dstream<<"ERROR: ServerMap::saveChunkMeta(): "
4967                                 <<"could not open"<<fullpath<<std::endl;
4968                 throw FileNotGoodException("Cannot open chunk metadata");
4969         }
4970         
4971         u8 version = 0;
4972         
4973         // Write version
4974         os.write((char*)&version, 1);
4975
4976         u8 buf[4];
4977         
4978         // Write count
4979         writeU32(buf, count);
4980         os.write((char*)buf, 4);
4981         
4982         for(core::map<v2s16, MapChunk*>::Iterator
4983                         i = m_chunks.getIterator();
4984                         i.atEnd()==false; i++)
4985         {
4986                 v2s16 p = i.getNode()->getKey();
4987                 MapChunk *chunk = i.getNode()->getValue();
4988                 // Write position
4989                 writeV2S16(buf, p);
4990                 os.write((char*)buf, 4);
4991                 // Write chunk data
4992                 chunk->serialize(os, version);
4993         }
4994 }
4995
4996 void ServerMap::loadChunkMeta()
4997 {
4998         DSTACK(__FUNCTION_NAME);
4999         
5000         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading chunk metadata"
5001                         <<std::endl;
5002
5003         std::string fullpath = m_savedir + "/chunk_meta";
5004         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5005         if(is.good() == false)
5006         {
5007                 dstream<<"ERROR: ServerMap::loadChunkMeta(): "
5008                                 <<"could not open"<<fullpath<<std::endl;
5009                 throw FileNotGoodException("Cannot open chunk metadata");
5010         }
5011
5012         u8 version = 0;
5013         
5014         // Read version
5015         is.read((char*)&version, 1);
5016
5017         u8 buf[4];
5018         
5019         // Read count
5020         is.read((char*)buf, 4);
5021         u32 count = readU32(buf);
5022
5023         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading metadata of "
5024                         <<count<<" chunks"<<std::endl;
5025         
5026         for(u32 i=0; i<count; i++)
5027         {
5028                 v2s16 p;
5029                 MapChunk *chunk = new MapChunk();
5030                 // Read position
5031                 is.read((char*)buf, 4);
5032                 p = readV2S16(buf);
5033                 // Read chunk data
5034                 chunk->deSerialize(is, version);
5035                 m_chunks.insert(p, chunk);
5036         }
5037 }
5038
5039 void ServerMap::saveSectorMeta(ServerMapSector *sector)
5040 {
5041         DSTACK(__FUNCTION_NAME);
5042         // Format used for writing
5043         u8 version = SER_FMT_VER_HIGHEST;
5044         // Get destination
5045         v2s16 pos = sector->getPos();
5046         createDir(m_savedir);
5047         createDir(m_savedir+"/sectors");
5048         std::string dir = getSectorDir(pos);
5049         createDir(dir);
5050         
5051         std::string fullpath = dir + "/meta";
5052         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5053         if(o.good() == false)
5054                 throw FileNotGoodException("Cannot open sector metafile");
5055
5056         sector->serialize(o, version);
5057         
5058         sector->differs_from_disk = false;
5059 }
5060
5061 MapSector* ServerMap::loadSectorMeta(std::string dirname)
5062 {
5063         DSTACK(__FUNCTION_NAME);
5064         // Get destination
5065         v2s16 p2d = getSectorPos(dirname);
5066         std::string dir = m_savedir + "/sectors/" + dirname;
5067         
5068         std::string fullpath = dir + "/meta";
5069         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5070         if(is.good() == false)
5071                 throw FileNotGoodException("Cannot open sector metafile");
5072
5073         ServerMapSector *sector = ServerMapSector::deSerialize
5074                         (is, this, p2d, m_sectors);
5075         
5076         sector->differs_from_disk = false;
5077
5078         return sector;
5079 }
5080
5081 bool ServerMap::loadSectorFull(v2s16 p2d)
5082 {
5083         DSTACK(__FUNCTION_NAME);
5084         std::string sectorsubdir = getSectorSubDir(p2d);
5085
5086         MapSector *sector = NULL;
5087
5088         JMutexAutoLock lock(m_sector_mutex);
5089
5090         try{
5091                 sector = loadSectorMeta(sectorsubdir);
5092         }
5093         catch(InvalidFilenameException &e)
5094         {
5095                 return false;
5096         }
5097         catch(FileNotGoodException &e)
5098         {
5099                 return false;
5100         }
5101         catch(std::exception &e)
5102         {
5103                 return false;
5104         }
5105         
5106         /*
5107                 Load blocks
5108         */
5109         std::vector<fs::DirListNode> list2 = fs::GetDirListing
5110                         (m_savedir+"/sectors/"+sectorsubdir);
5111         std::vector<fs::DirListNode>::iterator i2;
5112         for(i2=list2.begin(); i2!=list2.end(); i2++)
5113         {
5114                 // We want files
5115                 if(i2->dir)
5116                         continue;
5117                 try{
5118                         loadBlock(sectorsubdir, i2->name, sector);
5119                 }
5120                 catch(InvalidFilenameException &e)
5121                 {
5122                         // This catches unknown crap in directory
5123                 }
5124         }
5125         return true;
5126 }
5127
5128 void ServerMap::saveBlock(MapBlock *block)
5129 {
5130         DSTACK(__FUNCTION_NAME);
5131         /*
5132                 Dummy blocks are not written
5133         */
5134         if(block->isDummy())
5135         {
5136                 /*v3s16 p = block->getPos();
5137                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
5138                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
5139                 return;
5140         }
5141
5142         // Format used for writing
5143         u8 version = SER_FMT_VER_HIGHEST;
5144         // Get destination
5145         v3s16 p3d = block->getPos();
5146         v2s16 p2d(p3d.X, p3d.Z);
5147         createDir(m_savedir);
5148         createDir(m_savedir+"/sectors");
5149         std::string dir = getSectorDir(p2d);
5150         createDir(dir);
5151         
5152         // Block file is map/sectors/xxxxxxxx/xxxx
5153         char cc[5];
5154         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
5155         std::string fullpath = dir + "/" + cc;
5156         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5157         if(o.good() == false)
5158                 throw FileNotGoodException("Cannot open block data");
5159
5160         /*
5161                 [0] u8 serialization version
5162                 [1] data
5163         */
5164         o.write((char*)&version, 1);
5165         
5166         block->serialize(o, version);
5167
5168         /*
5169                 Versions up from 9 have block objects.
5170         */
5171         if(version >= 9)
5172         {
5173                 block->serializeObjects(o, version);
5174         }
5175         
5176         /*
5177                 Versions up from 15 have static objects.
5178         */
5179         if(version >= 15)
5180         {
5181                 block->m_static_objects.serialize(o);
5182         }
5183         
5184         // We just wrote it to the disk
5185         block->resetChangedFlag();
5186 }
5187
5188 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
5189 {
5190         DSTACK(__FUNCTION_NAME);
5191
5192         // Block file is map/sectors/xxxxxxxx/xxxx
5193         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
5194         try{
5195
5196                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5197                 if(is.good() == false)
5198                         throw FileNotGoodException("Cannot open block file");
5199                 
5200                 v3s16 p3d = getBlockPos(sectordir, blockfile);
5201                 v2s16 p2d(p3d.X, p3d.Z);
5202                 
5203                 assert(sector->getPos() == p2d);
5204                 
5205                 u8 version = SER_FMT_VER_INVALID;
5206                 is.read((char*)&version, 1);
5207
5208                 if(is.fail())
5209                         throw SerializationError("ServerMap::loadBlock(): Failed"
5210                                         " to read MapBlock version");
5211
5212                 /*u32 block_size = MapBlock::serializedLength(version);
5213                 SharedBuffer<u8> data(block_size);
5214                 is.read((char*)*data, block_size);*/
5215
5216                 // This will always return a sector because we're the server
5217                 //MapSector *sector = emergeSector(p2d);
5218
5219                 MapBlock *block = NULL;
5220                 bool created_new = false;
5221                 try{
5222                         block = sector->getBlockNoCreate(p3d.Y);
5223                 }
5224                 catch(InvalidPositionException &e)
5225                 {
5226                         block = sector->createBlankBlockNoInsert(p3d.Y);
5227                         created_new = true;
5228                 }
5229                 
5230                 // deserialize block data
5231                 block->deSerialize(is, version);
5232                 
5233                 /*
5234                         Versions up from 9 have block objects.
5235                 */
5236                 if(version >= 9)
5237                 {
5238                         block->updateObjects(is, version, NULL, 0);
5239                 }
5240
5241                 /*
5242                         Versions up from 15 have static objects.
5243                 */
5244                 if(version >= 15)
5245                 {
5246                         block->m_static_objects.deSerialize(is);
5247                 }
5248                 
5249                 if(created_new)
5250                         sector->insertBlock(block);
5251                 
5252                 /*
5253                         Convert old formats to new and save
5254                 */
5255
5256                 // Save old format blocks in new format
5257                 if(version < SER_FMT_VER_HIGHEST)
5258                 {
5259                         saveBlock(block);
5260                 }
5261                 
5262                 // We just loaded it from the disk, so it's up-to-date.
5263                 block->resetChangedFlag();
5264
5265         }
5266         catch(SerializationError &e)
5267         {
5268                 dstream<<"WARNING: Invalid block data on disk "
5269                                 "(SerializationError). Ignoring. "
5270                                 "A new one will be generated."
5271                                 <<std::endl;
5272
5273                 // TODO: Backup file; name is in fullpath.
5274         }
5275 }
5276
5277 void ServerMap::PrintInfo(std::ostream &out)
5278 {
5279         out<<"ServerMap: ";
5280 }
5281
5282 #ifndef SERVER
5283
5284 /*
5285         ClientMap
5286 */
5287
5288 ClientMap::ClientMap(
5289                 Client *client,
5290                 MapDrawControl &control,
5291                 scene::ISceneNode* parent,
5292                 scene::ISceneManager* mgr,
5293                 s32 id
5294 ):
5295         Map(dout_client),
5296         scene::ISceneNode(parent, mgr, id),
5297         m_client(client),
5298         m_control(control),
5299         m_camera_position(0,0,0),
5300         m_camera_direction(0,0,1)
5301 {
5302         m_camera_mutex.Init();
5303         assert(m_camera_mutex.IsInitialized());
5304         
5305         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
5306                         BS*1000000,BS*1000000,BS*1000000);
5307 }
5308
5309 ClientMap::~ClientMap()
5310 {
5311         /*JMutexAutoLock lock(mesh_mutex);
5312         
5313         if(mesh != NULL)
5314         {
5315                 mesh->drop();
5316                 mesh = NULL;
5317         }*/
5318 }
5319
5320 MapSector * ClientMap::emergeSector(v2s16 p2d)
5321 {
5322         DSTACK(__FUNCTION_NAME);
5323         // Check that it doesn't exist already
5324         try{
5325                 return getSectorNoGenerate(p2d);
5326         }
5327         catch(InvalidPositionException &e)
5328         {
5329         }
5330         
5331         // Create a sector
5332         ClientMapSector *sector = new ClientMapSector(this, p2d);
5333         
5334         {
5335                 JMutexAutoLock lock(m_sector_mutex);
5336                 m_sectors.insert(p2d, sector);
5337         }
5338         
5339         return sector;
5340 }
5341
5342 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
5343 {
5344         DSTACK(__FUNCTION_NAME);
5345         ClientMapSector *sector = NULL;
5346
5347         JMutexAutoLock lock(m_sector_mutex);
5348         
5349         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
5350
5351         if(n != NULL)
5352         {
5353                 sector = (ClientMapSector*)n->getValue();
5354                 assert(sector->getId() == MAPSECTOR_CLIENT);
5355         }
5356         else
5357         {
5358                 sector = new ClientMapSector(this, p2d);
5359                 {
5360                         JMutexAutoLock lock(m_sector_mutex);
5361                         m_sectors.insert(p2d, sector);
5362                 }
5363         }
5364
5365         sector->deSerialize(is);
5366 }
5367
5368 void ClientMap::OnRegisterSceneNode()
5369 {
5370         if(IsVisible)
5371         {
5372                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
5373                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
5374         }
5375
5376         ISceneNode::OnRegisterSceneNode();
5377 }
5378
5379 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
5380 {
5381         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
5382         DSTACK(__FUNCTION_NAME);
5383
5384         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
5385
5386         /*
5387                 Get time for measuring timeout.
5388                 
5389                 Measuring time is very useful for long delays when the
5390                 machine is swapping a lot.
5391         */
5392         int time1 = time(0);
5393
5394         //u32 daynight_ratio = m_client->getDayNightRatio();
5395
5396         m_camera_mutex.Lock();
5397         v3f camera_position = m_camera_position;
5398         v3f camera_direction = m_camera_direction;
5399         m_camera_mutex.Unlock();
5400
5401         /*
5402                 Get all blocks and draw all visible ones
5403         */
5404
5405         v3s16 cam_pos_nodes(
5406                         camera_position.X / BS,
5407                         camera_position.Y / BS,
5408                         camera_position.Z / BS);
5409
5410         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
5411
5412         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
5413         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
5414
5415         // Take a fair amount as we will be dropping more out later
5416         v3s16 p_blocks_min(
5417                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
5418                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
5419                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
5420         v3s16 p_blocks_max(
5421                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
5422                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
5423                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
5424         
5425         u32 vertex_count = 0;
5426         
5427         // For limiting number of mesh updates per frame
5428         u32 mesh_update_count = 0;
5429         
5430         u32 blocks_would_have_drawn = 0;
5431         u32 blocks_drawn = 0;
5432
5433         //NOTE: The sectors map should be locked but we're not doing it
5434         // because it'd cause too much delays
5435
5436         int timecheck_counter = 0;
5437         core::map<v2s16, MapSector*>::Iterator si;
5438         si = m_sectors.getIterator();
5439         for(; si.atEnd() == false; si++)
5440         {
5441                 {
5442                         timecheck_counter++;
5443                         if(timecheck_counter > 50)
5444                         {
5445                                 timecheck_counter = 0;
5446                                 int time2 = time(0);
5447                                 if(time2 > time1 + 4)
5448                                 {
5449                                         dstream<<"ClientMap::renderMap(): "
5450                                                 "Rendering takes ages, returning."
5451                                                 <<std::endl;
5452                                         return;
5453                                 }
5454                         }
5455                 }
5456
5457                 MapSector *sector = si.getNode()->getValue();
5458                 v2s16 sp = sector->getPos();
5459                 
5460                 if(m_control.range_all == false)
5461                 {
5462                         if(sp.X < p_blocks_min.X
5463                         || sp.X > p_blocks_max.X
5464                         || sp.Y < p_blocks_min.Z
5465                         || sp.Y > p_blocks_max.Z)
5466                                 continue;
5467                 }
5468
5469                 core::list< MapBlock * > sectorblocks;
5470                 sector->getBlocks(sectorblocks);
5471                 
5472                 /*
5473                         Draw blocks
5474                 */
5475
5476                 core::list< MapBlock * >::Iterator i;
5477                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5478                 {
5479                         MapBlock *block = *i;
5480
5481                         /*
5482                                 Compare block position to camera position, skip
5483                                 if not seen on display
5484                         */
5485                         
5486                         float range = 100000 * BS;
5487                         if(m_control.range_all == false)
5488                                 range = m_control.wanted_range * BS;
5489                         
5490                         float d = 0.0;
5491                         if(isBlockInSight(block->getPos(), camera_position,
5492                                         camera_direction, range, &d) == false)
5493                         {
5494                                 continue;
5495                         }
5496                         
5497                         // This is ugly (spherical distance limit?)
5498                         /*if(m_control.range_all == false &&
5499                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
5500                                 continue;*/
5501
5502 #if 1
5503                         /*
5504                                 Update expired mesh (used for day/night change)
5505
5506                                 It doesn't work exactly like it should now with the
5507                                 tasked mesh update but whatever.
5508                         */
5509
5510                         bool mesh_expired = false;
5511                         
5512                         {
5513                                 JMutexAutoLock lock(block->mesh_mutex);
5514
5515                                 mesh_expired = block->getMeshExpired();
5516
5517                                 // Mesh has not been expired and there is no mesh:
5518                                 // block has no content
5519                                 if(block->mesh == NULL && mesh_expired == false)
5520                                         continue;
5521                         }
5522
5523                         f32 faraway = BS*50;
5524                         //f32 faraway = m_control.wanted_range * BS;
5525                         
5526                         /*
5527                                 This has to be done with the mesh_mutex unlocked
5528                         */
5529                         // Pretty random but this should work somewhat nicely
5530                         if(mesh_expired && (
5531                                         (mesh_update_count < 3
5532                                                 && (d < faraway || mesh_update_count < 2)
5533                                         )
5534                                         || 
5535                                         (m_control.range_all && mesh_update_count < 20)
5536                                 )
5537                         )
5538                         /*if(mesh_expired && mesh_update_count < 6
5539                                         && (d < faraway || mesh_update_count < 3))*/
5540                         {
5541                                 mesh_update_count++;
5542
5543                                 // Mesh has been expired: generate new mesh
5544                                 //block->updateMesh(daynight_ratio);
5545                                 m_client->addUpdateMeshTask(block->getPos());
5546
5547                                 mesh_expired = false;
5548                         }
5549                         
5550 #endif
5551                         /*
5552                                 Draw the faces of the block
5553                         */
5554                         {
5555                                 JMutexAutoLock lock(block->mesh_mutex);
5556
5557                                 scene::SMesh *mesh = block->mesh;
5558
5559                                 if(mesh == NULL)
5560                                         continue;
5561                                 
5562                                 blocks_would_have_drawn++;
5563                                 if(blocks_drawn >= m_control.wanted_max_blocks
5564                                                 && m_control.range_all == false
5565                                                 && d > m_control.wanted_min_range * BS)
5566                                         continue;
5567                                 blocks_drawn++;
5568
5569                                 u32 c = mesh->getMeshBufferCount();
5570
5571                                 for(u32 i=0; i<c; i++)
5572                                 {
5573                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
5574                                         const video::SMaterial& material = buf->getMaterial();
5575                                         video::IMaterialRenderer* rnd =
5576                                                         driver->getMaterialRenderer(material.MaterialType);
5577                                         bool transparent = (rnd && rnd->isTransparent());
5578                                         // Render transparent on transparent pass and likewise.
5579                                         if(transparent == is_transparent_pass)
5580                                         {
5581                                                 /*
5582                                                         This *shouldn't* hurt too much because Irrlicht
5583                                                         doesn't change opengl textures if the old
5584                                                         material is set again.
5585                                                 */
5586                                                 driver->setMaterial(buf->getMaterial());
5587                                                 driver->drawMeshBuffer(buf);
5588                                                 vertex_count += buf->getVertexCount();
5589                                         }
5590                                 }
5591                         }
5592                 } // foreach sectorblocks
5593         }
5594         
5595         m_control.blocks_drawn = blocks_drawn;
5596         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
5597
5598         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
5599                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
5600 }
5601
5602 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
5603                 core::map<v3s16, MapBlock*> *affected_blocks)
5604 {
5605         bool changed = false;
5606         /*
5607                 Add it to all blocks touching it
5608         */
5609         v3s16 dirs[7] = {
5610                 v3s16(0,0,0), // this
5611                 v3s16(0,0,1), // back
5612                 v3s16(0,1,0), // top
5613                 v3s16(1,0,0), // right
5614                 v3s16(0,0,-1), // front
5615                 v3s16(0,-1,0), // bottom
5616                 v3s16(-1,0,0), // left
5617         };
5618         for(u16 i=0; i<7; i++)
5619         {
5620                 v3s16 p2 = p + dirs[i];
5621                 // Block position of neighbor (or requested) node
5622                 v3s16 blockpos = getNodeBlockPos(p2);
5623                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5624                 if(blockref == NULL)
5625                         continue;
5626                 // Relative position of requested node
5627                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5628                 if(blockref->setTempMod(relpos, mod))
5629                 {
5630                         changed = true;
5631                 }
5632         }
5633         if(changed && affected_blocks!=NULL)
5634         {
5635                 for(u16 i=0; i<7; i++)
5636                 {
5637                         v3s16 p2 = p + dirs[i];
5638                         // Block position of neighbor (or requested) node
5639                         v3s16 blockpos = getNodeBlockPos(p2);
5640                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5641                         if(blockref == NULL)
5642                                 continue;
5643                         affected_blocks->insert(blockpos, blockref);
5644                 }
5645         }
5646         return changed;
5647 }
5648
5649 bool ClientMap::clearTempMod(v3s16 p,
5650                 core::map<v3s16, MapBlock*> *affected_blocks)
5651 {
5652         bool changed = false;
5653         v3s16 dirs[7] = {
5654                 v3s16(0,0,0), // this
5655                 v3s16(0,0,1), // back
5656                 v3s16(0,1,0), // top
5657                 v3s16(1,0,0), // right
5658                 v3s16(0,0,-1), // front
5659                 v3s16(0,-1,0), // bottom
5660                 v3s16(-1,0,0), // left
5661         };
5662         for(u16 i=0; i<7; i++)
5663         {
5664                 v3s16 p2 = p + dirs[i];
5665                 // Block position of neighbor (or requested) node
5666                 v3s16 blockpos = getNodeBlockPos(p2);
5667                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5668                 if(blockref == NULL)
5669                         continue;
5670                 // Relative position of requested node
5671                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5672                 if(blockref->clearTempMod(relpos))
5673                 {
5674                         changed = true;
5675                 }
5676         }
5677         if(changed && affected_blocks!=NULL)
5678         {
5679                 for(u16 i=0; i<7; i++)
5680                 {
5681                         v3s16 p2 = p + dirs[i];
5682                         // Block position of neighbor (or requested) node
5683                         v3s16 blockpos = getNodeBlockPos(p2);
5684                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5685                         if(blockref == NULL)
5686                                 continue;
5687                         affected_blocks->insert(blockpos, blockref);
5688                 }
5689         }
5690         return changed;
5691 }
5692
5693 void ClientMap::expireMeshes(bool only_daynight_diffed)
5694 {
5695         TimeTaker timer("expireMeshes()");
5696
5697         core::map<v2s16, MapSector*>::Iterator si;
5698         si = m_sectors.getIterator();
5699         for(; si.atEnd() == false; si++)
5700         {
5701                 MapSector *sector = si.getNode()->getValue();
5702
5703                 core::list< MapBlock * > sectorblocks;
5704                 sector->getBlocks(sectorblocks);
5705                 
5706                 core::list< MapBlock * >::Iterator i;
5707                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5708                 {
5709                         MapBlock *block = *i;
5710
5711                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
5712                         {
5713                                 continue;
5714                         }
5715                         
5716                         {
5717                                 JMutexAutoLock lock(block->mesh_mutex);
5718                                 if(block->mesh != NULL)
5719                                 {
5720                                         /*block->mesh->drop();
5721                                         block->mesh = NULL;*/
5722                                         block->setMeshExpired(true);
5723                                 }
5724                         }
5725                 }
5726         }
5727 }
5728
5729 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
5730 {
5731         assert(mapType() == MAPTYPE_CLIENT);
5732
5733         try{
5734                 v3s16 p = blockpos + v3s16(0,0,0);
5735                 MapBlock *b = getBlockNoCreate(p);
5736                 b->updateMesh(daynight_ratio);
5737                 //b->setMeshExpired(true);
5738         }
5739         catch(InvalidPositionException &e){}
5740         // Leading edge
5741         try{
5742                 v3s16 p = blockpos + v3s16(-1,0,0);
5743                 MapBlock *b = getBlockNoCreate(p);
5744                 b->updateMesh(daynight_ratio);
5745                 //b->setMeshExpired(true);
5746         }
5747         catch(InvalidPositionException &e){}
5748         try{
5749                 v3s16 p = blockpos + v3s16(0,-1,0);
5750                 MapBlock *b = getBlockNoCreate(p);
5751                 b->updateMesh(daynight_ratio);
5752                 //b->setMeshExpired(true);
5753         }
5754         catch(InvalidPositionException &e){}
5755         try{
5756                 v3s16 p = blockpos + v3s16(0,0,-1);
5757                 MapBlock *b = getBlockNoCreate(p);
5758                 b->updateMesh(daynight_ratio);
5759                 //b->setMeshExpired(true);
5760         }
5761         catch(InvalidPositionException &e){}
5762 }
5763
5764 #if 0
5765 /*
5766         Update mesh of block in which the node is, and if the node is at the
5767         leading edge, update the appropriate leading blocks too.
5768 */
5769 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
5770 {
5771         v3s16 dirs[4] = {
5772                 v3s16(0,0,0),
5773                 v3s16(-1,0,0),
5774                 v3s16(0,-1,0),
5775                 v3s16(0,0,-1),
5776         };
5777         v3s16 blockposes[4];
5778         for(u32 i=0; i<4; i++)
5779         {
5780                 v3s16 np = nodepos + dirs[i];
5781                 blockposes[i] = getNodeBlockPos(np);
5782                 // Don't update mesh of block if it has been done already
5783                 bool already_updated = false;
5784                 for(u32 j=0; j<i; j++)
5785                 {
5786                         if(blockposes[j] == blockposes[i])
5787                         {
5788                                 already_updated = true;
5789                                 break;
5790                         }
5791                 }
5792                 if(already_updated)
5793                         continue;
5794                 // Update mesh
5795                 MapBlock *b = getBlockNoCreate(blockposes[i]);
5796                 b->updateMesh(daynight_ratio);
5797         }
5798 }
5799 #endif
5800
5801 void ClientMap::PrintInfo(std::ostream &out)
5802 {
5803         out<<"ClientMap: ";
5804 }
5805
5806 #endif // !SERVER
5807
5808 /*
5809         MapVoxelManipulator
5810 */
5811
5812 MapVoxelManipulator::MapVoxelManipulator(Map *map)
5813 {
5814         m_map = map;
5815 }
5816
5817 MapVoxelManipulator::~MapVoxelManipulator()
5818 {
5819         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
5820                         <<std::endl;*/
5821 }
5822
5823 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5824 {
5825         TimeTaker timer1("emerge", &emerge_time);
5826
5827         // Units of these are MapBlocks
5828         v3s16 p_min = getNodeBlockPos(a.MinEdge);
5829         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
5830
5831         VoxelArea block_area_nodes
5832                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5833
5834         addArea(block_area_nodes);
5835
5836         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5837         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5838         for(s32 x=p_min.X; x<=p_max.X; x++)
5839         {
5840                 v3s16 p(x,y,z);
5841                 core::map<v3s16, bool>::Node *n;
5842                 n = m_loaded_blocks.find(p);
5843                 if(n != NULL)
5844                         continue;
5845                 
5846                 bool block_data_inexistent = false;
5847                 try
5848                 {
5849                         TimeTaker timer1("emerge load", &emerge_load_time);
5850
5851                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
5852                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5853                                         <<" wanted area: ";
5854                         a.print(dstream);
5855                         dstream<<std::endl;*/
5856                         
5857                         MapBlock *block = m_map->getBlockNoCreate(p);
5858                         if(block->isDummy())
5859                                 block_data_inexistent = true;
5860                         else
5861                                 block->copyTo(*this);
5862                 }
5863                 catch(InvalidPositionException &e)
5864                 {
5865                         block_data_inexistent = true;
5866                 }
5867
5868                 if(block_data_inexistent)
5869                 {
5870                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5871                         // Fill with VOXELFLAG_INEXISTENT
5872                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
5873                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
5874                         {
5875                                 s32 i = m_area.index(a.MinEdge.X,y,z);
5876                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
5877                         }
5878                 }
5879
5880                 m_loaded_blocks.insert(p, !block_data_inexistent);
5881         }
5882
5883         //dstream<<"emerge done"<<std::endl;
5884 }
5885
5886 /*
5887         SUGG: Add an option to only update eg. water and air nodes.
5888               This will make it interfere less with important stuff if
5889                   run on background.
5890 */
5891 void MapVoxelManipulator::blitBack
5892                 (core::map<v3s16, MapBlock*> & modified_blocks)
5893 {
5894         if(m_area.getExtent() == v3s16(0,0,0))
5895                 return;
5896         
5897         //TimeTaker timer1("blitBack");
5898
5899         /*dstream<<"blitBack(): m_loaded_blocks.size()="
5900                         <<m_loaded_blocks.size()<<std::endl;*/
5901         
5902         /*
5903                 Initialize block cache
5904         */
5905         v3s16 blockpos_last;
5906         MapBlock *block = NULL;
5907         bool block_checked_in_modified = false;
5908
5909         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
5910         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
5911         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
5912         {
5913                 v3s16 p(x,y,z);
5914
5915                 u8 f = m_flags[m_area.index(p)];
5916                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
5917                         continue;
5918
5919                 MapNode &n = m_data[m_area.index(p)];
5920                         
5921                 v3s16 blockpos = getNodeBlockPos(p);
5922                 
5923                 try
5924                 {
5925                         // Get block
5926                         if(block == NULL || blockpos != blockpos_last){
5927                                 block = m_map->getBlockNoCreate(blockpos);
5928                                 blockpos_last = blockpos;
5929                                 block_checked_in_modified = false;
5930                         }
5931                         
5932                         // Calculate relative position in block
5933                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
5934
5935                         // Don't continue if nothing has changed here
5936                         if(block->getNode(relpos) == n)
5937                                 continue;
5938
5939                         //m_map->setNode(m_area.MinEdge + p, n);
5940                         block->setNode(relpos, n);
5941                         
5942                         /*
5943                                 Make sure block is in modified_blocks
5944                         */
5945                         if(block_checked_in_modified == false)
5946                         {
5947                                 modified_blocks[blockpos] = block;
5948                                 block_checked_in_modified = true;
5949                         }
5950                 }
5951                 catch(InvalidPositionException &e)
5952                 {
5953                 }
5954         }
5955 }
5956
5957 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
5958                 MapVoxelManipulator(map)
5959 {
5960 }
5961
5962 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
5963 {
5964 }
5965
5966 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5967 {
5968         // Just create the area so that it can be pointed to
5969         VoxelManipulator::emerge(a, caller_id);
5970 }
5971
5972 void ManualMapVoxelManipulator::initialEmerge(
5973                 v3s16 blockpos_min, v3s16 blockpos_max)
5974 {
5975         TimeTaker timer1("initialEmerge", &emerge_time);
5976
5977         // Units of these are MapBlocks
5978         v3s16 p_min = blockpos_min;
5979         v3s16 p_max = blockpos_max;
5980
5981         VoxelArea block_area_nodes
5982                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5983         
5984         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
5985         if(size_MB >= 1)
5986         {
5987                 dstream<<"initialEmerge: area: ";
5988                 block_area_nodes.print(dstream);
5989                 dstream<<" ("<<size_MB<<"MB)";
5990                 dstream<<std::endl;
5991         }
5992
5993         addArea(block_area_nodes);
5994
5995         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5996         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5997         for(s32 x=p_min.X; x<=p_max.X; x++)
5998         {
5999                 v3s16 p(x,y,z);
6000                 core::map<v3s16, bool>::Node *n;
6001                 n = m_loaded_blocks.find(p);
6002                 if(n != NULL)
6003                         continue;
6004                 
6005                 bool block_data_inexistent = false;
6006                 try
6007                 {
6008                         TimeTaker timer1("emerge load", &emerge_load_time);
6009
6010                         MapBlock *block = m_map->getBlockNoCreate(p);
6011                         if(block->isDummy())
6012                                 block_data_inexistent = true;
6013                         else
6014                                 block->copyTo(*this);
6015                 }
6016                 catch(InvalidPositionException &e)
6017                 {
6018                         block_data_inexistent = true;
6019                 }
6020
6021                 if(block_data_inexistent)
6022                 {
6023                         /*
6024                                 Mark area inexistent
6025                         */
6026                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6027                         // Fill with VOXELFLAG_INEXISTENT
6028                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
6029                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
6030                         {
6031                                 s32 i = m_area.index(a.MinEdge.X,y,z);
6032                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
6033                         }
6034                 }
6035
6036                 m_loaded_blocks.insert(p, !block_data_inexistent);
6037         }
6038 }
6039
6040 void ManualMapVoxelManipulator::blitBackAll(
6041                 core::map<v3s16, MapBlock*> * modified_blocks)
6042 {
6043         if(m_area.getExtent() == v3s16(0,0,0))
6044                 return;
6045         
6046         /*
6047                 Copy data of all blocks
6048         */
6049         for(core::map<v3s16, bool>::Iterator
6050                         i = m_loaded_blocks.getIterator();
6051                         i.atEnd() == false; i++)
6052         {
6053                 bool existed = i.getNode()->getValue();
6054                 if(existed == false)
6055                         continue;
6056                 v3s16 p = i.getNode()->getKey();
6057                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
6058                 if(block == NULL)
6059                 {
6060                         dstream<<"WARNING: "<<__FUNCTION_NAME
6061                                         <<": got NULL block "
6062                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
6063                                         <<std::endl;
6064                         continue;
6065                 }
6066
6067                 block->copyFrom(*this);
6068
6069                 if(modified_blocks)
6070                         modified_blocks->insert(p, block);
6071         }
6072 }
6073
6074 //END