mapgen stuff
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 #include "serverobject.h"
31 #include "content_mapnode.h"
32
33 extern "C" {
34         #include "sqlite3.h"
35 }
36 /*
37         SQLite format specification:
38         - Initially only replaces sectors/ and sectors2/
39 */
40
41 /*
42         Map
43 */
44
45 Map::Map(std::ostream &dout):
46         m_dout(dout),
47         m_sector_cache(NULL)
48 {
49         /*m_sector_mutex.Init();
50         assert(m_sector_mutex.IsInitialized());*/
51 }
52
53 Map::~Map()
54 {
55         /*
56                 Free all MapSectors
57         */
58         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
59         for(; i.atEnd() == false; i++)
60         {
61                 MapSector *sector = i.getNode()->getValue();
62                 delete sector;
63         }
64 }
65
66 void Map::addEventReceiver(MapEventReceiver *event_receiver)
67 {
68         m_event_receivers.insert(event_receiver, false);
69 }
70
71 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
72 {
73         if(m_event_receivers.find(event_receiver) == NULL)
74                 return;
75         m_event_receivers.remove(event_receiver);
76 }
77
78 void Map::dispatchEvent(MapEditEvent *event)
79 {
80         for(core::map<MapEventReceiver*, bool>::Iterator
81                         i = m_event_receivers.getIterator();
82                         i.atEnd()==false; i++)
83         {
84                 MapEventReceiver* event_receiver = i.getNode()->getKey();
85                 event_receiver->onMapEditEvent(event);
86         }
87 }
88
89 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
90 {
91         if(m_sector_cache != NULL && p == m_sector_cache_p){
92                 MapSector * sector = m_sector_cache;
93                 return sector;
94         }
95         
96         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
97         
98         if(n == NULL)
99                 return NULL;
100         
101         MapSector *sector = n->getValue();
102         
103         // Cache the last result
104         m_sector_cache_p = p;
105         m_sector_cache = sector;
106
107         return sector;
108 }
109
110 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
111 {
112         return getSectorNoGenerateNoExNoLock(p);
113 }
114
115 MapSector * Map::getSectorNoGenerate(v2s16 p)
116 {
117         MapSector *sector = getSectorNoGenerateNoEx(p);
118         if(sector == NULL)
119                 throw InvalidPositionException();
120         
121         return sector;
122 }
123
124 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
125 {       
126         v2s16 p2d(p3d.X, p3d.Z);
127         MapSector * sector = getSectorNoGenerate(p2d);
128
129         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
130
131         return block;
132 }
133
134 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
135 {
136         try
137         {
138                 v2s16 p2d(p3d.X, p3d.Z);
139                 MapSector * sector = getSectorNoGenerate(p2d);
140                 MapBlock *block = sector->getBlockNoCreate(p3d.Y);
141                 return block;
142         }
143         catch(InvalidPositionException &e)
144         {
145                 return NULL;
146         }
147 }
148
149 /*MapBlock * Map::getBlockCreate(v3s16 p3d)
150 {
151         v2s16 p2d(p3d.X, p3d.Z);
152         MapSector * sector = getSectorCreate(p2d);
153         assert(sector);
154         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
155         if(block)
156                 return block;
157         block = sector->createBlankBlock(p3d.Y);
158         return block;
159 }*/
160
161 bool Map::isNodeUnderground(v3s16 p)
162 {
163         v3s16 blockpos = getNodeBlockPos(p);
164         try{
165                 MapBlock * block = getBlockNoCreate(blockpos);
166                 return block->getIsUnderground();
167         }
168         catch(InvalidPositionException &e)
169         {
170                 return false;
171         }
172 }
173
174 /*
175         Goes recursively through the neighbours of the node.
176
177         Alters only transparent nodes.
178
179         If the lighting of the neighbour is lower than the lighting of
180         the node was (before changing it to 0 at the step before), the
181         lighting of the neighbour is set to 0 and then the same stuff
182         repeats for the neighbour.
183
184         The ending nodes of the routine are stored in light_sources.
185         This is useful when a light is removed. In such case, this
186         routine can be called for the light node and then again for
187         light_sources to re-light the area without the removed light.
188
189         values of from_nodes are lighting values.
190 */
191 void Map::unspreadLight(enum LightBank bank,
192                 core::map<v3s16, u8> & from_nodes,
193                 core::map<v3s16, bool> & light_sources,
194                 core::map<v3s16, MapBlock*>  & modified_blocks)
195 {
196         v3s16 dirs[6] = {
197                 v3s16(0,0,1), // back
198                 v3s16(0,1,0), // top
199                 v3s16(1,0,0), // right
200                 v3s16(0,0,-1), // front
201                 v3s16(0,-1,0), // bottom
202                 v3s16(-1,0,0), // left
203         };
204         
205         if(from_nodes.size() == 0)
206                 return;
207         
208         u32 blockchangecount = 0;
209
210         core::map<v3s16, u8> unlighted_nodes;
211         core::map<v3s16, u8>::Iterator j;
212         j = from_nodes.getIterator();
213
214         /*
215                 Initialize block cache
216         */
217         v3s16 blockpos_last;
218         MapBlock *block = NULL;
219         // Cache this a bit, too
220         bool block_checked_in_modified = false;
221         
222         for(; j.atEnd() == false; j++)
223         {
224                 v3s16 pos = j.getNode()->getKey();
225                 v3s16 blockpos = getNodeBlockPos(pos);
226                 
227                 // Only fetch a new block if the block position has changed
228                 try{
229                         if(block == NULL || blockpos != blockpos_last){
230                                 block = getBlockNoCreate(blockpos);
231                                 blockpos_last = blockpos;
232
233                                 block_checked_in_modified = false;
234                                 blockchangecount++;
235                         }
236                 }
237                 catch(InvalidPositionException &e)
238                 {
239                         continue;
240                 }
241
242                 if(block->isDummy())
243                         continue;
244
245                 // Calculate relative position in block
246                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
247
248                 // Get node straight from the block
249                 MapNode n = block->getNode(relpos);
250
251                 u8 oldlight = j.getNode()->getValue();
252
253                 // Loop through 6 neighbors
254                 for(u16 i=0; i<6; i++)
255                 {
256                         // Get the position of the neighbor node
257                         v3s16 n2pos = pos + dirs[i];
258
259                         // Get the block where the node is located
260                         v3s16 blockpos = getNodeBlockPos(n2pos);
261
262                         try
263                         {
264                                 // Only fetch a new block if the block position has changed
265                                 try{
266                                         if(block == NULL || blockpos != blockpos_last){
267                                                 block = getBlockNoCreate(blockpos);
268                                                 blockpos_last = blockpos;
269
270                                                 block_checked_in_modified = false;
271                                                 blockchangecount++;
272                                         }
273                                 }
274                                 catch(InvalidPositionException &e)
275                                 {
276                                         continue;
277                                 }
278
279                                 // Calculate relative position in block
280                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
281                                 // Get node straight from the block
282                                 MapNode n2 = block->getNode(relpos);
283
284                                 bool changed = false;
285
286                                 //TODO: Optimize output by optimizing light_sources?
287
288                                 /*
289                                         If the neighbor is dimmer than what was specified
290                                         as oldlight (the light of the previous node)
291                                 */
292                                 if(n2.getLight(bank) < oldlight)
293                                 {
294                                         /*
295                                                 And the neighbor is transparent and it has some light
296                                         */
297                                         if(n2.light_propagates() && n2.getLight(bank) != 0)
298                                         {
299                                                 /*
300                                                         Set light to 0 and add to queue
301                                                 */
302
303                                                 u8 current_light = n2.getLight(bank);
304                                                 n2.setLight(bank, 0);
305                                                 block->setNode(relpos, n2);
306
307                                                 unlighted_nodes.insert(n2pos, current_light);
308                                                 changed = true;
309
310                                                 /*
311                                                         Remove from light_sources if it is there
312                                                         NOTE: This doesn't happen nearly at all
313                                                 */
314                                                 /*if(light_sources.find(n2pos))
315                                                 {
316                                                         std::cout<<"Removed from light_sources"<<std::endl;
317                                                         light_sources.remove(n2pos);
318                                                 }*/
319                                         }
320
321                                         /*// DEBUG
322                                         if(light_sources.find(n2pos) != NULL)
323                                                 light_sources.remove(n2pos);*/
324                                 }
325                                 else{
326                                         light_sources.insert(n2pos, true);
327                                 }
328
329                                 // Add to modified_blocks
330                                 if(changed == true && block_checked_in_modified == false)
331                                 {
332                                         // If the block is not found in modified_blocks, add.
333                                         if(modified_blocks.find(blockpos) == NULL)
334                                         {
335                                                 modified_blocks.insert(blockpos, block);
336                                         }
337                                         block_checked_in_modified = true;
338                                 }
339                         }
340                         catch(InvalidPositionException &e)
341                         {
342                                 continue;
343                         }
344                 }
345         }
346
347         /*dstream<<"unspreadLight(): Changed block "
348                         <<blockchangecount<<" times"
349                         <<" for "<<from_nodes.size()<<" nodes"
350                         <<std::endl;*/
351
352         if(unlighted_nodes.size() > 0)
353                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
354 }
355
356 /*
357         A single-node wrapper of the above
358 */
359 void Map::unLightNeighbors(enum LightBank bank,
360                 v3s16 pos, u8 lightwas,
361                 core::map<v3s16, bool> & light_sources,
362                 core::map<v3s16, MapBlock*>  & modified_blocks)
363 {
364         core::map<v3s16, u8> from_nodes;
365         from_nodes.insert(pos, lightwas);
366
367         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
368 }
369
370 /*
371         Lights neighbors of from_nodes, collects all them and then
372         goes on recursively.
373 */
374 void Map::spreadLight(enum LightBank bank,
375                 core::map<v3s16, bool> & from_nodes,
376                 core::map<v3s16, MapBlock*> & modified_blocks)
377 {
378         const v3s16 dirs[6] = {
379                 v3s16(0,0,1), // back
380                 v3s16(0,1,0), // top
381                 v3s16(1,0,0), // right
382                 v3s16(0,0,-1), // front
383                 v3s16(0,-1,0), // bottom
384                 v3s16(-1,0,0), // left
385         };
386
387         if(from_nodes.size() == 0)
388                 return;
389
390         u32 blockchangecount = 0;
391
392         core::map<v3s16, bool> lighted_nodes;
393         core::map<v3s16, bool>::Iterator j;
394         j = from_nodes.getIterator();
395
396         /*
397                 Initialize block cache
398         */
399         v3s16 blockpos_last;
400         MapBlock *block = NULL;
401         // Cache this a bit, too
402         bool block_checked_in_modified = false;
403
404         for(; j.atEnd() == false; j++)
405         //for(; j != from_nodes.end(); j++)
406         {
407                 v3s16 pos = j.getNode()->getKey();
408                 //v3s16 pos = *j;
409                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
410                 v3s16 blockpos = getNodeBlockPos(pos);
411
412                 // Only fetch a new block if the block position has changed
413                 try{
414                         if(block == NULL || blockpos != blockpos_last){
415                                 block = getBlockNoCreate(blockpos);
416                                 blockpos_last = blockpos;
417
418                                 block_checked_in_modified = false;
419                                 blockchangecount++;
420                         }
421                 }
422                 catch(InvalidPositionException &e)
423                 {
424                         continue;
425                 }
426
427                 if(block->isDummy())
428                         continue;
429
430                 // Calculate relative position in block
431                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
432
433                 // Get node straight from the block
434                 MapNode n = block->getNode(relpos);
435
436                 u8 oldlight = n.getLight(bank);
437                 u8 newlight = diminish_light(oldlight);
438
439                 // Loop through 6 neighbors
440                 for(u16 i=0; i<6; i++){
441                         // Get the position of the neighbor node
442                         v3s16 n2pos = pos + dirs[i];
443
444                         // Get the block where the node is located
445                         v3s16 blockpos = getNodeBlockPos(n2pos);
446
447                         try
448                         {
449                                 // Only fetch a new block if the block position has changed
450                                 try{
451                                         if(block == NULL || blockpos != blockpos_last){
452                                                 block = getBlockNoCreate(blockpos);
453                                                 blockpos_last = blockpos;
454
455                                                 block_checked_in_modified = false;
456                                                 blockchangecount++;
457                                         }
458                                 }
459                                 catch(InvalidPositionException &e)
460                                 {
461                                         continue;
462                                 }
463
464                                 // Calculate relative position in block
465                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
466                                 // Get node straight from the block
467                                 MapNode n2 = block->getNode(relpos);
468
469                                 bool changed = false;
470                                 /*
471                                         If the neighbor is brighter than the current node,
472                                         add to list (it will light up this node on its turn)
473                                 */
474                                 if(n2.getLight(bank) > undiminish_light(oldlight))
475                                 {
476                                         lighted_nodes.insert(n2pos, true);
477                                         //lighted_nodes.push_back(n2pos);
478                                         changed = true;
479                                 }
480                                 /*
481                                         If the neighbor is dimmer than how much light this node
482                                         would spread on it, add to list
483                                 */
484                                 if(n2.getLight(bank) < newlight)
485                                 {
486                                         if(n2.light_propagates())
487                                         {
488                                                 n2.setLight(bank, newlight);
489                                                 block->setNode(relpos, n2);
490                                                 lighted_nodes.insert(n2pos, true);
491                                                 //lighted_nodes.push_back(n2pos);
492                                                 changed = true;
493                                         }
494                                 }
495
496                                 // Add to modified_blocks
497                                 if(changed == true && block_checked_in_modified == false)
498                                 {
499                                         // If the block is not found in modified_blocks, add.
500                                         if(modified_blocks.find(blockpos) == NULL)
501                                         {
502                                                 modified_blocks.insert(blockpos, block);
503                                         }
504                                         block_checked_in_modified = true;
505                                 }
506                         }
507                         catch(InvalidPositionException &e)
508                         {
509                                 continue;
510                         }
511                 }
512         }
513
514         /*dstream<<"spreadLight(): Changed block "
515                         <<blockchangecount<<" times"
516                         <<" for "<<from_nodes.size()<<" nodes"
517                         <<std::endl;*/
518
519         if(lighted_nodes.size() > 0)
520                 spreadLight(bank, lighted_nodes, modified_blocks);
521 }
522
523 /*
524         A single-node source variation of the above.
525 */
526 void Map::lightNeighbors(enum LightBank bank,
527                 v3s16 pos,
528                 core::map<v3s16, MapBlock*> & modified_blocks)
529 {
530         core::map<v3s16, bool> from_nodes;
531         from_nodes.insert(pos, true);
532         spreadLight(bank, from_nodes, modified_blocks);
533 }
534
535 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
536 {
537         v3s16 dirs[6] = {
538                 v3s16(0,0,1), // back
539                 v3s16(0,1,0), // top
540                 v3s16(1,0,0), // right
541                 v3s16(0,0,-1), // front
542                 v3s16(0,-1,0), // bottom
543                 v3s16(-1,0,0), // left
544         };
545
546         u8 brightest_light = 0;
547         v3s16 brightest_pos(0,0,0);
548         bool found_something = false;
549
550         // Loop through 6 neighbors
551         for(u16 i=0; i<6; i++){
552                 // Get the position of the neighbor node
553                 v3s16 n2pos = p + dirs[i];
554                 MapNode n2;
555                 try{
556                         n2 = getNode(n2pos);
557                 }
558                 catch(InvalidPositionException &e)
559                 {
560                         continue;
561                 }
562                 if(n2.getLight(bank) > brightest_light || found_something == false){
563                         brightest_light = n2.getLight(bank);
564                         brightest_pos = n2pos;
565                         found_something = true;
566                 }
567         }
568
569         if(found_something == false)
570                 throw InvalidPositionException();
571
572         return brightest_pos;
573 }
574
575 /*
576         Propagates sunlight down from a node.
577         Starting point gets sunlight.
578
579         Returns the lowest y value of where the sunlight went.
580
581         Mud is turned into grass in where the sunlight stops.
582 */
583 s16 Map::propagateSunlight(v3s16 start,
584                 core::map<v3s16, MapBlock*> & modified_blocks)
585 {
586         s16 y = start.Y;
587         for(; ; y--)
588         {
589                 v3s16 pos(start.X, y, start.Z);
590
591                 v3s16 blockpos = getNodeBlockPos(pos);
592                 MapBlock *block;
593                 try{
594                         block = getBlockNoCreate(blockpos);
595                 }
596                 catch(InvalidPositionException &e)
597                 {
598                         break;
599                 }
600
601                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
602                 MapNode n = block->getNode(relpos);
603
604                 if(n.sunlight_propagates())
605                 {
606                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
607                         block->setNode(relpos, n);
608
609                         modified_blocks.insert(blockpos, block);
610                 }
611                 else
612                 {
613                         /*// Turn mud into grass
614                         if(n.d == CONTENT_MUD)
615                         {
616                                 n.d = CONTENT_GRASS;
617                                 block->setNode(relpos, n);
618                                 modified_blocks.insert(blockpos, block);
619                         }*/
620
621                         // Sunlight goes no further
622                         break;
623                 }
624         }
625         return y + 1;
626 }
627
628 void Map::updateLighting(enum LightBank bank,
629                 core::map<v3s16, MapBlock*> & a_blocks,
630                 core::map<v3s16, MapBlock*> & modified_blocks)
631 {
632         /*m_dout<<DTIME<<"Map::updateLighting(): "
633                         <<a_blocks.size()<<" blocks."<<std::endl;*/
634
635         //TimeTaker timer("updateLighting");
636
637         // For debugging
638         //bool debug=true;
639         //u32 count_was = modified_blocks.size();
640
641         core::map<v3s16, MapBlock*> blocks_to_update;
642
643         core::map<v3s16, bool> light_sources;
644
645         core::map<v3s16, u8> unlight_from;
646
647         core::map<v3s16, MapBlock*>::Iterator i;
648         i = a_blocks.getIterator();
649         for(; i.atEnd() == false; i++)
650         {
651                 MapBlock *block = i.getNode()->getValue();
652
653                 for(;;)
654                 {
655                         // Don't bother with dummy blocks.
656                         if(block->isDummy())
657                                 break;
658
659                         v3s16 pos = block->getPos();
660                         modified_blocks.insert(pos, block);
661
662                         blocks_to_update.insert(pos, block);
663
664                         /*
665                                 Clear all light from block
666                         */
667                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
668                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
669                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
670                         {
671
672                                 try{
673                                         v3s16 p(x,y,z);
674                                         MapNode n = block->getNode(v3s16(x,y,z));
675                                         u8 oldlight = n.getLight(bank);
676                                         n.setLight(bank, 0);
677                                         block->setNode(v3s16(x,y,z), n);
678
679                                         // Collect borders for unlighting
680                                         if(x==0 || x == MAP_BLOCKSIZE-1
681                                         || y==0 || y == MAP_BLOCKSIZE-1
682                                         || z==0 || z == MAP_BLOCKSIZE-1)
683                                         {
684                                                 v3s16 p_map = p + v3s16(
685                                                                 MAP_BLOCKSIZE*pos.X,
686                                                                 MAP_BLOCKSIZE*pos.Y,
687                                                                 MAP_BLOCKSIZE*pos.Z);
688                                                 unlight_from.insert(p_map, oldlight);
689                                         }
690                                 }
691                                 catch(InvalidPositionException &e)
692                                 {
693                                         /*
694                                                 This would happen when dealing with a
695                                                 dummy block.
696                                         */
697                                         //assert(0);
698                                         dstream<<"updateLighting(): InvalidPositionException"
699                                                         <<std::endl;
700                                 }
701                         }
702
703                         if(bank == LIGHTBANK_DAY)
704                         {
705                                 bool bottom_valid = block->propagateSunlight(light_sources);
706
707                                 // If bottom is valid, we're done.
708                                 if(bottom_valid)
709                                         break;
710                         }
711                         else if(bank == LIGHTBANK_NIGHT)
712                         {
713                                 // For night lighting, sunlight is not propagated
714                                 break;
715                         }
716                         else
717                         {
718                                 // Invalid lighting bank
719                                 assert(0);
720                         }
721
722                         /*dstream<<"Bottom for sunlight-propagated block ("
723                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
724                                         <<std::endl;*/
725
726                         // Bottom sunlight is not valid; get the block and loop to it
727
728                         pos.Y--;
729                         try{
730                                 block = getBlockNoCreate(pos);
731                         }
732                         catch(InvalidPositionException &e)
733                         {
734                                 assert(0);
735                         }
736
737                 }
738         }
739
740 #if 0
741         {
742                 TimeTaker timer("unspreadLight");
743                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
744         }
745
746         if(debug)
747         {
748                 u32 diff = modified_blocks.size() - count_was;
749                 count_was = modified_blocks.size();
750                 dstream<<"unspreadLight modified "<<diff<<std::endl;
751         }
752
753         {
754                 TimeTaker timer("spreadLight");
755                 spreadLight(bank, light_sources, modified_blocks);
756         }
757
758         if(debug)
759         {
760                 u32 diff = modified_blocks.size() - count_was;
761                 count_was = modified_blocks.size();
762                 dstream<<"spreadLight modified "<<diff<<std::endl;
763         }
764 #endif
765
766         {
767                 //MapVoxelManipulator vmanip(this);
768
769                 // Make a manual voxel manipulator and load all the blocks
770                 // that touch the requested blocks
771                 ManualMapVoxelManipulator vmanip(this);
772                 core::map<v3s16, MapBlock*>::Iterator i;
773                 i = blocks_to_update.getIterator();
774                 for(; i.atEnd() == false; i++)
775                 {
776                         MapBlock *block = i.getNode()->getValue();
777                         v3s16 p = block->getPos();
778
779                         // Add all surrounding blocks
780                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
781
782                         /*
783                                 Add all surrounding blocks that have up-to-date lighting
784                                 NOTE: This doesn't quite do the job (not everything
785                                           appropriate is lighted)
786                         */
787                         /*for(s16 z=-1; z<=1; z++)
788                         for(s16 y=-1; y<=1; y++)
789                         for(s16 x=-1; x<=1; x++)
790                         {
791                                 v3s16 p(x,y,z);
792                                 MapBlock *block = getBlockNoCreateNoEx(p);
793                                 if(block == NULL)
794                                         continue;
795                                 if(block->isDummy())
796                                         continue;
797                                 if(block->getLightingExpired())
798                                         continue;
799                                 vmanip.initialEmerge(p, p);
800                         }*/
801
802                         // Lighting of block will be updated completely
803                         block->setLightingExpired(false);
804                 }
805
806                 {
807                         //TimeTaker timer("unSpreadLight");
808                         vmanip.unspreadLight(bank, unlight_from, light_sources);
809                 }
810                 {
811                         //TimeTaker timer("spreadLight");
812                         vmanip.spreadLight(bank, light_sources);
813                 }
814                 {
815                         //TimeTaker timer("blitBack");
816                         vmanip.blitBack(modified_blocks);
817                 }
818                 /*dstream<<"emerge_time="<<emerge_time<<std::endl;
819                 emerge_time = 0;*/
820         }
821
822         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
823 }
824
825 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
826                 core::map<v3s16, MapBlock*> & modified_blocks)
827 {
828         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
829         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
830
831         /*
832                 Update information about whether day and night light differ
833         */
834         for(core::map<v3s16, MapBlock*>::Iterator
835                         i = modified_blocks.getIterator();
836                         i.atEnd() == false; i++)
837         {
838                 MapBlock *block = i.getNode()->getValue();
839                 block->updateDayNightDiff();
840         }
841 }
842
843 /*
844 */
845 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
846                 core::map<v3s16, MapBlock*> &modified_blocks)
847 {
848         /*PrintInfo(m_dout);
849         m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
850                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
851
852         /*
853                 From this node to nodes underneath:
854                 If lighting is sunlight (1.0), unlight neighbours and
855                 set lighting to 0.
856                 Else discontinue.
857         */
858
859         v3s16 toppos = p + v3s16(0,1,0);
860         v3s16 bottompos = p + v3s16(0,-1,0);
861
862         bool node_under_sunlight = true;
863         core::map<v3s16, bool> light_sources;
864
865         /*
866                 If there is a node at top and it doesn't have sunlight,
867                 there has not been any sunlight going down.
868
869                 Otherwise there probably is.
870         */
871         try{
872                 MapNode topnode = getNode(toppos);
873
874                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
875                         node_under_sunlight = false;
876         }
877         catch(InvalidPositionException &e)
878         {
879         }
880
881 #if 1
882         /*
883                 If the new node is solid and there is grass below, change it to mud
884         */
885         if(content_features(n.d).walkable == true)
886         {
887                 try{
888                         MapNode bottomnode = getNode(bottompos);
889
890                         if(bottomnode.d == CONTENT_GRASS
891                                         || bottomnode.d == CONTENT_GRASS_FOOTSTEPS)
892                         {
893                                 bottomnode.d = CONTENT_MUD;
894                                 setNode(bottompos, bottomnode);
895                         }
896                 }
897                 catch(InvalidPositionException &e)
898                 {
899                 }
900         }
901 #endif
902
903 #if 0
904         /*
905                 If the new node is mud and it is under sunlight, change it
906                 to grass
907         */
908         if(n.d == CONTENT_MUD && node_under_sunlight)
909         {
910                 n.d = CONTENT_GRASS;
911         }
912 #endif
913
914         /*
915                 Remove all light that has come out of this node
916         */
917
918         enum LightBank banks[] =
919         {
920                 LIGHTBANK_DAY,
921                 LIGHTBANK_NIGHT
922         };
923         for(s32 i=0; i<2; i++)
924         {
925                 enum LightBank bank = banks[i];
926
927                 u8 lightwas = getNode(p).getLight(bank);
928
929                 // Add the block of the added node to modified_blocks
930                 v3s16 blockpos = getNodeBlockPos(p);
931                 MapBlock * block = getBlockNoCreate(blockpos);
932                 assert(block != NULL);
933                 modified_blocks.insert(blockpos, block);
934
935                 assert(isValidPosition(p));
936
937                 // Unlight neighbours of node.
938                 // This means setting light of all consequent dimmer nodes
939                 // to 0.
940                 // This also collects the nodes at the border which will spread
941                 // light again into this.
942                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
943
944                 n.setLight(bank, 0);
945         }
946
947         /*
948                 If node lets sunlight through and is under sunlight, it has
949                 sunlight too.
950         */
951         if(node_under_sunlight && content_features(n.d).sunlight_propagates)
952         {
953                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
954         }
955
956         /*
957                 Set the node on the map
958         */
959
960         setNode(p, n);
961
962         /*
963                 Add intial metadata
964         */
965
966         NodeMetadata *meta_proto = content_features(n.d).initial_metadata;
967         if(meta_proto)
968         {
969                 NodeMetadata *meta = meta_proto->clone();
970                 setNodeMetadata(p, meta);
971         }
972
973         /*
974                 If node is under sunlight and doesn't let sunlight through,
975                 take all sunlighted nodes under it and clear light from them
976                 and from where the light has been spread.
977                 TODO: This could be optimized by mass-unlighting instead
978                           of looping
979         */
980         if(node_under_sunlight && !content_features(n.d).sunlight_propagates)
981         {
982                 s16 y = p.Y - 1;
983                 for(;; y--){
984                         //m_dout<<DTIME<<"y="<<y<<std::endl;
985                         v3s16 n2pos(p.X, y, p.Z);
986
987                         MapNode n2;
988                         try{
989                                 n2 = getNode(n2pos);
990                         }
991                         catch(InvalidPositionException &e)
992                         {
993                                 break;
994                         }
995
996                         if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
997                         {
998                                 unLightNeighbors(LIGHTBANK_DAY,
999                                                 n2pos, n2.getLight(LIGHTBANK_DAY),
1000                                                 light_sources, modified_blocks);
1001                                 n2.setLight(LIGHTBANK_DAY, 0);
1002                                 setNode(n2pos, n2);
1003                         }
1004                         else
1005                                 break;
1006                 }
1007         }
1008
1009         for(s32 i=0; i<2; i++)
1010         {
1011                 enum LightBank bank = banks[i];
1012
1013                 /*
1014                         Spread light from all nodes that might be capable of doing so
1015                 */
1016                 spreadLight(bank, light_sources, modified_blocks);
1017         }
1018
1019         /*
1020                 Update information about whether day and night light differ
1021         */
1022         for(core::map<v3s16, MapBlock*>::Iterator
1023                         i = modified_blocks.getIterator();
1024                         i.atEnd() == false; i++)
1025         {
1026                 MapBlock *block = i.getNode()->getValue();
1027                 block->updateDayNightDiff();
1028         }
1029
1030         /*
1031                 Add neighboring liquid nodes and the node itself if it is
1032                 liquid (=water node was added) to transform queue.
1033         */
1034         v3s16 dirs[7] = {
1035                 v3s16(0,0,0), // self
1036                 v3s16(0,0,1), // back
1037                 v3s16(0,1,0), // top
1038                 v3s16(1,0,0), // right
1039                 v3s16(0,0,-1), // front
1040                 v3s16(0,-1,0), // bottom
1041                 v3s16(-1,0,0), // left
1042         };
1043         for(u16 i=0; i<7; i++)
1044         {
1045                 try
1046                 {
1047
1048                 v3s16 p2 = p + dirs[i];
1049
1050                 MapNode n2 = getNode(p2);
1051                 if(content_liquid(n2.d))
1052                 {
1053                         m_transforming_liquid.push_back(p2);
1054                 }
1055
1056                 }catch(InvalidPositionException &e)
1057                 {
1058                 }
1059         }
1060 }
1061
1062 /*
1063 */
1064 void Map::removeNodeAndUpdate(v3s16 p,
1065                 core::map<v3s16, MapBlock*> &modified_blocks)
1066 {
1067         /*PrintInfo(m_dout);
1068         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1069                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1070
1071         bool node_under_sunlight = true;
1072
1073         v3s16 toppos = p + v3s16(0,1,0);
1074
1075         // Node will be replaced with this
1076         u8 replace_material = CONTENT_AIR;
1077
1078         /*
1079                 If there is a node at top and it doesn't have sunlight,
1080                 there will be no sunlight going down.
1081         */
1082         try{
1083                 MapNode topnode = getNode(toppos);
1084
1085                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1086                         node_under_sunlight = false;
1087         }
1088         catch(InvalidPositionException &e)
1089         {
1090         }
1091
1092         core::map<v3s16, bool> light_sources;
1093
1094         enum LightBank banks[] =
1095         {
1096                 LIGHTBANK_DAY,
1097                 LIGHTBANK_NIGHT
1098         };
1099         for(s32 i=0; i<2; i++)
1100         {
1101                 enum LightBank bank = banks[i];
1102
1103                 /*
1104                         Unlight neighbors (in case the node is a light source)
1105                 */
1106                 unLightNeighbors(bank, p,
1107                                 getNode(p).getLight(bank),
1108                                 light_sources, modified_blocks);
1109         }
1110
1111         /*
1112                 Remove node metadata
1113         */
1114
1115         removeNodeMetadata(p);
1116
1117         /*
1118                 Remove the node.
1119                 This also clears the lighting.
1120         */
1121
1122         MapNode n;
1123         n.d = replace_material;
1124         setNode(p, n);
1125
1126         for(s32 i=0; i<2; i++)
1127         {
1128                 enum LightBank bank = banks[i];
1129
1130                 /*
1131                         Recalculate lighting
1132                 */
1133                 spreadLight(bank, light_sources, modified_blocks);
1134         }
1135
1136         // Add the block of the removed node to modified_blocks
1137         v3s16 blockpos = getNodeBlockPos(p);
1138         MapBlock * block = getBlockNoCreate(blockpos);
1139         assert(block != NULL);
1140         modified_blocks.insert(blockpos, block);
1141
1142         /*
1143                 If the removed node was under sunlight, propagate the
1144                 sunlight down from it and then light all neighbors
1145                 of the propagated blocks.
1146         */
1147         if(node_under_sunlight)
1148         {
1149                 s16 ybottom = propagateSunlight(p, modified_blocks);
1150                 /*m_dout<<DTIME<<"Node was under sunlight. "
1151                                 "Propagating sunlight";
1152                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1153                 s16 y = p.Y;
1154                 for(; y >= ybottom; y--)
1155                 {
1156                         v3s16 p2(p.X, y, p.Z);
1157                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1158                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1159                                         <<std::endl;*/
1160                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1161                 }
1162         }
1163         else
1164         {
1165                 // Set the lighting of this node to 0
1166                 // TODO: Is this needed? Lighting is cleared up there already.
1167                 try{
1168                         MapNode n = getNode(p);
1169                         n.setLight(LIGHTBANK_DAY, 0);
1170                         setNode(p, n);
1171                 }
1172                 catch(InvalidPositionException &e)
1173                 {
1174                         assert(0);
1175                 }
1176         }
1177
1178         for(s32 i=0; i<2; i++)
1179         {
1180                 enum LightBank bank = banks[i];
1181
1182                 // Get the brightest neighbour node and propagate light from it
1183                 v3s16 n2p = getBrightestNeighbour(bank, p);
1184                 try{
1185                         MapNode n2 = getNode(n2p);
1186                         lightNeighbors(bank, n2p, modified_blocks);
1187                 }
1188                 catch(InvalidPositionException &e)
1189                 {
1190                 }
1191         }
1192
1193         /*
1194                 Update information about whether day and night light differ
1195         */
1196         for(core::map<v3s16, MapBlock*>::Iterator
1197                         i = modified_blocks.getIterator();
1198                         i.atEnd() == false; i++)
1199         {
1200                 MapBlock *block = i.getNode()->getValue();
1201                 block->updateDayNightDiff();
1202         }
1203
1204         /*
1205                 Add neighboring liquid nodes to transform queue.
1206         */
1207         v3s16 dirs[6] = {
1208                 v3s16(0,0,1), // back
1209                 v3s16(0,1,0), // top
1210                 v3s16(1,0,0), // right
1211                 v3s16(0,0,-1), // front
1212                 v3s16(0,-1,0), // bottom
1213                 v3s16(-1,0,0), // left
1214         };
1215         for(u16 i=0; i<6; i++)
1216         {
1217                 try
1218                 {
1219
1220                 v3s16 p2 = p + dirs[i];
1221
1222                 MapNode n2 = getNode(p2);
1223                 if(content_liquid(n2.d))
1224                 {
1225                         m_transforming_liquid.push_back(p2);
1226                 }
1227
1228                 }catch(InvalidPositionException &e)
1229                 {
1230                 }
1231         }
1232 }
1233
1234 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1235 {
1236         MapEditEvent event;
1237         event.type = MEET_ADDNODE;
1238         event.p = p;
1239         event.n = n;
1240
1241         bool succeeded = true;
1242         try{
1243                 core::map<v3s16, MapBlock*> modified_blocks;
1244                 addNodeAndUpdate(p, n, modified_blocks);
1245
1246                 // Copy modified_blocks to event
1247                 for(core::map<v3s16, MapBlock*>::Iterator
1248                                 i = modified_blocks.getIterator();
1249                                 i.atEnd()==false; i++)
1250                 {
1251                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1252                 }
1253         }
1254         catch(InvalidPositionException &e){
1255                 succeeded = false;
1256         }
1257
1258         dispatchEvent(&event);
1259
1260         return succeeded;
1261 }
1262
1263 bool Map::removeNodeWithEvent(v3s16 p)
1264 {
1265         MapEditEvent event;
1266         event.type = MEET_REMOVENODE;
1267         event.p = p;
1268
1269         bool succeeded = true;
1270         try{
1271                 core::map<v3s16, MapBlock*> modified_blocks;
1272                 removeNodeAndUpdate(p, modified_blocks);
1273
1274                 // Copy modified_blocks to event
1275                 for(core::map<v3s16, MapBlock*>::Iterator
1276                                 i = modified_blocks.getIterator();
1277                                 i.atEnd()==false; i++)
1278                 {
1279                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1280                 }
1281         }
1282         catch(InvalidPositionException &e){
1283                 succeeded = false;
1284         }
1285
1286         dispatchEvent(&event);
1287
1288         return succeeded;
1289 }
1290
1291 bool Map::dayNightDiffed(v3s16 blockpos)
1292 {
1293         try{
1294                 v3s16 p = blockpos + v3s16(0,0,0);
1295                 MapBlock *b = getBlockNoCreate(p);
1296                 if(b->dayNightDiffed())
1297                         return true;
1298         }
1299         catch(InvalidPositionException &e){}
1300         // Leading edges
1301         try{
1302                 v3s16 p = blockpos + v3s16(-1,0,0);
1303                 MapBlock *b = getBlockNoCreate(p);
1304                 if(b->dayNightDiffed())
1305                         return true;
1306         }
1307         catch(InvalidPositionException &e){}
1308         try{
1309                 v3s16 p = blockpos + v3s16(0,-1,0);
1310                 MapBlock *b = getBlockNoCreate(p);
1311                 if(b->dayNightDiffed())
1312                         return true;
1313         }
1314         catch(InvalidPositionException &e){}
1315         try{
1316                 v3s16 p = blockpos + v3s16(0,0,-1);
1317                 MapBlock *b = getBlockNoCreate(p);
1318                 if(b->dayNightDiffed())
1319                         return true;
1320         }
1321         catch(InvalidPositionException &e){}
1322         // Trailing edges
1323         try{
1324                 v3s16 p = blockpos + v3s16(1,0,0);
1325                 MapBlock *b = getBlockNoCreate(p);
1326                 if(b->dayNightDiffed())
1327                         return true;
1328         }
1329         catch(InvalidPositionException &e){}
1330         try{
1331                 v3s16 p = blockpos + v3s16(0,1,0);
1332                 MapBlock *b = getBlockNoCreate(p);
1333                 if(b->dayNightDiffed())
1334                         return true;
1335         }
1336         catch(InvalidPositionException &e){}
1337         try{
1338                 v3s16 p = blockpos + v3s16(0,0,1);
1339                 MapBlock *b = getBlockNoCreate(p);
1340                 if(b->dayNightDiffed())
1341                         return true;
1342         }
1343         catch(InvalidPositionException &e){}
1344
1345         return false;
1346 }
1347
1348 /*
1349         Updates usage timers
1350 */
1351 void Map::timerUpdate(float dtime)
1352 {
1353         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
1354
1355         core::map<v2s16, MapSector*>::Iterator si;
1356
1357         si = m_sectors.getIterator();
1358         for(; si.atEnd() == false; si++)
1359         {
1360                 MapSector *sector = si.getNode()->getValue();
1361
1362                 core::list<MapBlock*> blocks;
1363                 sector->getBlocks(blocks);
1364                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1365                                 i != blocks.end(); i++)
1366                 {
1367                         (*i)->incrementUsageTimer(dtime);
1368                 }
1369         }
1370 }
1371
1372 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
1373 {
1374         core::list<v2s16>::Iterator j;
1375         for(j=list.begin(); j!=list.end(); j++)
1376         {
1377                 MapSector *sector = m_sectors[*j];
1378                 if(only_blocks)
1379                 {
1380                         sector->deleteBlocks();
1381                 }
1382                 else
1383                 {
1384                         /*
1385                                 If sector is in sector cache, remove it from there
1386                         */
1387                         if(m_sector_cache == sector)
1388                         {
1389                                 m_sector_cache = NULL;
1390                         }
1391                         /*
1392                                 Remove from map and delete
1393                         */
1394                         m_sectors.remove(*j);
1395                         delete sector;
1396                 }
1397         }
1398 }
1399
1400 u32 Map::unloadUnusedData(float timeout, bool only_blocks,
1401                 core::list<v3s16> *deleted_blocks)
1402 {
1403         core::list<v2s16> sector_deletion_queue;
1404
1405         core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
1406         for(; si.atEnd() == false; si++)
1407         {
1408                 MapSector *sector = si.getNode()->getValue();
1409
1410                 bool all_blocks_deleted = true;
1411
1412                 core::list<MapBlock*> blocks;
1413                 sector->getBlocks(blocks);
1414                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1415                                 i != blocks.end(); i++)
1416                 {
1417                         MapBlock *block = (*i);
1418
1419                         if(block->getUsageTimer() > timeout)
1420                         {
1421                                 // Save if modified
1422                                 if(block->getModified() != MOD_STATE_CLEAN)
1423                                         saveBlock(block);
1424                                 // Unload
1425                                 sector->removeBlock(block);
1426                                 delete block;
1427                         }
1428                         else
1429                         {
1430                                 all_blocks_deleted = false;
1431                         }
1432                 }
1433
1434                 if(all_blocks_deleted)
1435                 {
1436                         sector_deletion_queue.push_back(si.getNode()->getKey());
1437                 }
1438         }
1439
1440 #if 0
1441         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
1442         for(; i.atEnd() == false; i++)
1443         {
1444                 MapSector *sector = i.getNode()->getValue();
1445                 /*
1446                         Delete sector from memory if it hasn't been used in a long time
1447                 */
1448                 if(sector->usage_timer > timeout)
1449                 {
1450                         sector_deletion_queue.push_back(i.getNode()->getKey());
1451
1452                         if(deleted_blocks != NULL)
1453                         {
1454                                 // Collect positions of blocks of sector
1455                                 MapSector *sector = i.getNode()->getValue();
1456                                 core::list<MapBlock*> blocks;
1457                                 sector->getBlocks(blocks);
1458                                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1459                                                 i != blocks.end(); i++)
1460                                 {
1461                                         deleted_blocks->push_back((*i)->getPos());
1462                                 }
1463                         }
1464                 }
1465         }
1466 #endif
1467
1468         deleteSectors(sector_deletion_queue, only_blocks);
1469         return sector_deletion_queue.getSize();
1470 }
1471
1472 void Map::PrintInfo(std::ostream &out)
1473 {
1474         out<<"Map: ";
1475 }
1476
1477 #define WATER_DROP_BOOST 4
1478
1479 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1480 {
1481         DSTACK(__FUNCTION_NAME);
1482         //TimeTaker timer("transformLiquids()");
1483
1484         u32 loopcount = 0;
1485         u32 initial_size = m_transforming_liquid.size();
1486
1487         /*if(initial_size != 0)
1488                 dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1489
1490         while(m_transforming_liquid.size() != 0)
1491         {
1492                 /*
1493                         Get a queued transforming liquid node
1494                 */
1495                 v3s16 p0 = m_transforming_liquid.pop_front();
1496
1497                 MapNode n0 = getNode(p0);
1498
1499                 // Don't deal with non-liquids
1500                 if(content_liquid(n0.d) == false)
1501                         continue;
1502
1503                 bool is_source = !content_flowing_liquid(n0.d);
1504
1505                 u8 liquid_level = 8;
1506                 if(is_source == false)
1507                         liquid_level = n0.param2 & 0x0f;
1508
1509                 // Turn possible source into non-source
1510                 u8 nonsource_c = make_liquid_flowing(n0.d);
1511
1512                 /*
1513                         If not source, check that some node flows into this one
1514                         and what is the level of liquid in this one
1515                 */
1516                 if(is_source == false)
1517                 {
1518                         s8 new_liquid_level_max = -1;
1519
1520                         v3s16 dirs_from[5] = {
1521                                 v3s16(0,1,0), // top
1522                                 v3s16(0,0,1), // back
1523                                 v3s16(1,0,0), // right
1524                                 v3s16(0,0,-1), // front
1525                                 v3s16(-1,0,0), // left
1526                         };
1527                         for(u16 i=0; i<5; i++)
1528                         {
1529                                 try
1530                                 {
1531
1532                                 bool from_top = (i==0);
1533
1534                                 v3s16 p2 = p0 + dirs_from[i];
1535                                 MapNode n2 = getNode(p2);
1536
1537                                 if(content_liquid(n2.d))
1538                                 {
1539                                         u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1540                                         // Check that the liquids are the same type
1541                                         if(n2_nonsource_c != nonsource_c)
1542                                         {
1543                                                 dstream<<"WARNING: Not handling: different liquids"
1544                                                                 " collide"<<std::endl;
1545                                                 continue;
1546                                         }
1547                                         bool n2_is_source = !content_flowing_liquid(n2.d);
1548                                         s8 n2_liquid_level = 8;
1549                                         if(n2_is_source == false)
1550                                                 n2_liquid_level = n2.param2 & 0x07;
1551
1552                                         s8 new_liquid_level = -1;
1553                                         if(from_top)
1554                                         {
1555                                                 //new_liquid_level = 7;
1556                                                 if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
1557                                                         new_liquid_level = 7;
1558                                                 else
1559                                                         new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
1560                                         }
1561                                         else if(n2_liquid_level > 0)
1562                                         {
1563                                                 new_liquid_level = n2_liquid_level - 1;
1564                                         }
1565
1566                                         if(new_liquid_level > new_liquid_level_max)
1567                                                 new_liquid_level_max = new_liquid_level;
1568                                 }
1569
1570                                 }catch(InvalidPositionException &e)
1571                                 {
1572                                 }
1573                         } //for
1574
1575                         /*
1576                                 If liquid level should be something else, update it and
1577                                 add all the neighboring water nodes to the transform queue.
1578                         */
1579                         if(new_liquid_level_max != liquid_level)
1580                         {
1581                                 if(new_liquid_level_max == -1)
1582                                 {
1583                                         // Remove water alltoghether
1584                                         n0.d = CONTENT_AIR;
1585                                         n0.param2 = 0;
1586                                         setNode(p0, n0);
1587                                 }
1588                                 else
1589                                 {
1590                                         n0.param2 = new_liquid_level_max;
1591                                         setNode(p0, n0);
1592                                 }
1593
1594                                 // Block has been modified
1595                                 {
1596                                         v3s16 blockpos = getNodeBlockPos(p0);
1597                                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1598                                         if(block != NULL)
1599                                                 modified_blocks.insert(blockpos, block);
1600                                 }
1601
1602                                 /*
1603                                         Add neighboring non-source liquid nodes to transform queue.
1604                                 */
1605                                 v3s16 dirs[6] = {
1606                                         v3s16(0,0,1), // back
1607                                         v3s16(0,1,0), // top
1608                                         v3s16(1,0,0), // right
1609                                         v3s16(0,0,-1), // front
1610                                         v3s16(0,-1,0), // bottom
1611                                         v3s16(-1,0,0), // left
1612                                 };
1613                                 for(u16 i=0; i<6; i++)
1614                                 {
1615                                         try
1616                                         {
1617
1618                                         v3s16 p2 = p0 + dirs[i];
1619
1620                                         MapNode n2 = getNode(p2);
1621                                         if(content_flowing_liquid(n2.d))
1622                                         {
1623                                                 m_transforming_liquid.push_back(p2);
1624                                         }
1625
1626                                         }catch(InvalidPositionException &e)
1627                                         {
1628                                         }
1629                                 }
1630                         }
1631                 }
1632
1633                 // Get a new one from queue if the node has turned into non-water
1634                 if(content_liquid(n0.d) == false)
1635                         continue;
1636
1637                 /*
1638                         Flow water from this node
1639                 */
1640                 v3s16 dirs_to[5] = {
1641                         v3s16(0,-1,0), // bottom
1642                         v3s16(0,0,1), // back
1643                         v3s16(1,0,0), // right
1644                         v3s16(0,0,-1), // front
1645                         v3s16(-1,0,0), // left
1646                 };
1647                 for(u16 i=0; i<5; i++)
1648                 {
1649                         try
1650                         {
1651
1652                         bool to_bottom = (i == 0);
1653
1654                         // If liquid is at lowest possible height, it's not going
1655                         // anywhere except down
1656                         if(liquid_level == 0 && to_bottom == false)
1657                                 continue;
1658
1659                         u8 liquid_next_level = 0;
1660                         // If going to bottom
1661                         if(to_bottom)
1662                         {
1663                                 //liquid_next_level = 7;
1664                                 if(liquid_level >= 7 - WATER_DROP_BOOST)
1665                                         liquid_next_level = 7;
1666                                 else
1667                                         liquid_next_level = liquid_level + WATER_DROP_BOOST;
1668                         }
1669                         else
1670                                 liquid_next_level = liquid_level - 1;
1671
1672                         bool n2_changed = false;
1673                         bool flowed = false;
1674
1675                         v3s16 p2 = p0 + dirs_to[i];
1676
1677                         MapNode n2 = getNode(p2);
1678                         //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
1679
1680                         if(content_liquid(n2.d))
1681                         {
1682                                 u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1683                                 // Check that the liquids are the same type
1684                                 if(n2_nonsource_c != nonsource_c)
1685                                 {
1686                                         dstream<<"WARNING: Not handling: different liquids"
1687                                                         " collide"<<std::endl;
1688                                         continue;
1689                                 }
1690                                 bool n2_is_source = !content_flowing_liquid(n2.d);
1691                                 u8 n2_liquid_level = 8;
1692                                 if(n2_is_source == false)
1693                                         n2_liquid_level = n2.param2 & 0x07;
1694
1695                                 if(to_bottom)
1696                                 {
1697                                         flowed = true;
1698                                 }
1699
1700                                 if(n2_is_source)
1701                                 {
1702                                         // Just flow into the source, nothing changes.
1703                                         // n2_changed is not set because destination didn't change
1704                                         flowed = true;
1705                                 }
1706                                 else
1707                                 {
1708                                         if(liquid_next_level > liquid_level)
1709                                         {
1710                                                 n2.param2 = liquid_next_level;
1711                                                 setNode(p2, n2);
1712
1713                                                 n2_changed = true;
1714                                                 flowed = true;
1715                                         }
1716                                 }
1717                         }
1718                         else if(n2.d == CONTENT_AIR)
1719                         {
1720                                 n2.d = nonsource_c;
1721                                 n2.param2 = liquid_next_level;
1722                                 setNode(p2, n2);
1723
1724                                 n2_changed = true;
1725                                 flowed = true;
1726                         }
1727
1728                         //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl;
1729
1730                         if(n2_changed)
1731                         {
1732                                 m_transforming_liquid.push_back(p2);
1733
1734                                 v3s16 blockpos = getNodeBlockPos(p2);
1735                                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1736                                 if(block != NULL)
1737                                         modified_blocks.insert(blockpos, block);
1738                         }
1739
1740                         // If n2_changed to bottom, don't flow anywhere else
1741                         if(to_bottom && flowed && !is_source)
1742                                 break;
1743
1744                         }catch(InvalidPositionException &e)
1745                         {
1746                         }
1747                 }
1748
1749                 loopcount++;
1750                 //if(loopcount >= 100000)
1751                 if(loopcount >= initial_size * 1)
1752                         break;
1753         }
1754         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1755 }
1756
1757 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1758 {
1759         v3s16 blockpos = getNodeBlockPos(p);
1760         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1761         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1762         if(block == NULL)
1763         {
1764                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1765                                 <<std::endl;
1766                 return NULL;
1767         }
1768         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1769         return meta;
1770 }
1771
1772 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1773 {
1774         v3s16 blockpos = getNodeBlockPos(p);
1775         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1776         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1777         if(block == NULL)
1778         {
1779                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1780                                 <<std::endl;
1781                 return;
1782         }
1783         block->m_node_metadata.set(p_rel, meta);
1784 }
1785
1786 void Map::removeNodeMetadata(v3s16 p)
1787 {
1788         v3s16 blockpos = getNodeBlockPos(p);
1789         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1790         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1791         if(block == NULL)
1792         {
1793                 dstream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1794                                 <<std::endl;
1795                 return;
1796         }
1797         block->m_node_metadata.remove(p_rel);
1798 }
1799
1800 void Map::nodeMetadataStep(float dtime,
1801                 core::map<v3s16, MapBlock*> &changed_blocks)
1802 {
1803         /*
1804                 NOTE:
1805                 Currently there is no way to ensure that all the necessary
1806                 blocks are loaded when this is run. (They might get unloaded)
1807                 NOTE: ^- Actually, that might not be so. In a quick test it
1808                 reloaded a block with a furnace when I walked back to it from
1809                 a distance.
1810         */
1811         core::map<v2s16, MapSector*>::Iterator si;
1812         si = m_sectors.getIterator();
1813         for(; si.atEnd() == false; si++)
1814         {
1815                 MapSector *sector = si.getNode()->getValue();
1816                 core::list< MapBlock * > sectorblocks;
1817                 sector->getBlocks(sectorblocks);
1818                 core::list< MapBlock * >::Iterator i;
1819                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1820                 {
1821                         MapBlock *block = *i;
1822                         bool changed = block->m_node_metadata.step(dtime);
1823                         if(changed)
1824                                 changed_blocks[block->getPos()] = block;
1825                 }
1826         }
1827 }
1828
1829 /*
1830         ServerMap
1831 */
1832
1833 ServerMap::ServerMap(std::string savedir):
1834         Map(dout_server),
1835         m_seed(0),
1836         m_map_metadata_changed(true)
1837 {
1838         dstream<<__FUNCTION_NAME<<std::endl;
1839
1840         //m_chunksize = 8; // Takes a few seconds
1841
1842         m_seed = (((u64)(myrand()%0xffff)<<0)
1843                         + ((u64)(myrand()%0xffff)<<16)
1844                         + ((u64)(myrand()%0xffff)<<32)
1845                         + ((u64)(myrand()%0xffff)<<48));
1846
1847         /*
1848                 Experimental and debug stuff
1849         */
1850
1851         {
1852         }
1853
1854         /*
1855                 Try to load map; if not found, create a new one.
1856         */
1857
1858         m_savedir = savedir;
1859         m_map_saving_enabled = false;
1860
1861         try
1862         {
1863                 // If directory exists, check contents and load if possible
1864                 if(fs::PathExists(m_savedir))
1865                 {
1866                         // If directory is empty, it is safe to save into it.
1867                         if(fs::GetDirListing(m_savedir).size() == 0)
1868                         {
1869                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1870                                                 <<std::endl;
1871                                 m_map_saving_enabled = true;
1872                         }
1873                         else
1874                         {
1875                                 try{
1876                                         // Load map metadata (seed, chunksize)
1877                                         loadMapMeta();
1878                                 }
1879                                 catch(FileNotGoodException &e){
1880                                         dstream<<DTIME<<"WARNING: Could not load map metadata"
1881                                                         //<<" Disabling chunk-based generator."
1882                                                         <<std::endl;
1883                                         //m_chunksize = 0;
1884                                 }
1885
1886                                 /*try{
1887                                         // Load chunk metadata
1888                                         loadChunkMeta();
1889                                 }
1890                                 catch(FileNotGoodException &e){
1891                                         dstream<<DTIME<<"WARNING: Could not load chunk metadata."
1892                                                         <<" Disabling chunk-based generator."
1893                                                         <<std::endl;
1894                                         m_chunksize = 0;
1895                                 }*/
1896
1897                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1898                                                 "metadata and sector (0,0) from "<<savedir<<
1899                                                 ", assuming valid save directory."
1900                                                 <<std::endl;*/
1901
1902                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1903                                                 <<"and chunk metadata from "<<savedir
1904                                                 <<", assuming valid save directory."
1905                                                 <<std::endl;
1906
1907                                 m_map_saving_enabled = true;
1908                                 // Map loaded, not creating new one
1909                                 return;
1910                         }
1911                 }
1912                 // If directory doesn't exist, it is safe to save to it
1913                 else{
1914                         m_map_saving_enabled = true;
1915                 }
1916         }
1917         catch(std::exception &e)
1918         {
1919                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1920                                 <<", exception: "<<e.what()<<std::endl;
1921                 dstream<<"Please remove the map or fix it."<<std::endl;
1922                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1923         }
1924
1925         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1926
1927         // Create zero sector
1928         emergeSector(v2s16(0,0));
1929
1930         // Initially write whole map
1931         save(false);
1932 }
1933
1934 ServerMap::~ServerMap()
1935 {
1936         dstream<<__FUNCTION_NAME<<std::endl;
1937
1938         try
1939         {
1940                 if(m_map_saving_enabled)
1941                 {
1942                         //save(false);
1943                         // Save only changed parts
1944                         save(true);
1945                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1946                 }
1947                 else
1948                 {
1949                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1950                 }
1951         }
1952         catch(std::exception &e)
1953         {
1954                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1955                                 <<", exception: "<<e.what()<<std::endl;
1956         }
1957
1958 #if 0
1959         /*
1960                 Free all MapChunks
1961         */
1962         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1963         for(; i.atEnd() == false; i++)
1964         {
1965                 MapChunk *chunk = i.getNode()->getValue();
1966                 delete chunk;
1967         }
1968 #endif
1969 }
1970
1971 /*
1972         Some helper functions for the map generator
1973 */
1974
1975 s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
1976 {
1977         v3s16 em = vmanip.m_area.getExtent();
1978         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
1979         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
1980         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
1981         s16 y;
1982         for(y=y_nodes_max; y>=y_nodes_min; y--)
1983         {
1984                 MapNode &n = vmanip.m_data[i];
1985                 if(content_walkable(n.d))
1986                         break;
1987
1988                 vmanip.m_area.add_y(em, i, -1);
1989         }
1990         if(y >= y_nodes_min)
1991                 return y;
1992         else
1993                 return y_nodes_min;
1994 }
1995
1996 s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
1997 {
1998         v3s16 em = vmanip.m_area.getExtent();
1999         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
2000         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
2001         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2002         s16 y;
2003         for(y=y_nodes_max; y>=y_nodes_min; y--)
2004         {
2005                 MapNode &n = vmanip.m_data[i];
2006                 if(content_walkable(n.d)
2007                                 && n.d != CONTENT_TREE
2008                                 && n.d != CONTENT_LEAVES)
2009                         break;
2010
2011                 vmanip.m_area.add_y(em, i, -1);
2012         }
2013         if(y >= y_nodes_min)
2014                 return y;
2015         else
2016                 return y_nodes_min;
2017 }
2018
2019 void make_tree(VoxelManipulator &vmanip, v3s16 p0)
2020 {
2021         MapNode treenode(CONTENT_TREE);
2022         MapNode leavesnode(CONTENT_LEAVES);
2023
2024         s16 trunk_h = myrand_range(3, 6);
2025         v3s16 p1 = p0;
2026         for(s16 ii=0; ii<trunk_h; ii++)
2027         {
2028                 if(vmanip.m_area.contains(p1))
2029                         vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
2030                 p1.Y++;
2031         }
2032
2033         // p1 is now the last piece of the trunk
2034         p1.Y -= 1;
2035
2036         VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
2037         //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
2038         Buffer<u8> leaves_d(leaves_a.getVolume());
2039         for(s32 i=0; i<leaves_a.getVolume(); i++)
2040                 leaves_d[i] = 0;
2041
2042         // Force leaves at near the end of the trunk
2043         {
2044                 s16 d = 1;
2045                 for(s16 z=-d; z<=d; z++)
2046                 for(s16 y=-d; y<=d; y++)
2047                 for(s16 x=-d; x<=d; x++)
2048                 {
2049                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
2050                 }
2051         }
2052
2053         // Add leaves randomly
2054         for(u32 iii=0; iii<7; iii++)
2055         {
2056                 s16 d = 1;
2057
2058                 v3s16 p(
2059                         myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
2060                         myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
2061                         myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
2062                 );
2063
2064                 for(s16 z=0; z<=d; z++)
2065                 for(s16 y=0; y<=d; y++)
2066                 for(s16 x=0; x<=d; x++)
2067                 {
2068                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
2069                 }
2070         }
2071
2072         // Blit leaves to vmanip
2073         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
2074         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
2075         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
2076         {
2077                 v3s16 p(x,y,z);
2078                 p += p1;
2079                 if(vmanip.m_area.contains(p) == false)
2080                         continue;
2081                 u32 vi = vmanip.m_area.index(p);
2082                 if(vmanip.m_data[vi].d != CONTENT_AIR
2083                                 && vmanip.m_data[vi].d != CONTENT_IGNORE)
2084                         continue;
2085                 u32 i = leaves_a.index(x,y,z);
2086                 if(leaves_d[i] == 1)
2087                         vmanip.m_data[vi] = leavesnode;
2088         }
2089 }
2090
2091 #if 0
2092 void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
2093 {
2094         MapNode stonenode(CONTENT_STONE);
2095
2096         s16 size = myrand_range(3, 6);
2097         
2098         VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
2099         Buffer<u8> stone_d(stone_a.getVolume());
2100         for(s32 i=0; i<stone_a.getVolume(); i++)
2101                 stone_d[i] = 0;
2102
2103         // Force stone at bottom to make it usually touch the ground
2104         {
2105                 for(s16 z=0; z<=0; z++)
2106                 for(s16 y=0; y<=0; y++)
2107                 for(s16 x=0; x<=0; x++)
2108                 {
2109                         stone_d[stone_a.index(v3s16(x,y,z))] = 1;
2110                 }
2111         }
2112
2113         // Generate from perlin noise
2114         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
2115         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
2116         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
2117         {
2118                 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
2119                                 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
2120                 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
2121                         d -= 0.3;
2122                 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
2123                         d -= 0.3;
2124                 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
2125                         d -= 0.3;
2126                 if(d > 0.0)
2127                 {
2128                         u32 vi = stone_a.index(v3s16(x,y,z));
2129                         stone_d[vi] = 1;
2130                 }
2131         }
2132
2133         /*// Add stone randomly
2134         for(u32 iii=0; iii<7; iii++)
2135         {
2136                 s16 d = 1;
2137
2138                 v3s16 p(
2139                         myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
2140                         myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
2141                         myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
2142                 );
2143
2144                 for(s16 z=0; z<=d; z++)
2145                 for(s16 y=0; y<=d; y++)
2146                 for(s16 x=0; x<=d; x++)
2147                 {
2148                         stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
2149                 }
2150         }*/
2151
2152         // Blit stone to vmanip
2153         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
2154         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
2155         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
2156         {
2157                 v3s16 p(x,y,z);
2158                 p += p0;
2159                 if(vmanip.m_area.contains(p) == false)
2160                         continue;
2161                 u32 vi = vmanip.m_area.index(p);
2162                 if(vmanip.m_data[vi].d != CONTENT_AIR
2163                                 && vmanip.m_data[vi].d != CONTENT_IGNORE)
2164                         continue;
2165                 u32 i = stone_a.index(x,y,z);
2166                 if(stone_d[i] == 1)
2167                         vmanip.m_data[vi] = stonenode;
2168         }
2169 }
2170 #endif
2171
2172 #if 0
2173 void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
2174 {
2175         MapNode stonenode(CONTENT_STONE);
2176
2177         s16 size = myrand_range(8, 16);
2178         
2179         VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
2180         Buffer<u8> stone_d(stone_a.getVolume());
2181         for(s32 i=0; i<stone_a.getVolume(); i++)
2182                 stone_d[i] = 0;
2183
2184         // Force stone at bottom to make it usually touch the ground
2185         {
2186                 for(s16 z=0; z<=0; z++)
2187                 for(s16 y=0; y<=0; y++)
2188                 for(s16 x=0; x<=0; x++)
2189                 {
2190                         stone_d[stone_a.index(v3s16(x,y,z))] = 1;
2191                 }
2192         }
2193
2194         // Generate from perlin noise
2195         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
2196         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
2197         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
2198         {
2199                 double d = 1.0;
2200                 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
2201                                 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
2202                 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
2203                 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
2204                 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
2205                 double dz = (double)z-mid_z;
2206                 double dx = (double)x-mid_x;
2207                 double dy = MYMAX(0, (double)y-mid_y);
2208                 double r = sqrt(dz*dz+dx*dx+dy*dy);
2209                 d /= (2*r/size)*2 + 0.01;
2210                 if(d > 1.0)
2211                 {
2212                         u32 vi = stone_a.index(v3s16(x,y,z));
2213                         stone_d[vi] = 1;
2214                 }
2215         }
2216
2217         /*// Add stone randomly
2218         for(u32 iii=0; iii<7; iii++)
2219         {
2220                 s16 d = 1;
2221
2222                 v3s16 p(
2223                         myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
2224                         myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
2225                         myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
2226                 );
2227
2228                 for(s16 z=0; z<=d; z++)
2229                 for(s16 y=0; y<=d; y++)
2230                 for(s16 x=0; x<=d; x++)
2231                 {
2232                         stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
2233                 }
2234         }*/
2235
2236         // Blit stone to vmanip
2237         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
2238         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
2239         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
2240         {
2241                 v3s16 p(x,y,z);
2242                 p += p0;
2243                 if(vmanip.m_area.contains(p) == false)
2244                         continue;
2245                 u32 vi = vmanip.m_area.index(p);
2246                 /*if(vmanip.m_data[vi].d != CONTENT_AIR
2247                                 && vmanip.m_data[vi].d != CONTENT_IGNORE)
2248                         continue;*/
2249                 u32 i = stone_a.index(x,y,z);
2250                 if(stone_d[i] == 1)
2251                         vmanip.m_data[vi] = stonenode;
2252         }
2253 }
2254 #endif
2255
2256 /*
2257         Dungeon making routines
2258 */
2259
2260 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
2261 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
2262 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
2263                 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
2264
2265 void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
2266 {
2267         // Make +-X walls
2268         for(s16 z=0; z<roomsize.Z; z++)
2269         for(s16 y=0; y<roomsize.Y; y++)
2270         {
2271                 {
2272                         v3s16 p = roomplace + v3s16(0,y,z);
2273                         if(vmanip.m_area.contains(p) == false)
2274                                 continue;
2275                         u32 vi = vmanip.m_area.index(p);
2276                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2277                                 continue;
2278                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2279                 }
2280                 {
2281                         v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
2282                         if(vmanip.m_area.contains(p) == false)
2283                                 continue;
2284                         u32 vi = vmanip.m_area.index(p);
2285                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2286                                 continue;
2287                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2288                 }
2289         }
2290         
2291         // Make +-Z walls
2292         for(s16 x=0; x<roomsize.X; x++)
2293         for(s16 y=0; y<roomsize.Y; y++)
2294         {
2295                 {
2296                         v3s16 p = roomplace + v3s16(x,y,0);
2297                         if(vmanip.m_area.contains(p) == false)
2298                                 continue;
2299                         u32 vi = vmanip.m_area.index(p);
2300                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2301                                 continue;
2302                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2303                 }
2304                 {
2305                         v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
2306                         if(vmanip.m_area.contains(p) == false)
2307                                 continue;
2308                         u32 vi = vmanip.m_area.index(p);
2309                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2310                                 continue;
2311                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2312                 }
2313         }
2314         
2315         // Make +-Y walls (floor and ceiling)
2316         for(s16 z=0; z<roomsize.Z; z++)
2317         for(s16 x=0; x<roomsize.X; x++)
2318         {
2319                 {
2320                         v3s16 p = roomplace + v3s16(x,0,z);
2321                         if(vmanip.m_area.contains(p) == false)
2322                                 continue;
2323                         u32 vi = vmanip.m_area.index(p);
2324                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2325                                 continue;
2326                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2327                 }
2328                 {
2329                         v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
2330                         if(vmanip.m_area.contains(p) == false)
2331                                 continue;
2332                         u32 vi = vmanip.m_area.index(p);
2333                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2334                                 continue;
2335                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2336                 }
2337         }
2338         
2339         // Fill with air
2340         for(s16 z=1; z<roomsize.Z-1; z++)
2341         for(s16 y=1; y<roomsize.Y-1; y++)
2342         for(s16 x=1; x<roomsize.X-1; x++)
2343         {
2344                 v3s16 p = roomplace + v3s16(x,y,z);
2345                 if(vmanip.m_area.contains(p) == false)
2346                         continue;
2347                 u32 vi = vmanip.m_area.index(p);
2348                 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
2349                 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
2350         }
2351 }
2352
2353 void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
2354                 u8 avoid_flags, MapNode n, u8 or_flags)
2355 {
2356         for(s16 z=0; z<size.Z; z++)
2357         for(s16 y=0; y<size.Y; y++)
2358         for(s16 x=0; x<size.X; x++)
2359         {
2360                 v3s16 p = place + v3s16(x,y,z);
2361                 if(vmanip.m_area.contains(p) == false)
2362                         continue;
2363                 u32 vi = vmanip.m_area.index(p);
2364                 if(vmanip.m_flags[vi] & avoid_flags)
2365                         continue;
2366                 vmanip.m_flags[vi] |= or_flags;
2367                 vmanip.m_data[vi] = n;
2368         }
2369 }
2370
2371 void make_hole1(VoxelManipulator &vmanip, v3s16 place)
2372 {
2373         make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
2374                         VMANIP_FLAG_DUNGEON_INSIDE);
2375 }
2376
2377 void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
2378 {
2379         make_hole1(vmanip, doorplace);
2380         // Place torch (for testing)
2381         //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH);
2382 }
2383
2384 v3s16 rand_ortho_dir(PseudoRandom &random)
2385 {
2386         if(random.next()%2==0)
2387                 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
2388         else
2389                 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
2390 }
2391
2392 v3s16 turn_xz(v3s16 olddir, int t)
2393 {
2394         v3s16 dir;
2395         if(t == 0)
2396         {
2397                 // Turn right
2398                 dir.X = olddir.Z;
2399                 dir.Z = -olddir.X;
2400                 dir.Y = olddir.Y;
2401         }
2402         else
2403         {
2404                 // Turn left
2405                 dir.X = -olddir.Z;
2406                 dir.Z = olddir.X;
2407                 dir.Y = olddir.Y;
2408         }
2409         return dir;
2410 }
2411
2412 v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
2413 {
2414         int turn = random.range(0,2);
2415         v3s16 dir;
2416         if(turn == 0)
2417         {
2418                 // Go straight
2419                 dir = olddir;
2420         }
2421         else if(turn == 1)
2422                 // Turn right
2423                 dir = turn_xz(olddir, 0);
2424         else
2425                 // Turn left
2426                 dir = turn_xz(olddir, 1);
2427         return dir;
2428 }
2429
2430 void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
2431                 v3s16 &result_place, v3s16 &result_dir, PseudoRandom &random)
2432 {
2433         make_hole1(vmanip, doorplace);
2434         v3s16 p0 = doorplace;
2435         v3s16 dir = doordir;
2436         u32 length;
2437         if(random.next()%2)
2438                 length = random.range(1,13);
2439         else
2440                 length = random.range(1,6);
2441         length = random.range(1,13);
2442         u32 partlength = random.range(1,length);
2443         u32 partcount = 0;
2444         s16 make_stairs = 0;
2445         if(random.next()%2 == 0 && partlength >= 3)
2446                 make_stairs = random.next()%2 ? 1 : -1;
2447         for(u32 i=0; i<length; i++)
2448         {
2449                 v3s16 p = p0 + dir;
2450                 if(partcount != 0)
2451                         p.Y += make_stairs;
2452
2453                 /*// If already empty
2454                 if(vmanip.getNodeNoExNoEmerge(p).d
2455                                 == CONTENT_AIR
2456                 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
2457                                 == CONTENT_AIR)
2458                 {
2459                 }*/
2460
2461                 if(vmanip.m_area.contains(p) == true
2462                                 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
2463                 {
2464                         if(make_stairs)
2465                         {
2466                                 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
2467                                                 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
2468                                 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
2469                                                 VMANIP_FLAG_DUNGEON_INSIDE);
2470                                 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
2471                                                 VMANIP_FLAG_DUNGEON_INSIDE);
2472                         }
2473                         else
2474                         {
2475                                 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
2476                                                 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
2477                                 make_hole1(vmanip, p);
2478                                 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
2479                                                 VMANIP_FLAG_DUNGEON_INSIDE);*/
2480                         }
2481
2482                         p0 = p;
2483                 }
2484                 else
2485                 {
2486                         // Can't go here, turn away
2487                         dir = turn_xz(dir, random.range(0,1));
2488                         make_stairs = -make_stairs;
2489                         partcount = 0;
2490                         partlength = random.range(1,length);
2491                         continue;
2492                 }
2493
2494                 partcount++;
2495                 if(partcount >= partlength)
2496                 {
2497                         partcount = 0;
2498                         
2499                         dir = random_turn(random, dir);
2500                         
2501                         partlength = random.range(1,length);
2502
2503                         make_stairs = 0;
2504                         if(random.next()%2 == 0 && partlength >= 3)
2505                                 make_stairs = random.next()%2 ? 1 : -1;
2506                 }
2507         }
2508         result_place = p0;
2509         result_dir = dir;
2510 }
2511
2512 class RoomWalker
2513 {
2514 public:
2515
2516         RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random):
2517                         vmanip(vmanip_),
2518                         m_pos(pos),
2519                         m_random(random)
2520         {
2521                 randomizeDir();
2522         }
2523
2524         void randomizeDir()
2525         {
2526                 m_dir = rand_ortho_dir(m_random);
2527         }
2528
2529         void setPos(v3s16 pos)
2530         {
2531                 m_pos = pos;
2532         }
2533
2534         void setDir(v3s16 dir)
2535         {
2536                 m_dir = dir;
2537         }
2538         
2539         bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
2540         {
2541                 for(u32 i=0; i<100; i++)
2542                 {
2543                         v3s16 p = m_pos + m_dir;
2544                         v3s16 p1 = p + v3s16(0,1,0);
2545                         if(vmanip.m_area.contains(p) == false
2546                                         || vmanip.m_area.contains(p1) == false
2547                                         || i % 4 == 0)
2548                         {
2549                                 randomizeDir();
2550                                 continue;
2551                         }
2552                         if(vmanip.getNodeNoExNoEmerge(p).d
2553                                         == CONTENT_COBBLE
2554                         && vmanip.getNodeNoExNoEmerge(p1).d
2555                                         == CONTENT_COBBLE)
2556                         {
2557                                 // Found wall, this is a good place!
2558                                 result_place = p;
2559                                 result_dir = m_dir;
2560                                 // Randomize next direction
2561                                 randomizeDir();
2562                                 return true;
2563                         }
2564                         /*
2565                                 Determine where to move next
2566                         */
2567                         // Jump one up if the actual space is there
2568                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
2569                                         == CONTENT_COBBLE
2570                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
2571                                         == CONTENT_AIR
2572                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).d
2573                                         == CONTENT_AIR)
2574                                 p += v3s16(0,1,0);
2575                         // Jump one down if the actual space is there
2576                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
2577                                         == CONTENT_COBBLE
2578                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
2579                                         == CONTENT_AIR
2580                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).d
2581                                         == CONTENT_AIR)
2582                                 p += v3s16(0,-1,0);
2583                         // Check if walking is now possible
2584                         if(vmanip.getNodeNoExNoEmerge(p).d
2585                                         != CONTENT_AIR
2586                         || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
2587                                         != CONTENT_AIR)
2588                         {
2589                                 // Cannot continue walking here
2590                                 randomizeDir();
2591                                 continue;
2592                         }
2593                         // Move there
2594                         m_pos = p;
2595                 }
2596                 return false;
2597         }
2598
2599         bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
2600                         v3s16 &result_doordir, v3s16 &result_roomplace)
2601         {
2602                 for(s16 trycount=0; trycount<30; trycount++)
2603                 {
2604                         v3s16 doorplace;
2605                         v3s16 doordir;
2606                         bool r = findPlaceForDoor(doorplace, doordir);
2607                         if(r == false)
2608                                 continue;
2609                         v3s16 roomplace;
2610                         // X east, Z north, Y up
2611                         if(doordir == v3s16(1,0,0)) // X+
2612                                 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
2613                         if(doordir == v3s16(-1,0,0)) // X-
2614                                 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
2615                         if(doordir == v3s16(0,0,1)) // Z+
2616                                 roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,0);
2617                         if(doordir == v3s16(0,0,-1)) // Z-
2618                                 roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,-roomsize.Z+1);
2619                         
2620                         // Check fit
2621                         bool fits = true;
2622                         for(s16 z=1; z<roomsize.Z-1; z++)
2623                         for(s16 y=1; y<roomsize.Y-1; y++)
2624                         for(s16 x=1; x<roomsize.X-1; x++)
2625                         {
2626                                 v3s16 p = roomplace + v3s16(x,y,z);
2627                                 if(vmanip.m_area.contains(p) == false)
2628                                 {
2629                                         fits = false;
2630                                         break;
2631                                 }
2632                                 if(vmanip.m_flags[vmanip.m_area.index(p)]
2633                                                 & VMANIP_FLAG_DUNGEON_INSIDE)
2634                                 {
2635                                         fits = false;
2636                                         break;
2637                                 }
2638                         }
2639                         if(fits == false)
2640                         {
2641                                 // Find new place
2642                                 continue;
2643                         }
2644                         result_doorplace = doorplace;
2645                         result_doordir = doordir;
2646                         result_roomplace = roomplace;
2647                         return true;
2648                 }
2649                 return false;
2650         }
2651
2652 private:
2653         VoxelManipulator &vmanip;
2654         v3s16 m_pos;
2655         v3s16 m_dir;
2656         PseudoRandom &m_random;
2657 };
2658
2659 void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
2660 {
2661         v3s16 areasize = vmanip.m_area.getExtent();
2662         v3s16 roomsize;
2663         v3s16 roomplace;
2664         
2665         /*
2666                 Find place for first room
2667         */
2668         bool fits = false;
2669         for(u32 i=0; i<100; i++)
2670         {
2671                 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
2672                 roomplace = vmanip.m_area.MinEdge + v3s16(
2673                                 random.range(0,areasize.X-roomsize.X-1),
2674                                 random.range(0,areasize.Y-roomsize.Y-1),
2675                                 random.range(0,areasize.Z-roomsize.Z-1));
2676                 /*
2677                         Check that we're not putting the room to an unknown place,
2678                         otherwise it might end up floating in the air
2679                 */
2680                 fits = true;
2681                 for(s16 z=1; z<roomsize.Z-1; z++)
2682                 for(s16 y=1; y<roomsize.Y-1; y++)
2683                 for(s16 x=1; x<roomsize.X-1; x++)
2684                 {
2685                         v3s16 p = roomplace + v3s16(x,y,z);
2686                         u32 vi = vmanip.m_area.index(p);
2687                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
2688                         {
2689                                 fits = false;
2690                                 break;
2691                         }
2692                         if(vmanip.m_data[vi].d == CONTENT_IGNORE)
2693                         {
2694                                 fits = false;
2695                                 break;
2696                         }
2697                 }
2698                 if(fits)
2699                         break;
2700         }
2701         // No place found
2702         if(fits == false)
2703                 return;
2704         
2705         /*
2706                 Stores the center position of the last room made, so that
2707                 a new corridor can be started from the last room instead of
2708                 the new room, if chosen so.
2709         */
2710         v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
2711         
2712         u32 room_count = random.range(2,7);
2713         for(u32 i=0; i<room_count; i++)
2714         {
2715                 // Make a room to the determined place
2716                 make_room1(vmanip, roomsize, roomplace);
2717                 
2718                 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
2719
2720                 // Place torch at room center (for testing)
2721                 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(CONTENT_TORCH);
2722
2723                 // Quit if last room
2724                 if(i == room_count-1)
2725                         break;
2726                 
2727                 // Determine walker start position
2728
2729                 bool start_in_last_room = (random.range(0,1)==0);
2730                 //bool start_in_last_room = true;
2731
2732                 v3s16 walker_start_place;
2733
2734                 if(start_in_last_room)
2735                 {
2736                         walker_start_place = last_room_center;
2737                 }
2738                 else
2739                 {
2740                         walker_start_place = room_center;
2741                         // Store center of current room as the last one
2742                         last_room_center = room_center;
2743                 }
2744                 
2745                 // Create walker and find a place for a door
2746                 RoomWalker walker(vmanip, walker_start_place, random);
2747                 v3s16 doorplace;
2748                 v3s16 doordir;
2749                 bool r = walker.findPlaceForDoor(doorplace, doordir);
2750                 if(r == false)
2751                         return;
2752                 
2753                 if(random.range(0,1)==0)
2754                         // Make the door
2755                         make_door1(vmanip, doorplace, doordir);
2756                 else
2757                         // Don't actually make a door
2758                         doorplace -= doordir;
2759                 
2760                 // Make a random corridor starting from the door
2761                 v3s16 corridor_end;
2762                 v3s16 corridor_end_dir;
2763                 make_corridor(vmanip, doorplace, doordir, corridor_end,
2764                                 corridor_end_dir, random);
2765                 
2766                 // Find a place for a random sized room
2767                 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
2768                 walker.setPos(corridor_end);
2769                 walker.setDir(corridor_end_dir);
2770                 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
2771                 if(r == false)
2772                         return;
2773
2774                 if(random.range(0,1)==0)
2775                         // Make the door
2776                         make_door1(vmanip, doorplace, doordir);
2777                 else
2778                         // Don't actually make a door
2779                         roomplace -= doordir;
2780                 
2781         }
2782 }
2783
2784 /*
2785         Noise functions. Make sure seed is mangled differently in each one.
2786 */
2787
2788 // This affects the shape of the contour
2789 //#define CAVE_NOISE_SCALE 10.0
2790 //#define CAVE_NOISE_SCALE 7.5
2791 #define CAVE_NOISE_SCALE 5.0
2792
2793 NoiseParams get_cave_noise1_params(u64 seed)
2794 {
2795         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
2796                         200, CAVE_NOISE_SCALE);*/
2797         return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
2798                         100, CAVE_NOISE_SCALE);
2799 }
2800
2801 NoiseParams get_cave_noise2_params(u64 seed)
2802 {
2803         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
2804                         200, CAVE_NOISE_SCALE);*/
2805         return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
2806                         100, CAVE_NOISE_SCALE);
2807 }
2808
2809 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
2810 #define CAVE_NOISE_THRESHOLD (2.0/CAVE_NOISE_SCALE)
2811
2812 NoiseParams get_ground_noise1_params(u64 seed)
2813 {
2814         return NoiseParams(NOISE_PERLIN, seed+983240, 5,
2815                         0.60, 100.0, 30.0);
2816 }
2817
2818 NoiseParams get_ground_crumbleness_params(u64 seed)
2819 {
2820         return NoiseParams(NOISE_PERLIN, seed+34413, 3,
2821                         1.3, 20.0, 1.0);
2822 }
2823
2824 NoiseParams get_ground_wetness_params(u64 seed)
2825 {
2826         return NoiseParams(NOISE_PERLIN, seed+32474, 4,
2827                         1.1, 40.0, 1.0);
2828 }
2829
2830 bool is_cave(u64 seed, v3s16 p)
2831 {
2832         double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
2833         double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
2834         return d1*d2 > CAVE_NOISE_THRESHOLD;
2835 }
2836
2837 /*
2838         Ground density noise shall be interpreted by using this.
2839
2840         TODO: No perlin noises here, they should be outsourced
2841               and buffered
2842 */
2843 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
2844 {
2845         //return ((double)p.Y < ground_noise1_val);
2846
2847         double f = 0.8 + noise2d_perlin(
2848                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
2849                         seed+920381, 3, 0.5);
2850         if(f < 0.01)
2851                 f = 0.01;
2852         else if(f >= 1.0)
2853                 f *= 2.0;
2854         double h = WATER_LEVEL + 10 * noise2d_perlin(
2855                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
2856                         seed+84174, 4, 0.5);
2857         return ((double)p.Y - h < ground_noise1_val * f);
2858 }
2859
2860 /*
2861         Queries whether a position is ground or not.
2862 */
2863 bool is_ground(u64 seed, v3s16 p)
2864 {
2865         double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
2866         return val_is_ground(val1, p, seed);
2867 }
2868
2869 // Amount of trees per area in nodes
2870 double tree_amount_2d(u64 seed, v2s16 p)
2871 {
2872         /*double noise = noise2d_perlin(
2873                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
2874                         seed+2, 5, 0.66);*/
2875         double noise = noise2d_perlin(
2876                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
2877                         seed+2, 4, 0.66);
2878         double zeroval = -0.35;
2879         if(noise < zeroval)
2880                 return 0;
2881         else
2882                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
2883 }
2884
2885 #if 0
2886 double randomstone_amount_2d(u64 seed, v2s16 p)
2887 {
2888         double noise = noise2d_perlin(
2889                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
2890                         seed+3829434, 5, 0.66);
2891         double zeroval = 0.1;
2892         if(noise < zeroval)
2893                 return 0;
2894         else
2895                 return 0.01 * (noise-zeroval) / (1.0-zeroval);
2896 }
2897 #endif
2898
2899 double largestone_amount_2d(u64 seed, v2s16 p)
2900 {
2901         double noise = noise2d_perlin(
2902                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
2903                         seed+14143242, 5, 0.66);
2904         double zeroval = 0.3;
2905         if(noise < zeroval)
2906                 return 0;
2907         else
2908                 return 0.005 * (noise-zeroval) / (1.0-zeroval);
2909 }
2910
2911 /*
2912         Incrementally find ground level from 3d noise
2913 */
2914 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
2915 {
2916         // Start a bit fuzzy to make averaging lower precision values
2917         // more useful
2918         s16 level = myrand_range(-precision/2, precision/2);
2919         s16 dec[] = {31000, 100, 20, 4, 1, 0};
2920         s16 i;
2921         for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
2922         {
2923                 // First find non-ground by going upwards
2924                 // Don't stop in caves.
2925                 {
2926                         s16 max = level+dec[i-1]*2;
2927                         v3s16 p(p2d.X, level, p2d.Y);
2928                         for(; p.Y < max; p.Y += dec[i])
2929                         {
2930                                 if(!is_ground(seed, p))
2931                                 {
2932                                         level = p.Y;
2933                                         break;
2934                                 }
2935                         }
2936                 }
2937                 // Then find ground by going downwards from there.
2938                 // Go in caves, too, when precision is 1.
2939                 {
2940                         s16 min = level-dec[i-1]*2;
2941                         v3s16 p(p2d.X, level, p2d.Y);
2942                         for(; p.Y>min; p.Y-=dec[i])
2943                         {
2944                                 bool ground = is_ground(seed, p);
2945                                 /*if(dec[i] == 1 && is_cave(seed, p))
2946                                         ground = false;*/
2947                                 if(ground)
2948                                 {
2949                                         level = p.Y;
2950                                         break;
2951                                 }
2952                         }
2953                 }
2954         }
2955         
2956         // This is more like the actual ground level
2957         level += dec[i-1]/2;
2958
2959         return level;
2960 }
2961
2962 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
2963
2964 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
2965 {
2966         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
2967         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
2968         double a = 0;
2969         a += find_ground_level_from_noise(seed,
2970                         v2s16(node_min.X, node_min.Y), p);
2971         a += find_ground_level_from_noise(seed,
2972                         v2s16(node_min.X, node_max.Y), p);
2973         a += find_ground_level_from_noise(seed,
2974                         v2s16(node_max.X, node_max.Y), p);
2975         a += find_ground_level_from_noise(seed,
2976                         v2s16(node_max.X, node_min.Y), p);
2977         a += find_ground_level_from_noise(seed,
2978                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
2979         a /= 5;
2980         return a;
2981 }
2982
2983 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
2984
2985 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
2986 {
2987         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
2988         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
2989         double a = -31000;
2990         a = MYMAX(a, find_ground_level_from_noise(seed,
2991                         v2s16(node_min.X, node_min.Y), p));
2992         a = MYMAX(a, find_ground_level_from_noise(seed,
2993                         v2s16(node_min.X, node_max.Y), p));
2994         a = MYMAX(a, find_ground_level_from_noise(seed,
2995                         v2s16(node_max.X, node_max.Y), p));
2996         a = MYMAX(a, find_ground_level_from_noise(seed,
2997                         v2s16(node_min.X, node_min.Y), p));
2998         a = MYMAX(a, find_ground_level_from_noise(seed,
2999                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
3000         return a;
3001 }
3002
3003 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
3004
3005 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
3006 {
3007         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
3008         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
3009         double a = 31000;
3010         a = MYMIN(a, find_ground_level_from_noise(seed,
3011                         v2s16(node_min.X, node_min.Y), p));
3012         a = MYMIN(a, find_ground_level_from_noise(seed,
3013                         v2s16(node_min.X, node_max.Y), p));
3014         a = MYMIN(a, find_ground_level_from_noise(seed,
3015                         v2s16(node_max.X, node_max.Y), p));
3016         a = MYMIN(a, find_ground_level_from_noise(seed,
3017                         v2s16(node_min.X, node_min.Y), p));
3018         a = MYMIN(a, find_ground_level_from_noise(seed,
3019                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
3020         return a;
3021 }
3022
3023 #if 0
3024 #define AVERAGE_MUD_AMOUNT 4
3025
3026 double base_rock_level_2d(u64 seed, v2s16 p)
3027 {
3028         // The base ground level
3029         double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
3030                         + 20. * noise2d_perlin(
3031                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
3032                         (seed>>32)+654879876, 6, 0.6);
3033
3034         /*// A bit hillier one
3035         double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
3036                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
3037                         (seed>>27)+90340, 6, 0.69);
3038         if(base2 > base)
3039                 base = base2;*/
3040 #if 1
3041         // Higher ground level
3042         double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
3043                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
3044                         seed+85039, 5, 0.69);
3045         //higher = 30; // For debugging
3046
3047         // Limit higher to at least base
3048         if(higher < base)
3049                 higher = base;
3050
3051         // Steepness factor of cliffs
3052         double b = 1.0 + 1.0 * noise2d_perlin(
3053                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
3054                         seed-932, 7, 0.7);
3055         b = rangelim(b, 0.0, 1000.0);
3056         b = pow(b, 5);
3057         b *= 7;
3058         b = rangelim(b, 3.0, 1000.0);
3059         //dstream<<"b="<<b<<std::endl;
3060         //double b = 20;
3061
3062         // Offset to more low
3063         double a_off = -0.2;
3064         // High/low selector
3065         /*double a = 0.5 + b * (a_off + noise2d_perlin(
3066                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
3067                         seed-359, 6, 0.7));*/
3068         double a = (double)0.5 + b * (a_off + noise2d_perlin(
3069                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
3070                         seed-359, 5, 0.60));
3071         // Limit
3072         a = rangelim(a, 0.0, 1.0);
3073
3074         //dstream<<"a="<<a<<std::endl;
3075
3076         double h = base*(1.0-a) + higher*a;
3077 #else
3078         double h = base;
3079 #endif
3080         return h;
3081 }
3082
3083 double get_mud_add_amount(u64 seed, v2s16 p)
3084 {
3085         return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
3086                         0.5+(float)p.X/200, 0.5+(float)p.Y/200,
3087                         seed+91013, 3, 0.55));
3088 }
3089 #endif
3090
3091 bool get_have_sand(u64 seed, v2s16 p2d)
3092 {
3093         // Determine whether to have sand here
3094         double sandnoise = noise2d_perlin(
3095                         0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
3096                         seed+59420, 3, 0.50);
3097
3098         return (sandnoise > -0.15);
3099 }
3100
3101 /*
3102         Adds random objects to block, depending on the content of the block
3103 */
3104 void addRandomObjects(MapBlock *block)
3105 {
3106         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3107         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3108         {
3109                 bool last_node_walkable = false;
3110                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3111                 {
3112                         v3s16 p(x0,y0,z0);
3113                         MapNode n = block->getNodeNoEx(p);
3114                         if(n.d == CONTENT_IGNORE)
3115                                 continue;
3116                         if(content_features(n.d).liquid_type != LIQUID_NONE)
3117                                 continue;
3118                         if(content_features(n.d).walkable)
3119                         {
3120                                 last_node_walkable = true;
3121                                 continue;
3122                         }
3123                         if(last_node_walkable)
3124                         {
3125                                 // If block contains light information
3126                                 if(content_features(n.d).param_type == CPT_LIGHT)
3127                                 {
3128                                         if(n.getLight(LIGHTBANK_DAY) <= 3)
3129                                         {
3130                                                 if(myrand() % 300 == 0)
3131                                                 {
3132                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
3133                                                         pos_f.Y -= BS*0.4;
3134                                                         ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
3135                                                         std::string data = obj->getStaticData();
3136                                                         StaticObject s_obj(obj->getType(),
3137                                                                         obj->getBasePosition(), data);
3138                                                         // Add some
3139                                                         block->m_static_objects.insert(0, s_obj);
3140                                                         block->m_static_objects.insert(0, s_obj);
3141                                                         block->m_static_objects.insert(0, s_obj);
3142                                                         block->m_static_objects.insert(0, s_obj);
3143                                                         block->m_static_objects.insert(0, s_obj);
3144                                                         block->m_static_objects.insert(0, s_obj);
3145                                                         delete obj;
3146                                                 }
3147                                                 if(myrand() % 1000 == 0)
3148                                                 {
3149                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
3150                                                         pos_f.Y -= BS*0.4;
3151                                                         ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
3152                                                         std::string data = obj->getStaticData();
3153                                                         StaticObject s_obj(obj->getType(),
3154                                                                         obj->getBasePosition(), data);
3155                                                         // Add one
3156                                                         block->m_static_objects.insert(0, s_obj);
3157                                                         delete obj;
3158                                                 }
3159                                         }
3160                                 }
3161                         }
3162                         last_node_walkable = false;
3163                 }
3164         }
3165         block->setChangedFlag();
3166 }
3167
3168 void makeBlock(BlockMakeData *data)
3169 {
3170         if(data->no_op)
3171         {
3172                 dstream<<"makeBlock: no-op"<<std::endl;
3173                 return;
3174         }
3175
3176         v3s16 blockpos = data->blockpos;
3177         
3178         /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
3179                         <<blockpos.Z<<")"<<std::endl;*/
3180
3181         ManualMapVoxelManipulator &vmanip = data->vmanip;
3182         v3s16 blockpos_min = blockpos - v3s16(1,1,1);
3183         v3s16 blockpos_max = blockpos + v3s16(1,1,1);
3184         // Area of center block
3185         v3s16 node_min = blockpos*MAP_BLOCKSIZE;
3186         v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
3187         // Full allocated area
3188         v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
3189         v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
3190         // Area of a block
3191         double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
3192
3193         v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
3194
3195         /*
3196                 Get average ground level from noise
3197         */
3198         
3199         s16 approx_groundlevel = (s16)get_sector_average_ground_level(
3200                         data->seed, v2s16(blockpos.X, blockpos.Z));
3201         //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
3202         
3203         s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
3204         
3205         s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
3206                         data->seed, v2s16(blockpos.X, blockpos.Z));
3207         // Minimum amount of ground above the top of the central block
3208         s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
3209
3210         s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
3211                         data->seed, v2s16(blockpos.X, blockpos.Z), 1);
3212         // Maximum amount of ground above the bottom of the central block
3213         s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
3214         
3215         /*
3216                 Special case for high air or water: Just fill with air and water.
3217         */
3218         if(maximum_ground_depth < -20)
3219         {
3220                 for(s16 x=node_min.X; x<=node_max.X; x++)
3221                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
3222                 {
3223                         // Node position
3224                         v2s16 p2d(x,z);
3225                         {
3226                                 // Use fast index incrementing
3227                                 v3s16 em = vmanip.m_area.getExtent();
3228                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
3229                                 for(s16 y=node_min.Y; y<=node_max.Y; y++)
3230                                 {
3231                                         // Only modify places that have no content
3232                                         if(vmanip.m_data[i].d == CONTENT_IGNORE)
3233                                         {
3234                                                 if(y <= WATER_LEVEL)
3235                                                         vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
3236                                                 else
3237                                                         vmanip.m_data[i] = MapNode(CONTENT_AIR);
3238                                         }
3239                                 
3240                                         data->vmanip.m_area.add_y(em, i, 1);
3241                                 }
3242                         }
3243                 }
3244                 
3245                 // We're done
3246                 return;
3247         }
3248
3249         /*
3250                 If block is deep underground, this is set to true and ground
3251                 density noise is not generated, for speed optimization.
3252         */
3253         bool all_is_ground_except_caves = (minimum_ground_depth > 16);
3254         
3255         /*
3256                 Create a block-specific seed
3257         */
3258         u32 blockseed = (data->seed%0x100000000) + full_node_min.Z*38134234
3259                         + full_node_min.Y*42123 + full_node_min.X*23;
3260         
3261         /*
3262                 Make some 3D noise
3263         */
3264         
3265         //NoiseBuffer noisebuf1;
3266         //NoiseBuffer noisebuf2;
3267         NoiseBuffer noisebuf_cave;
3268         NoiseBuffer noisebuf_ground;
3269         NoiseBuffer noisebuf_ground_crumbleness;
3270         NoiseBuffer noisebuf_ground_wetness;
3271         {
3272                 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
3273                 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
3274
3275                 //TimeTaker timer("noisebuf.create");
3276
3277                 /*
3278                         Cave noise
3279                 */
3280
3281                 noisebuf_cave.create(get_cave_noise1_params(data->seed),
3282                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
3283                                 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
3284                                 4, 3, 4);
3285                 
3286                 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
3287
3288                 /*
3289                         Ground noise
3290                 */
3291                 
3292                 // Sample length
3293                 v3f sl = v3f(4.0, 4.0, 4.0);
3294                 
3295                 /*
3296                         Density noise
3297                 */
3298                 if(all_is_ground_except_caves == false)
3299                         //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
3300                         noisebuf_ground.create(get_ground_noise1_params(data->seed),
3301                                         minpos_f.X, minpos_f.Y, minpos_f.Z,
3302                                         maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
3303                                         sl.X, sl.Y, sl.Z);
3304                 
3305                 /*
3306                         Ground property noise
3307                 */
3308                 sl = v3f(2.5, 2.5, 2.5);
3309                 noisebuf_ground_crumbleness.create(
3310                                 get_ground_crumbleness_params(data->seed),
3311                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
3312                                 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
3313                                 sl.X, sl.Y, sl.Z);
3314                 noisebuf_ground_wetness.create(
3315                                 get_ground_wetness_params(data->seed),
3316                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
3317                                 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
3318                                 sl.X, sl.Y, sl.Z);
3319         }
3320         
3321         /*
3322                 Make base ground level
3323         */
3324
3325         for(s16 x=node_min.X; x<=node_max.X; x++)
3326         for(s16 z=node_min.Z; z<=node_max.Z; z++)
3327         {
3328                 // Node position
3329                 v2s16 p2d(x,z);
3330                 {
3331                         // Use fast index incrementing
3332                         v3s16 em = vmanip.m_area.getExtent();
3333                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
3334                         for(s16 y=node_min.Y; y<=node_max.Y; y++)
3335                         {
3336                                 // Only modify places that have no content
3337                                 if(vmanip.m_data[i].d == CONTENT_IGNORE)
3338                                 {
3339                                         // First priority: make air and water.
3340                                         // This avoids caves inside water.
3341                                         if(all_is_ground_except_caves == false
3342                                                         && val_is_ground(noisebuf_ground.get(x,y,z),
3343                                                         v3s16(x,y,z), data->seed) == false)
3344                                         {
3345                                                 if(y <= WATER_LEVEL)
3346                                                         vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
3347                                                 else
3348                                                         vmanip.m_data[i] = MapNode(CONTENT_AIR);
3349                                         }
3350                                         else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
3351                                                 vmanip.m_data[i] = MapNode(CONTENT_AIR);
3352                                         else
3353                                                 vmanip.m_data[i] = MapNode(CONTENT_STONE);
3354                                 }
3355                         
3356                                 data->vmanip.m_area.add_y(em, i, 1);
3357                         }
3358                 }
3359         }
3360
3361         /*
3362                 Add minerals
3363         */
3364
3365         {
3366                 PseudoRandom mineralrandom(blockseed);
3367
3368                 /*
3369                         Add meseblocks
3370                 */
3371                 for(s16 i=0; i<approx_ground_depth/4; i++)
3372                 {
3373                         if(mineralrandom.next()%50 == 0)
3374                         {
3375                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3376                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3377                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3378                                 for(u16 i=0; i<27; i++)
3379                                 {
3380                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3381                                         u32 vi = vmanip.m_area.index(p);
3382                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
3383                                                 if(mineralrandom.next()%8 == 0)
3384                                                         vmanip.m_data[vi] = MapNode(CONTENT_MESE);
3385                                 }
3386                                         
3387                         }
3388                 }
3389                 /*
3390                         Add others
3391                 */
3392                 {
3393                         u16 a = mineralrandom.range(0,15);
3394                         a = a*a*a;
3395                         u16 amount = 20 * a/1000;
3396                         for(s16 i=0; i<amount; i++)
3397                         {
3398                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3399                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3400                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3401
3402                                 u8 base_content = CONTENT_STONE;
3403                                 MapNode new_content(CONTENT_IGNORE);
3404                                 u32 sparseness = 6;
3405
3406                                 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
3407                                 {
3408                                         new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
3409                                 }
3410                                 else
3411                                 {
3412                                         if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
3413                                                 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
3414                                         /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
3415                                                 vmanip.m_data[i] = MapNode(CONTENT_MUD);
3416                                         else
3417                                                 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
3418                                 }
3419                                 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
3420                                 {
3421                                 }*/
3422
3423                                 if(new_content.d != CONTENT_IGNORE)
3424                                 {
3425                                         for(u16 i=0; i<27; i++)
3426                                         {
3427                                                 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3428                                                 u32 vi = vmanip.m_area.index(p);
3429                                                 if(vmanip.m_data[vi].d == base_content)
3430                                                 {
3431                                                         if(mineralrandom.next()%sparseness == 0)
3432                                                                 vmanip.m_data[vi] = new_content;
3433                                                 }
3434                                         }
3435                                 }
3436                         }
3437                 }
3438                 /*
3439                         Add coal
3440                 */
3441                 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
3442                 //for(s16 i=0; i<50; i++)
3443                 u16 coal_amount = 30;
3444                 u16 coal_rareness = 60 / coal_amount;
3445                 if(coal_rareness == 0)
3446                         coal_rareness = 1;
3447                 if(mineralrandom.next()%coal_rareness == 0)
3448                 {
3449                         u16 a = mineralrandom.next() % 16;
3450                         u16 amount = coal_amount * a*a*a / 1000;
3451                         for(s16 i=0; i<amount; i++)
3452                         {
3453                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3454                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3455                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3456                                 for(u16 i=0; i<27; i++)
3457                                 {
3458                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3459                                         u32 vi = vmanip.m_area.index(p);
3460                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
3461                                                 if(mineralrandom.next()%8 == 0)
3462                                                         vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
3463                                 }
3464                         }
3465                 }
3466                 /*
3467                         Add iron
3468                 */
3469                 u16 iron_amount = 8;
3470                 u16 iron_rareness = 60 / iron_amount;
3471                 if(iron_rareness == 0)
3472                         iron_rareness = 1;
3473                 if(mineralrandom.next()%iron_rareness == 0)
3474                 {
3475                         u16 a = mineralrandom.next() % 16;
3476                         u16 amount = iron_amount * a*a*a / 1000;
3477                         for(s16 i=0; i<amount; i++)
3478                         {
3479                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3480                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3481                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3482                                 for(u16 i=0; i<27; i++)
3483                                 {
3484                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3485                                         u32 vi = vmanip.m_area.index(p);
3486                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
3487                                                 if(mineralrandom.next()%8 == 0)
3488                                                         vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
3489                                 }
3490                         }
3491                 }
3492         }
3493
3494         /*
3495                 Add mud and sand and others underground (in place of stone)
3496         */
3497
3498         for(s16 x=node_min.X; x<=node_max.X; x++)
3499         for(s16 z=node_min.Z; z<=node_max.Z; z++)
3500         {
3501                 // Node position
3502                 v2s16 p2d(x,z);
3503                 {
3504                         // Use fast index incrementing
3505                         v3s16 em = vmanip.m_area.getExtent();
3506                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
3507                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
3508                         {
3509                                 if(vmanip.m_data[i].d == CONTENT_STONE)
3510                                 {
3511                                         if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
3512                                         {
3513                                                 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
3514                                                         vmanip.m_data[i] = MapNode(CONTENT_MUD);
3515                                                 else
3516                                                         vmanip.m_data[i] = MapNode(CONTENT_SAND);
3517                                         }
3518                                         else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
3519                                         {
3520                                                 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
3521                                                         vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
3522                                         }
3523                                 }
3524
3525                                 data->vmanip.m_area.add_y(em, i, -1);
3526                         }
3527                 }
3528         }
3529
3530         /*
3531                 Add dungeons
3532         */
3533         
3534         //if(node_min.Y < approx_groundlevel)
3535         //if(myrand() % 3 == 0)
3536         //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
3537         //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
3538         //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
3539         float dungeon_rarity = 0.02;
3540         if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
3541                         < dungeon_rarity
3542                         && node_min.Y < approx_groundlevel)
3543         {
3544                 // Dungeon generator doesn't modify places which have this set
3545                 data->vmanip.clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
3546                                 | VMANIP_FLAG_DUNGEON_PRESERVE);
3547                 
3548                 // Set all air and water to be untouchable to make dungeons open
3549                 // to caves and open air
3550                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
3551                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
3552                 {
3553                         // Node position
3554                         v2s16 p2d(x,z);
3555                         {
3556                                 // Use fast index incrementing
3557                                 v3s16 em = vmanip.m_area.getExtent();
3558                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
3559                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
3560                                 {
3561                                         if(vmanip.m_data[i].d == CONTENT_AIR)
3562                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
3563                                         else if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
3564                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
3565                                         data->vmanip.m_area.add_y(em, i, -1);
3566                                 }
3567                         }
3568                 }
3569                 
3570                 PseudoRandom random(blockseed+2);
3571
3572                 // Add it
3573                 make_dungeon1(data->vmanip, random);
3574                 
3575                 // Convert some cobble to mossy cobble
3576                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
3577                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
3578                 {
3579                         // Node position
3580                         v2s16 p2d(x,z);
3581                         {
3582                                 // Use fast index incrementing
3583                                 v3s16 em = vmanip.m_area.getExtent();
3584                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
3585                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
3586                                 {
3587                                         // (noisebuf not used because it doesn't contain the
3588                                         //  full area)
3589                                         double wetness = noise3d_param(
3590                                                         get_ground_wetness_params(data->seed), x,y,z);
3591                                         double d = noise3d_perlin((float)x/2.5,
3592                                                         (float)y/2.5,(float)z/2.5,
3593                                                         blockseed, 2, 1.4);
3594                                         if(vmanip.m_data[i].d == CONTENT_COBBLE)
3595                                         {
3596                                                 if(d < wetness/3.0)
3597                                                 {
3598                                                         vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE;
3599                                                 }
3600                                         }
3601                                         /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
3602                                         {
3603                                                 if(wetness > 1.2)
3604                                                         vmanip.m_data[i].d = CONTENT_MUD;
3605                                         }*/
3606                                         data->vmanip.m_area.add_y(em, i, -1);
3607                                 }
3608                         }
3609                 }
3610         }
3611         
3612         /*
3613                 Add top and bottom side of water to transforming_liquid queue
3614         */
3615
3616         for(s16 x=node_min.X; x<=node_max.X; x++)
3617         for(s16 z=node_min.Z; z<=node_max.Z; z++)
3618         {
3619                 // Node position
3620                 v2s16 p2d(x,z);
3621                 {
3622                         bool water_found = false;
3623                         // Use fast index incrementing
3624                         v3s16 em = vmanip.m_area.getExtent();
3625                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
3626                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
3627                         {
3628                                 if(water_found == false)
3629                                 {
3630                                         if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
3631                                         {
3632                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
3633                                                 data->transforming_liquid.push_back(p);
3634                                                 water_found = true;
3635                                         }
3636                                 }
3637                                 else
3638                                 {
3639                                         // This can be done because water_found can only
3640                                         // turn to true and end up here after going through
3641                                         // a single block.
3642                                         if(vmanip.m_data[i+1].d != CONTENT_WATERSOURCE)
3643                                         {
3644                                                 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
3645                                                 data->transforming_liquid.push_back(p);
3646                                                 water_found = false;
3647                                         }
3648                                 }
3649
3650                                 data->vmanip.m_area.add_y(em, i, -1);
3651                         }
3652                 }
3653         }
3654
3655         /*
3656                 If close to ground level
3657         */
3658
3659         //if(abs(approx_ground_depth) < 30)
3660         if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
3661         {
3662                 /*
3663                         Add grass and mud
3664                 */
3665
3666                 for(s16 x=node_min.X; x<=node_max.X; x++)
3667                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
3668                 {
3669                         // Node position
3670                         v2s16 p2d(x,z);
3671                         {
3672                                 bool possibly_have_sand = get_have_sand(data->seed, p2d);
3673                                 bool have_sand = false;
3674                                 u32 current_depth = 0;
3675                                 bool air_detected = false;
3676                                 bool water_detected = false;
3677                                 // Use fast index incrementing
3678                                 s16 start_y = node_max.Y+2;
3679                                 v3s16 em = vmanip.m_area.getExtent();
3680                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
3681                                 for(s16 y=start_y; y>=node_min.Y-3; y--)
3682                                 {
3683                                         if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
3684                                                 water_detected = true;
3685                                         if(vmanip.m_data[i].d == CONTENT_AIR)
3686                                                 air_detected = true;
3687
3688                                         if((vmanip.m_data[i].d == CONTENT_STONE
3689                                                         || vmanip.m_data[i].d == CONTENT_GRASS
3690                                                         || vmanip.m_data[i].d == CONTENT_MUD
3691                                                         || vmanip.m_data[i].d == CONTENT_SAND
3692                                                         || vmanip.m_data[i].d == CONTENT_GRAVEL
3693                                                         ) && (air_detected || water_detected))
3694                                         {
3695                                                 if(current_depth == 0 && y <= WATER_LEVEL+2
3696                                                                 && possibly_have_sand)
3697                                                         have_sand = true;
3698                                                 
3699                                                 if(current_depth < 4)
3700                                                 {
3701                                                         if(have_sand)
3702                                                         {
3703                                                                 vmanip.m_data[i] = MapNode(CONTENT_SAND);
3704                                                         }
3705                                                         #if 1
3706                                                         else if(current_depth==0 && !water_detected
3707                                                                         && y >= WATER_LEVEL && air_detected)
3708                                                                 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
3709                                                         #endif
3710                                                         else
3711                                                                 vmanip.m_data[i] = MapNode(CONTENT_MUD);
3712                                                 }
3713                                                 else
3714                                                 {
3715                                                         if(vmanip.m_data[i].d == CONTENT_MUD
3716                                                                 || vmanip.m_data[i].d == CONTENT_GRASS)
3717                                                                 vmanip.m_data[i] = MapNode(CONTENT_STONE);
3718                                                 }
3719
3720                                                 current_depth++;
3721
3722                                                 if(current_depth >= 8)
3723                                                         break;
3724                                         }
3725                                         else if(current_depth != 0)
3726                                                 break;
3727
3728                                         data->vmanip.m_area.add_y(em, i, -1);
3729                                 }
3730                         }
3731                 }
3732
3733                 /*
3734                         Add trees
3735                 */
3736                 
3737                 // Amount of trees
3738                 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
3739                 PseudoRandom treerandom(blockseed);
3740                 // Put trees in random places on part of division
3741                 for(u32 i=0; i<tree_count; i++)
3742                 {
3743                         s16 x = treerandom.range(node_min.X, node_max.X);
3744                         s16 z = treerandom.range(node_min.Z, node_max.Z);
3745                         //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
3746                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
3747                         // Don't make a tree under water level
3748                         if(y < WATER_LEVEL)
3749                                 continue;
3750                         // Make sure tree fits (only trees whose starting point is
3751                         // at this block are added)
3752                         if(y < node_min.Y || y > node_max.Y)
3753                                 continue;
3754                         /*
3755                                 Find exact ground level
3756                         */
3757                         v3s16 p(x,y+6,z);
3758                         bool found = false;
3759                         for(; p.Y >= y-6; p.Y--)
3760                         {
3761                                 u32 i = data->vmanip.m_area.index(p);
3762                                 MapNode *n = &data->vmanip.m_data[i];
3763                                 if(n->d != CONTENT_AIR && n->d != CONTENT_IGNORE)
3764                                 {
3765                                         found = true;
3766                                         break;
3767                                 }
3768                         }
3769                         // If not found, handle next one
3770                         if(found == false)
3771                                 continue;
3772                         /*
3773                                 Trees grow only on mud and grass
3774                         */
3775                         {
3776                                 u32 i = data->vmanip.m_area.index(p);
3777                                 MapNode *n = &data->vmanip.m_data[i];
3778                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3779                                         continue;
3780                         }
3781                         // Tree will be placed one higher
3782                         p.Y++;
3783                         // Make a tree
3784                         make_tree(data->vmanip, p);
3785                 }
3786
3787 #if 0
3788                 /*
3789                         Add some kind of random stones
3790                 */
3791                 
3792                 u32 random_stone_count = block_area_nodes *
3793                                 randomstone_amount_2d(data->seed, p2d_center);
3794                 // Put in random places on part of division
3795                 for(u32 i=0; i<random_stone_count; i++)
3796                 {
3797                         s16 x = myrand_range(node_min.X, node_max.X);
3798                         s16 z = myrand_range(node_min.Z, node_max.Z);
3799                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
3800                         // Don't add under water level
3801                         /*if(y < WATER_LEVEL)
3802                                 continue;*/
3803                         // Don't add if doesn't belong to this block
3804                         if(y < node_min.Y || y > node_max.Y)
3805                                 continue;
3806                         v3s16 p(x,y,z);
3807                         // Filter placement
3808                         /*{
3809                                 u32 i = data->vmanip.m_area.index(v3s16(p));
3810                                 MapNode *n = &data->vmanip.m_data[i];
3811                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3812                                         continue;
3813                         }*/
3814                         // Will be placed one higher
3815                         p.Y++;
3816                         // Add it
3817                         make_randomstone(data->vmanip, p);
3818                 }
3819 #endif
3820
3821 #if 0
3822                 /*
3823                         Add larger stones
3824                 */
3825                 
3826                 u32 large_stone_count = block_area_nodes *
3827                                 largestone_amount_2d(data->seed, p2d_center);
3828                 //u32 large_stone_count = 1;
3829                 // Put in random places on part of division
3830                 for(u32 i=0; i<large_stone_count; i++)
3831                 {
3832                         s16 x = myrand_range(node_min.X, node_max.X);
3833                         s16 z = myrand_range(node_min.Z, node_max.Z);
3834                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
3835                         // Don't add under water level
3836                         /*if(y < WATER_LEVEL)
3837                                 continue;*/
3838                         // Don't add if doesn't belong to this block
3839                         if(y < node_min.Y || y > node_max.Y)
3840                                 continue;
3841                         v3s16 p(x,y,z);
3842                         // Filter placement
3843                         /*{
3844                                 u32 i = data->vmanip.m_area.index(v3s16(p));
3845                                 MapNode *n = &data->vmanip.m_data[i];
3846                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3847                                         continue;
3848                         }*/
3849                         // Will be placed one lower
3850                         p.Y--;
3851                         // Add it
3852                         make_largestone(data->vmanip, p);
3853                 }
3854 #endif
3855         }
3856
3857 }
3858
3859 void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
3860 {
3861         /*dstream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
3862                         <<blockpos.Z<<")"<<std::endl;*/
3863
3864         data->no_op = false;
3865         data->seed = m_seed;
3866         data->blockpos = blockpos;
3867
3868         /*
3869                 Create the whole area of this and the neighboring blocks
3870         */
3871         {
3872                 //TimeTaker timer("initBlockMake() create area");
3873                 
3874                 for(s16 x=-1; x<=1; x++)
3875                 for(s16 z=-1; z<=1; z++)
3876                 {
3877                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
3878                         // Sector metadata is loaded from disk if not already loaded.
3879                         ServerMapSector *sector = createSector(sectorpos);
3880                         assert(sector);
3881
3882                         for(s16 y=-1; y<=1; y++)
3883                         {
3884                                 MapBlock *block = createBlock(blockpos);
3885
3886                                 // Lighting won't be calculated
3887                                 block->setLightingExpired(true);
3888                                 // Lighting will be calculated
3889                                 //block->setLightingExpired(false);
3890
3891                                 /*
3892                                         Block gets sunlight if this is true.
3893
3894                                         This should be set to true when the top side of a block
3895                                         is completely exposed to the sky.
3896                                 */
3897                                 block->setIsUnderground(false);
3898                         }
3899                 }
3900         }
3901         
3902         /*
3903                 Now we have a big empty area.
3904
3905                 Make a ManualMapVoxelManipulator that contains this and the
3906                 neighboring blocks
3907         */
3908         
3909         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
3910         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
3911         
3912         data->vmanip.setMap(this);
3913
3914         // Add the area
3915         {
3916                 //TimeTaker timer("initBlockMake() initialEmerge");
3917                 data->vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
3918         }
3919
3920         // Data is ready now.
3921 }
3922
3923 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
3924                 core::map<v3s16, MapBlock*> &changed_blocks)
3925 {
3926         v3s16 blockpos = data->blockpos;
3927         /*dstream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
3928                         <<blockpos.Z<<")"<<std::endl;*/
3929
3930         if(data->no_op)
3931         {
3932                 dstream<<"finishBlockMake(): no-op"<<std::endl;
3933                 return NULL;
3934         }
3935
3936         /*dstream<<"Resulting vmanip:"<<std::endl;
3937         data->vmanip.print(dstream);*/
3938         
3939         /*
3940                 Blit generated stuff to map
3941                 NOTE: blitBackAll adds nearly everything to changed_blocks
3942         */
3943         {
3944                 // 70ms @cs=8
3945                 //TimeTaker timer("finishBlockMake() blitBackAll");
3946                 data->vmanip.blitBackAll(&changed_blocks);
3947         }
3948 #if 1
3949         dstream<<"finishBlockMake: changed_blocks.size()="
3950                         <<changed_blocks.size()<<std::endl;
3951 #endif
3952         /*
3953                 Copy transforming liquid information
3954         */
3955         while(data->transforming_liquid.size() > 0)
3956         {
3957                 v3s16 p = data->transforming_liquid.pop_front();
3958                 m_transforming_liquid.push_back(p);
3959         }
3960         
3961         /*
3962                 Get central block
3963         */
3964         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
3965         assert(block);
3966
3967         /*
3968                 Set is_underground flag for lighting with sunlight
3969         */
3970
3971         s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
3972                         data->seed, v2s16(blockpos.X, blockpos.Z));
3973         
3974         if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
3975                 block->setIsUnderground(true);
3976         else
3977                 block->setIsUnderground(false);
3978
3979         /*
3980                 Add sunlight to central block.
3981                 This makes in-dark-spawning monsters to not flood the whole thing.
3982                 Do not spread the light, though.
3983         */
3984         /*core::map<v3s16, bool> light_sources;
3985         bool black_air_left = false;
3986         block->propagateSunlight(light_sources, true, &black_air_left);*/
3987
3988         /*
3989                 NOTE: Lighting and object adding shouldn't really be here, but
3990                 lighting is a bit tricky to move properly to makeBlock.
3991                 TODO: Do this the right way anyway.
3992         */
3993
3994         /*
3995                 Update lighting
3996         */
3997
3998         core::map<v3s16, MapBlock*> lighting_update_blocks;
3999         // Center block
4000         lighting_update_blocks.insert(block->getPos(), block);
4001 #if 0
4002         // All modified blocks
4003         for(core::map<v3s16, MapBlock*>::Iterator
4004                         i = changed_blocks.getIterator();
4005                         i.atEnd() == false; i++)
4006         {
4007                 lighting_update_blocks.insert(i.getNode()->getKey(),
4008                                 i.getNode()->getValue());
4009         }
4010 #endif
4011         updateLighting(lighting_update_blocks, changed_blocks);
4012         
4013         /*
4014                 Add random objects to block
4015         */
4016         addRandomObjects(block);
4017
4018         /*
4019                 Go through changed blocks
4020         */
4021         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
4022                         i.atEnd() == false; i++)
4023         {
4024                 MapBlock *block = i.getNode()->getValue();
4025                 assert(block);
4026                 /*
4027                         Update day/night difference cache of the MapBlocks
4028                 */
4029                 block->updateDayNightDiff();
4030                 /*
4031                         Set block as modified
4032                 */
4033                 block->raiseModified(MOD_STATE_WRITE_NEEDED);
4034         }
4035
4036         /*
4037                 Set central block as generated
4038         */
4039         block->setGenerated(true);
4040         
4041         /*
4042                 Save changed parts of map
4043                 NOTE: Will be saved later.
4044         */
4045         //save(true);
4046
4047         /*dstream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
4048                         <<blockpos.Z<<")"<<std::endl;*/
4049         
4050         return block;
4051 }
4052
4053 ServerMapSector * ServerMap::createSector(v2s16 p2d)
4054 {
4055         DSTACKF("%s: p2d=(%d,%d)",
4056                         __FUNCTION_NAME,
4057                         p2d.X, p2d.Y);
4058         
4059         /*
4060                 Check if it exists already in memory
4061         */
4062         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
4063         if(sector != NULL)
4064                 return sector;
4065         
4066         /*
4067                 Try to load it from disk (with blocks)
4068         */
4069         //if(loadSectorFull(p2d) == true)
4070
4071         /*
4072                 Try to load metadata from disk
4073         */
4074         if(loadSectorMeta(p2d) == true)
4075         {
4076                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
4077                 if(sector == NULL)
4078                 {
4079                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
4080                         throw InvalidPositionException("");
4081                 }
4082                 return sector;
4083         }
4084
4085         /*
4086                 Do not create over-limit
4087         */
4088         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4089         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4090         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4091         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4092                 throw InvalidPositionException("createSector(): pos. over limit");
4093
4094         /*
4095                 Generate blank sector
4096         */
4097         
4098         sector = new ServerMapSector(this, p2d);
4099         
4100         // Sector position on map in nodes
4101         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
4102
4103         /*
4104                 Insert to container
4105         */
4106         m_sectors.insert(p2d, sector);
4107         
4108         return sector;
4109 }
4110
4111 /*
4112         This is a quick-hand function for calling makeBlock().
4113 */
4114 MapBlock * ServerMap::generateBlock(
4115                 v3s16 p,
4116                 core::map<v3s16, MapBlock*> &modified_blocks
4117 )
4118 {
4119         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
4120         
4121         /*dstream<<"generateBlock(): "
4122                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4123                         <<std::endl;*/
4124         
4125         TimeTaker timer("generateBlock");
4126         
4127         //MapBlock *block = original_dummy;
4128                         
4129         v2s16 p2d(p.X, p.Z);
4130         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
4131         
4132         /*
4133                 Do not generate over-limit
4134         */
4135         if(blockpos_over_limit(p))
4136         {
4137                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
4138                 throw InvalidPositionException("generateBlock(): pos. over limit");
4139         }
4140
4141         /*
4142                 Create block make data
4143         */
4144         BlockMakeData data;
4145         initBlockMake(&data, p);
4146
4147         /*
4148                 Generate block
4149         */
4150         {
4151                 TimeTaker t("makeBlock()");
4152                 makeBlock(&data);
4153         }
4154
4155         /*
4156                 Blit data back on map, update lighting, add mobs and whatever this does
4157         */
4158         finishBlockMake(&data, modified_blocks);
4159
4160         /*
4161                 Get central block
4162         */
4163         MapBlock *block = getBlockNoCreateNoEx(p);
4164         assert(block);
4165
4166 #if 0
4167         /*
4168                 Check result
4169         */
4170         bool erroneus_content = false;
4171         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4172         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4173         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4174         {
4175                 v3s16 p(x0,y0,z0);
4176                 MapNode n = block->getNode(p);
4177                 if(n.d == CONTENT_IGNORE)
4178                 {
4179                         dstream<<"CONTENT_IGNORE at "
4180                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4181                                         <<std::endl;
4182                         erroneus_content = true;
4183                         assert(0);
4184                 }
4185         }
4186         if(erroneus_content)
4187         {
4188                 assert(0);
4189         }
4190 #endif
4191
4192 #if 0
4193         /*
4194                 Generate a completely empty block
4195         */
4196         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4197         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4198         {
4199                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4200                 {
4201                         MapNode n;
4202                         if(y0%2==0)
4203                                 n.d = CONTENT_AIR;
4204                         else
4205                                 n.d = CONTENT_STONE;
4206                         block->setNode(v3s16(x0,y0,z0), n);
4207                 }
4208         }
4209 #endif
4210
4211         return block;
4212 }
4213
4214 MapBlock * ServerMap::createBlock(v3s16 p)
4215 {
4216         DSTACKF("%s: p=(%d,%d,%d)",
4217                         __FUNCTION_NAME, p.X, p.Y, p.Z);
4218         
4219         /*
4220                 Do not create over-limit
4221         */
4222         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4223         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4224         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4225         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4226         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4227         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4228                 throw InvalidPositionException("createBlock(): pos. over limit");
4229         
4230         v2s16 p2d(p.X, p.Z);
4231         s16 block_y = p.Y;
4232         /*
4233                 This will create or load a sector if not found in memory.
4234                 If block exists on disk, it will be loaded.
4235
4236                 NOTE: On old save formats, this will be slow, as it generates
4237                       lighting on blocks for them.
4238         */
4239         ServerMapSector *sector;
4240         try{
4241                 sector = (ServerMapSector*)createSector(p2d);
4242                 assert(sector->getId() == MAPSECTOR_SERVER);
4243         }
4244         catch(InvalidPositionException &e)
4245         {
4246                 dstream<<"createBlock: createSector() failed"<<std::endl;
4247                 throw e;
4248         }
4249         /*
4250                 NOTE: This should not be done, or at least the exception
4251                 should not be passed on as std::exception, because it
4252                 won't be catched at all.
4253         */
4254         /*catch(std::exception &e)
4255         {
4256                 dstream<<"createBlock: createSector() failed: "
4257                                 <<e.what()<<std::endl;
4258                 throw e;
4259         }*/
4260
4261         /*
4262                 Try to get a block from the sector
4263         */
4264
4265         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4266         if(block)
4267         {
4268                 if(block->isDummy())
4269                         block->unDummify();
4270                 return block;
4271         }
4272         // Create blank
4273         block = sector->createBlankBlock(block_y);
4274         return block;
4275 }
4276
4277 #if 0
4278 MapBlock * ServerMap::emergeBlock(
4279                 v3s16 p,
4280                 bool only_from_disk,
4281                 core::map<v3s16, MapBlock*> &changed_blocks,
4282                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
4283 )
4284 {
4285         DSTACKF("%s: p=(%d,%d,%d), only_from_disk=%d",
4286                         __FUNCTION_NAME,
4287                         p.X, p.Y, p.Z, only_from_disk);
4288         
4289         // This has to be redone or removed
4290         assert(0);
4291         return NULL;
4292 }
4293 #endif
4294
4295 #if 0
4296         /*
4297                 Do not generate over-limit
4298         */
4299         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4300         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4301         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4302         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4303         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4304         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4305                 throw InvalidPositionException("emergeBlock(): pos. over limit");
4306         
4307         v2s16 p2d(p.X, p.Z);
4308         s16 block_y = p.Y;
4309         /*
4310                 This will create or load a sector if not found in memory.
4311                 If block exists on disk, it will be loaded.
4312         */
4313         ServerMapSector *sector;
4314         try{
4315                 sector = createSector(p2d);
4316                 //sector = emergeSector(p2d, changed_blocks);
4317         }
4318         catch(InvalidPositionException &e)
4319         {
4320                 dstream<<"emergeBlock: createSector() failed: "
4321                                 <<e.what()<<std::endl;
4322                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4323                                 <<std::endl
4324                                 <<"You could try to delete it."<<std::endl;
4325                 throw e;
4326         }
4327         catch(VersionMismatchException &e)
4328         {
4329                 dstream<<"emergeBlock: createSector() failed: "
4330                                 <<e.what()<<std::endl;
4331                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4332                                 <<std::endl
4333                                 <<"You could try to delete it."<<std::endl;
4334                 throw e;
4335         }
4336
4337         /*
4338                 Try to get a block from the sector
4339         */
4340
4341         bool does_not_exist = false;
4342         bool lighting_expired = false;
4343         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4344         
4345         // If not found, try loading from disk
4346         if(block == NULL)
4347         {
4348                 block = loadBlock(p);
4349         }
4350         
4351         // Handle result
4352         if(block == NULL)
4353         {
4354                 does_not_exist = true;
4355         }
4356         else if(block->isDummy() == true)
4357         {
4358                 does_not_exist = true;
4359         }
4360         else if(block->getLightingExpired())
4361         {
4362                 lighting_expired = true;
4363         }
4364         else
4365         {
4366                 // Valid block
4367                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
4368                 return block;
4369         }
4370         
4371         /*
4372                 If block was not found on disk and not going to generate a
4373                 new one, make sure there is a dummy block in place.
4374         */
4375         if(only_from_disk && (does_not_exist || lighting_expired))
4376         {
4377                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
4378
4379                 if(block == NULL)
4380                 {
4381                         // Create dummy block
4382                         block = new MapBlock(this, p, true);
4383
4384                         // Add block to sector
4385                         sector->insertBlock(block);
4386                 }
4387                 // Done.
4388                 return block;
4389         }
4390
4391         //dstream<<"Not found on disk, generating."<<std::endl;
4392         // 0ms
4393         //TimeTaker("emergeBlock() generate");
4394
4395         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
4396
4397         /*
4398                 If the block doesn't exist, generate the block.
4399         */
4400         if(does_not_exist)
4401         {
4402                 block = generateBlock(p, block, sector, changed_blocks,
4403                                 lighting_invalidated_blocks); 
4404         }
4405
4406         if(lighting_expired)
4407         {
4408                 lighting_invalidated_blocks.insert(p, block);
4409         }
4410
4411 #if 0
4412         /*
4413                 Initially update sunlight
4414         */
4415         {
4416                 core::map<v3s16, bool> light_sources;
4417                 bool black_air_left = false;
4418                 bool bottom_invalid =
4419                                 block->propagateSunlight(light_sources, true,
4420                                 &black_air_left);
4421
4422                 // If sunlight didn't reach everywhere and part of block is
4423                 // above ground, lighting has to be properly updated
4424                 //if(black_air_left && some_part_underground)
4425                 if(black_air_left)
4426                 {
4427                         lighting_invalidated_blocks[block->getPos()] = block;
4428                 }
4429
4430                 if(bottom_invalid)
4431                 {
4432                         lighting_invalidated_blocks[block->getPos()] = block;
4433                 }
4434         }
4435 #endif
4436         
4437         return block;
4438 }
4439 #endif
4440
4441 s16 ServerMap::findGroundLevel(v2s16 p2d)
4442 {
4443 #if 0
4444         /*
4445                 Uh, just do something random...
4446         */
4447         // Find existing map from top to down
4448         s16 max=63;
4449         s16 min=-64;
4450         v3s16 p(p2d.X, max, p2d.Y);
4451         for(; p.Y>min; p.Y--)
4452         {
4453                 MapNode n = getNodeNoEx(p);
4454                 if(n.d != CONTENT_IGNORE)
4455                         break;
4456         }
4457         if(p.Y == min)
4458                 goto plan_b;
4459         // If this node is not air, go to plan b
4460         if(getNodeNoEx(p).d != CONTENT_AIR)
4461                 goto plan_b;
4462         // Search existing walkable and return it
4463         for(; p.Y>min; p.Y--)
4464         {
4465                 MapNode n = getNodeNoEx(p);
4466                 if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
4467                         return p.Y;
4468         }
4469
4470         // Move to plan b
4471 plan_b:
4472 #endif
4473
4474         /*
4475                 Determine from map generator noise functions
4476         */
4477         
4478         s16 level = find_ground_level_from_noise(m_seed, p2d, 1);
4479         return level;
4480
4481         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
4482         //return (s16)level;
4483 }
4484
4485 void ServerMap::createDirs(std::string path)
4486 {
4487         if(fs::CreateAllDirs(path) == false)
4488         {
4489                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
4490                                 <<"\""<<path<<"\""<<std::endl;
4491                 throw BaseException("ServerMap failed to create directory");
4492         }
4493 }
4494
4495 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
4496 {
4497         char cc[9];
4498         switch(layout)
4499         {
4500                 case 1:
4501                         snprintf(cc, 9, "%.4x%.4x",
4502                                 (unsigned int)pos.X&0xffff,
4503                                 (unsigned int)pos.Y&0xffff);
4504
4505                         return m_savedir + "/sectors/" + cc;
4506                 case 2:
4507                         snprintf(cc, 9, "%.3x/%.3x",
4508                                 (unsigned int)pos.X&0xfff,
4509                                 (unsigned int)pos.Y&0xfff);
4510
4511                         return m_savedir + "/sectors2/" + cc;
4512                 default:
4513                         assert(false);
4514         }
4515 }
4516
4517 v2s16 ServerMap::getSectorPos(std::string dirname)
4518 {
4519         unsigned int x, y;
4520         int r;
4521         size_t spos = dirname.rfind('/') + 1;
4522         assert(spos != std::string::npos);
4523         if(dirname.size() - spos == 8)
4524         {
4525                 // Old layout
4526                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
4527         }
4528         else if(dirname.size() - spos == 3)
4529         {
4530                 // New layout
4531                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
4532                 // Sign-extend the 12 bit values up to 16 bits...
4533                 if(x&0x800) x|=0xF000;
4534                 if(y&0x800) y|=0xF000;
4535         }
4536         else
4537         {
4538                 assert(false);
4539         }
4540         assert(r == 2);
4541         v2s16 pos((s16)x, (s16)y);
4542         return pos;
4543 }
4544
4545 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
4546 {
4547         v2s16 p2d = getSectorPos(sectordir);
4548
4549         if(blockfile.size() != 4){
4550                 throw InvalidFilenameException("Invalid block filename");
4551         }
4552         unsigned int y;
4553         int r = sscanf(blockfile.c_str(), "%4x", &y);
4554         if(r != 1)
4555                 throw InvalidFilenameException("Invalid block filename");
4556         return v3s16(p2d.X, y, p2d.Y);
4557 }
4558
4559 std::string ServerMap::getBlockFilename(v3s16 p)
4560 {
4561         char cc[5];
4562         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
4563         return cc;
4564 }
4565
4566 void ServerMap::save(bool only_changed)
4567 {
4568         DSTACK(__FUNCTION_NAME);
4569         if(m_map_saving_enabled == false)
4570         {
4571                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
4572                 return;
4573         }
4574         
4575         if(only_changed == false)
4576                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
4577                                 <<std::endl;
4578         
4579         if(only_changed == false || m_map_metadata_changed)
4580         {
4581                 saveMapMeta();
4582         }
4583
4584         u32 sector_meta_count = 0;
4585         u32 block_count = 0;
4586         u32 block_count_all = 0; // Number of blocks in memory
4587         
4588         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
4589         for(; i.atEnd() == false; i++)
4590         {
4591                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
4592                 assert(sector->getId() == MAPSECTOR_SERVER);
4593         
4594                 if(sector->differs_from_disk || only_changed == false)
4595                 {
4596                         saveSectorMeta(sector);
4597                         sector_meta_count++;
4598                 }
4599                 core::list<MapBlock*> blocks;
4600                 sector->getBlocks(blocks);
4601                 core::list<MapBlock*>::Iterator j;
4602                 for(j=blocks.begin(); j!=blocks.end(); j++)
4603                 {
4604                         MapBlock *block = *j;
4605                         
4606                         block_count_all++;
4607
4608                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
4609                                         || only_changed == false)
4610                         {
4611                                 saveBlock(block);
4612                                 block_count++;
4613
4614                                 /*dstream<<"ServerMap: Written block ("
4615                                                 <<block->getPos().X<<","
4616                                                 <<block->getPos().Y<<","
4617                                                 <<block->getPos().Z<<")"
4618                                                 <<std::endl;*/
4619                         }
4620                 }
4621         }
4622
4623         /*
4624                 Only print if something happened or saved whole map
4625         */
4626         if(only_changed == false || sector_meta_count != 0
4627                         || block_count != 0)
4628         {
4629                 dstream<<DTIME<<"ServerMap: Written: "
4630                                 <<sector_meta_count<<" sector metadata files, "
4631                                 <<block_count<<" block files"
4632                                 <<", "<<block_count_all<<" blocks in memory."
4633                                 <<std::endl;
4634         }
4635 }
4636
4637 void ServerMap::saveMapMeta()
4638 {
4639         DSTACK(__FUNCTION_NAME);
4640         
4641         dstream<<"INFO: ServerMap::saveMapMeta(): "
4642                         <<"seed="<<m_seed
4643                         <<std::endl;
4644
4645         createDirs(m_savedir);
4646         
4647         std::string fullpath = m_savedir + "/map_meta.txt";
4648         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
4649         if(os.good() == false)
4650         {
4651                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
4652                                 <<"could not open"<<fullpath<<std::endl;
4653                 throw FileNotGoodException("Cannot open chunk metadata");
4654         }
4655         
4656         Settings params;
4657         params.setU64("seed", m_seed);
4658
4659         params.writeLines(os);
4660
4661         os<<"[end_of_params]\n";
4662         
4663         m_map_metadata_changed = false;
4664 }
4665
4666 void ServerMap::loadMapMeta()
4667 {
4668         DSTACK(__FUNCTION_NAME);
4669         
4670         dstream<<"INFO: ServerMap::loadMapMeta(): Loading map metadata"
4671                         <<std::endl;
4672
4673         std::string fullpath = m_savedir + "/map_meta.txt";
4674         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4675         if(is.good() == false)
4676         {
4677                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
4678                                 <<"could not open"<<fullpath<<std::endl;
4679                 throw FileNotGoodException("Cannot open map metadata");
4680         }
4681
4682         Settings params;
4683
4684         for(;;)
4685         {
4686                 if(is.eof())
4687                         throw SerializationError
4688                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
4689                 std::string line;
4690                 std::getline(is, line);
4691                 std::string trimmedline = trim(line);
4692                 if(trimmedline == "[end_of_params]")
4693                         break;
4694                 params.parseConfigLine(line);
4695         }
4696
4697         m_seed = params.getU64("seed");
4698
4699         dstream<<"INFO: ServerMap::loadMapMeta(): "
4700                         <<"seed="<<m_seed
4701                         <<std::endl;
4702 }
4703
4704 void ServerMap::saveSectorMeta(ServerMapSector *sector)
4705 {
4706         DSTACK(__FUNCTION_NAME);
4707         // Format used for writing
4708         u8 version = SER_FMT_VER_HIGHEST;
4709         // Get destination
4710         v2s16 pos = sector->getPos();
4711         std::string dir = getSectorDir(pos);
4712         createDirs(dir);
4713         
4714         std::string fullpath = dir + "/meta";
4715         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4716         if(o.good() == false)
4717                 throw FileNotGoodException("Cannot open sector metafile");
4718
4719         sector->serialize(o, version);
4720         
4721         sector->differs_from_disk = false;
4722 }
4723
4724 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
4725 {
4726         DSTACK(__FUNCTION_NAME);
4727         // Get destination
4728         v2s16 p2d = getSectorPos(sectordir);
4729
4730         ServerMapSector *sector = NULL;
4731
4732         std::string fullpath = sectordir + "/meta";
4733         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4734         if(is.good() == false)
4735         {
4736                 // If the directory exists anyway, it probably is in some old
4737                 // format. Just go ahead and create the sector.
4738                 if(fs::PathExists(sectordir))
4739                 {
4740                         dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
4741                                         <<fullpath<<" doesn't exist but directory does."
4742                                         <<" Continuing with a sector with no metadata."
4743                                         <<std::endl;
4744                         sector = new ServerMapSector(this, p2d);
4745                         m_sectors.insert(p2d, sector);
4746                 }
4747                 else
4748                 {
4749                         throw FileNotGoodException("Cannot open sector metafile");
4750                 }
4751         }
4752         else
4753         {
4754                 sector = ServerMapSector::deSerialize
4755                                 (is, this, p2d, m_sectors);
4756                 if(save_after_load)
4757                         saveSectorMeta(sector);
4758         }
4759         
4760         sector->differs_from_disk = false;
4761
4762         return sector;
4763 }
4764
4765 bool ServerMap::loadSectorMeta(v2s16 p2d)
4766 {
4767         DSTACK(__FUNCTION_NAME);
4768
4769         MapSector *sector = NULL;
4770
4771         // The directory layout we're going to load from.
4772         //  1 - original sectors/xxxxzzzz/
4773         //  2 - new sectors2/xxx/zzz/
4774         //  If we load from anything but the latest structure, we will
4775         //  immediately save to the new one, and remove the old.
4776         int loadlayout = 1;
4777         std::string sectordir1 = getSectorDir(p2d, 1);
4778         std::string sectordir;
4779         if(fs::PathExists(sectordir1))
4780         {
4781                 sectordir = sectordir1;
4782         }
4783         else
4784         {
4785                 loadlayout = 2;
4786                 sectordir = getSectorDir(p2d, 2);
4787         }
4788
4789         try{
4790                 sector = loadSectorMeta(sectordir, loadlayout != 2);
4791         }
4792         catch(InvalidFilenameException &e)
4793         {
4794                 return false;
4795         }
4796         catch(FileNotGoodException &e)
4797         {
4798                 return false;
4799         }
4800         catch(std::exception &e)
4801         {
4802                 return false;
4803         }
4804         
4805         return true;
4806 }
4807
4808 #if 0
4809 bool ServerMap::loadSectorFull(v2s16 p2d)
4810 {
4811         DSTACK(__FUNCTION_NAME);
4812
4813         MapSector *sector = NULL;
4814
4815         // The directory layout we're going to load from.
4816         //  1 - original sectors/xxxxzzzz/
4817         //  2 - new sectors2/xxx/zzz/
4818         //  If we load from anything but the latest structure, we will
4819         //  immediately save to the new one, and remove the old.
4820         int loadlayout = 1;
4821         std::string sectordir1 = getSectorDir(p2d, 1);
4822         std::string sectordir;
4823         if(fs::PathExists(sectordir1))
4824         {
4825                 sectordir = sectordir1;
4826         }
4827         else
4828         {
4829                 loadlayout = 2;
4830                 sectordir = getSectorDir(p2d, 2);
4831         }
4832
4833         try{
4834                 sector = loadSectorMeta(sectordir, loadlayout != 2);
4835         }
4836         catch(InvalidFilenameException &e)
4837         {
4838                 return false;
4839         }
4840         catch(FileNotGoodException &e)
4841         {
4842                 return false;
4843         }
4844         catch(std::exception &e)
4845         {
4846                 return false;
4847         }
4848         
4849         /*
4850                 Load blocks
4851         */
4852         std::vector<fs::DirListNode> list2 = fs::GetDirListing
4853                         (sectordir);
4854         std::vector<fs::DirListNode>::iterator i2;
4855         for(i2=list2.begin(); i2!=list2.end(); i2++)
4856         {
4857                 // We want files
4858                 if(i2->dir)
4859                         continue;
4860                 try{
4861                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
4862                 }
4863                 catch(InvalidFilenameException &e)
4864                 {
4865                         // This catches unknown crap in directory
4866                 }
4867         }
4868
4869         if(loadlayout != 2)
4870         {
4871                 dstream<<"Sector converted to new layout - deleting "<<
4872                         sectordir1<<std::endl;
4873                 fs::RecursiveDelete(sectordir1);
4874         }
4875
4876         return true;
4877 }
4878 #endif
4879
4880 void ServerMap::saveBlock(MapBlock *block)
4881 {
4882         DSTACK(__FUNCTION_NAME);
4883         /*
4884                 Dummy blocks are not written
4885         */
4886         if(block->isDummy())
4887         {
4888                 /*v3s16 p = block->getPos();
4889                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
4890                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
4891                 return;
4892         }
4893
4894         // Format used for writing
4895         u8 version = SER_FMT_VER_HIGHEST;
4896         // Get destination
4897         v3s16 p3d = block->getPos();
4898         
4899         v2s16 p2d(p3d.X, p3d.Z);
4900         std::string sectordir = getSectorDir(p2d);
4901
4902         createDirs(sectordir);
4903
4904         std::string fullpath = sectordir+"/"+getBlockFilename(p3d);
4905         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4906         if(o.good() == false)
4907                 throw FileNotGoodException("Cannot open block data");
4908
4909         /*
4910                 [0] u8 serialization version
4911                 [1] data
4912         */
4913         o.write((char*)&version, 1);
4914         
4915         // Write basic data
4916         block->serialize(o, version);
4917         
4918         // Write extra data stored on disk
4919         block->serializeDiskExtra(o, version);
4920
4921         // We just wrote it to the disk so clear modified flag
4922         block->resetModified();
4923 }
4924
4925 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
4926 {
4927         DSTACK(__FUNCTION_NAME);
4928
4929         std::string fullpath = sectordir+"/"+blockfile;
4930         try{
4931
4932                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4933                 if(is.good() == false)
4934                         throw FileNotGoodException("Cannot open block file");
4935                 
4936                 v3s16 p3d = getBlockPos(sectordir, blockfile);
4937                 v2s16 p2d(p3d.X, p3d.Z);
4938                 
4939                 assert(sector->getPos() == p2d);
4940                 
4941                 u8 version = SER_FMT_VER_INVALID;
4942                 is.read((char*)&version, 1);
4943
4944                 if(is.fail())
4945                         throw SerializationError("ServerMap::loadBlock(): Failed"
4946                                         " to read MapBlock version");
4947
4948                 /*u32 block_size = MapBlock::serializedLength(version);
4949                 SharedBuffer<u8> data(block_size);
4950                 is.read((char*)*data, block_size);*/
4951
4952                 // This will always return a sector because we're the server
4953                 //MapSector *sector = emergeSector(p2d);
4954
4955                 MapBlock *block = NULL;
4956                 bool created_new = false;
4957                 try{
4958                         block = sector->getBlockNoCreate(p3d.Y);
4959                 }
4960                 catch(InvalidPositionException &e)
4961                 {
4962                         block = sector->createBlankBlockNoInsert(p3d.Y);
4963                         created_new = true;
4964                 }
4965                 
4966                 // Read basic data
4967                 block->deSerialize(is, version);
4968
4969                 // Read extra data stored on disk
4970                 block->deSerializeDiskExtra(is, version);
4971                 
4972                 // If it's a new block, insert it to the map
4973                 if(created_new)
4974                         sector->insertBlock(block);
4975                 
4976                 /*
4977                         Save blocks loaded in old format in new format
4978                 */
4979
4980                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
4981                 {
4982                         saveBlock(block);
4983                 }
4984                 
4985                 // We just loaded it from the disk, so it's up-to-date.
4986                 block->resetModified();
4987
4988         }
4989         catch(SerializationError &e)
4990         {
4991                 dstream<<"WARNING: Invalid block data on disk "
4992                                 <<"fullpath="<<fullpath
4993                                 <<" (SerializationError). "
4994                                 <<"what()="<<e.what()
4995                                 <<std::endl;
4996                                 //" Ignoring. A new one will be generated.
4997                 assert(0);
4998
4999                 // TODO: Backup file; name is in fullpath.
5000         }
5001 }
5002
5003 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
5004 {
5005         DSTACK(__FUNCTION_NAME);
5006
5007         v2s16 p2d(blockpos.X, blockpos.Z);
5008
5009         // The directory layout we're going to load from.
5010         //  1 - original sectors/xxxxzzzz/
5011         //  2 - new sectors2/xxx/zzz/
5012         //  If we load from anything but the latest structure, we will
5013         //  immediately save to the new one, and remove the old.
5014         int loadlayout = 1;
5015         std::string sectordir1 = getSectorDir(p2d, 1);
5016         std::string sectordir;
5017         if(fs::PathExists(sectordir1))
5018         {
5019                 sectordir = sectordir1;
5020         }
5021         else
5022         {
5023                 loadlayout = 2;
5024                 sectordir = getSectorDir(p2d, 2);
5025         }
5026         
5027         /*
5028                 Make sure sector is loaded
5029         */
5030         MapSector *sector = getSectorNoGenerateNoEx(p2d);
5031         if(sector == NULL)
5032         {
5033                 try{
5034                         sector = loadSectorMeta(sectordir, loadlayout != 2);
5035                 }
5036                 catch(InvalidFilenameException &e)
5037                 {
5038                         return false;
5039                 }
5040                 catch(FileNotGoodException &e)
5041                 {
5042                         return false;
5043                 }
5044                 catch(std::exception &e)
5045                 {
5046                         return false;
5047                 }
5048         }
5049         
5050         /*
5051                 Make sure file exists
5052         */
5053
5054         std::string blockfilename = getBlockFilename(blockpos);
5055         if(fs::PathExists(sectordir+"/"+blockfilename) == false)
5056                 return NULL;
5057
5058         /*
5059                 Load block
5060         */
5061         loadBlock(sectordir, blockfilename, sector, loadlayout != 2);
5062         return getBlockNoCreateNoEx(blockpos);
5063 }
5064
5065 void ServerMap::PrintInfo(std::ostream &out)
5066 {
5067         out<<"ServerMap: ";
5068 }
5069
5070 #ifndef SERVER
5071
5072 /*
5073         ClientMap
5074 */
5075
5076 ClientMap::ClientMap(
5077                 Client *client,
5078                 MapDrawControl &control,
5079                 scene::ISceneNode* parent,
5080                 scene::ISceneManager* mgr,
5081                 s32 id
5082 ):
5083         Map(dout_client),
5084         scene::ISceneNode(parent, mgr, id),
5085         m_client(client),
5086         m_control(control),
5087         m_camera_position(0,0,0),
5088         m_camera_direction(0,0,1)
5089 {
5090         m_camera_mutex.Init();
5091         assert(m_camera_mutex.IsInitialized());
5092         
5093         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
5094                         BS*1000000,BS*1000000,BS*1000000);
5095 }
5096
5097 ClientMap::~ClientMap()
5098 {
5099         /*JMutexAutoLock lock(mesh_mutex);
5100         
5101         if(mesh != NULL)
5102         {
5103                 mesh->drop();
5104                 mesh = NULL;
5105         }*/
5106 }
5107
5108 MapSector * ClientMap::emergeSector(v2s16 p2d)
5109 {
5110         DSTACK(__FUNCTION_NAME);
5111         // Check that it doesn't exist already
5112         try{
5113                 return getSectorNoGenerate(p2d);
5114         }
5115         catch(InvalidPositionException &e)
5116         {
5117         }
5118         
5119         // Create a sector
5120         ClientMapSector *sector = new ClientMapSector(this, p2d);
5121         
5122         {
5123                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
5124                 m_sectors.insert(p2d, sector);
5125         }
5126         
5127         return sector;
5128 }
5129
5130 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
5131 {
5132         DSTACK(__FUNCTION_NAME);
5133         ClientMapSector *sector = NULL;
5134
5135         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
5136         
5137         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
5138
5139         if(n != NULL)
5140         {
5141                 sector = (ClientMapSector*)n->getValue();
5142                 assert(sector->getId() == MAPSECTOR_CLIENT);
5143         }
5144         else
5145         {
5146                 sector = new ClientMapSector(this, p2d);
5147                 {
5148                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
5149                         m_sectors.insert(p2d, sector);
5150                 }
5151         }
5152
5153         sector->deSerialize(is);
5154 }
5155
5156 void ClientMap::OnRegisterSceneNode()
5157 {
5158         if(IsVisible)
5159         {
5160                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
5161                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
5162         }
5163
5164         ISceneNode::OnRegisterSceneNode();
5165 }
5166
5167 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
5168 {
5169         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
5170         DSTACK(__FUNCTION_NAME);
5171
5172         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
5173         
5174         /*
5175                 This is called two times per frame, reset on the non-transparent one
5176         */
5177         if(pass == scene::ESNRP_SOLID)
5178         {
5179                 m_last_drawn_sectors.clear();
5180         }
5181
5182         /*
5183                 Get time for measuring timeout.
5184                 
5185                 Measuring time is very useful for long delays when the
5186                 machine is swapping a lot.
5187         */
5188         int time1 = time(0);
5189
5190         //u32 daynight_ratio = m_client->getDayNightRatio();
5191
5192         m_camera_mutex.Lock();
5193         v3f camera_position = m_camera_position;
5194         v3f camera_direction = m_camera_direction;
5195         m_camera_mutex.Unlock();
5196
5197         /*
5198                 Get all blocks and draw all visible ones
5199         */
5200
5201         v3s16 cam_pos_nodes(
5202                         camera_position.X / BS,
5203                         camera_position.Y / BS,
5204                         camera_position.Z / BS);
5205
5206         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
5207
5208         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
5209         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
5210
5211         // Take a fair amount as we will be dropping more out later
5212         v3s16 p_blocks_min(
5213                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
5214                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
5215                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
5216         v3s16 p_blocks_max(
5217                         p_nodes_max.X / MAP_BLOCKSIZE,
5218                         p_nodes_max.Y / MAP_BLOCKSIZE,
5219                         p_nodes_max.Z / MAP_BLOCKSIZE);
5220         
5221         u32 vertex_count = 0;
5222         
5223         // For limiting number of mesh updates per frame
5224         u32 mesh_update_count = 0;
5225         
5226         u32 blocks_would_have_drawn = 0;
5227         u32 blocks_drawn = 0;
5228
5229         int timecheck_counter = 0;
5230         core::map<v2s16, MapSector*>::Iterator si;
5231         si = m_sectors.getIterator();
5232         for(; si.atEnd() == false; si++)
5233         {
5234                 {
5235                         timecheck_counter++;
5236                         if(timecheck_counter > 50)
5237                         {
5238                                 timecheck_counter = 0;
5239                                 int time2 = time(0);
5240                                 if(time2 > time1 + 4)
5241                                 {
5242                                         dstream<<"ClientMap::renderMap(): "
5243                                                 "Rendering takes ages, returning."
5244                                                 <<std::endl;
5245                                         return;
5246                                 }
5247                         }
5248                 }
5249
5250                 MapSector *sector = si.getNode()->getValue();
5251                 v2s16 sp = sector->getPos();
5252                 
5253                 if(m_control.range_all == false)
5254                 {
5255                         if(sp.X < p_blocks_min.X
5256                         || sp.X > p_blocks_max.X
5257                         || sp.Y < p_blocks_min.Z
5258                         || sp.Y > p_blocks_max.Z)
5259                                 continue;
5260                 }
5261
5262                 core::list< MapBlock * > sectorblocks;
5263                 sector->getBlocks(sectorblocks);
5264                 
5265                 /*
5266                         Draw blocks
5267                 */
5268                 
5269                 u32 sector_blocks_drawn = 0;
5270
5271                 core::list< MapBlock * >::Iterator i;
5272                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5273                 {
5274                         MapBlock *block = *i;
5275
5276                         /*
5277                                 Compare block position to camera position, skip
5278                                 if not seen on display
5279                         */
5280                         
5281                         float range = 100000 * BS;
5282                         if(m_control.range_all == false)
5283                                 range = m_control.wanted_range * BS;
5284                         
5285                         float d = 0.0;
5286                         if(isBlockInSight(block->getPos(), camera_position,
5287                                         camera_direction, range, &d) == false)
5288                         {
5289                                 continue;
5290                         }
5291                         
5292                         // This is ugly (spherical distance limit?)
5293                         /*if(m_control.range_all == false &&
5294                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
5295                                 continue;*/
5296
5297 #if 1
5298                         /*
5299                                 Update expired mesh (used for day/night change)
5300
5301                                 It doesn't work exactly like it should now with the
5302                                 tasked mesh update but whatever.
5303                         */
5304
5305                         bool mesh_expired = false;
5306                         
5307                         {
5308                                 JMutexAutoLock lock(block->mesh_mutex);
5309
5310                                 mesh_expired = block->getMeshExpired();
5311
5312                                 // Mesh has not been expired and there is no mesh:
5313                                 // block has no content
5314                                 if(block->mesh == NULL && mesh_expired == false)
5315                                         continue;
5316                         }
5317
5318                         f32 faraway = BS*50;
5319                         //f32 faraway = m_control.wanted_range * BS;
5320                         
5321                         /*
5322                                 This has to be done with the mesh_mutex unlocked
5323                         */
5324                         // Pretty random but this should work somewhat nicely
5325                         if(mesh_expired && (
5326                                         (mesh_update_count < 3
5327                                                 && (d < faraway || mesh_update_count < 2)
5328                                         )
5329                                         || 
5330                                         (m_control.range_all && mesh_update_count < 20)
5331                                 )
5332                         )
5333                         /*if(mesh_expired && mesh_update_count < 6
5334                                         && (d < faraway || mesh_update_count < 3))*/
5335                         {
5336                                 mesh_update_count++;
5337
5338                                 // Mesh has been expired: generate new mesh
5339                                 //block->updateMesh(daynight_ratio);
5340                                 m_client->addUpdateMeshTask(block->getPos());
5341
5342                                 mesh_expired = false;
5343                         }
5344                         
5345 #endif
5346                         /*
5347                                 Draw the faces of the block
5348                         */
5349                         {
5350                                 JMutexAutoLock lock(block->mesh_mutex);
5351
5352                                 scene::SMesh *mesh = block->mesh;
5353
5354                                 if(mesh == NULL)
5355                                         continue;
5356                                 
5357                                 blocks_would_have_drawn++;
5358                                 if(blocks_drawn >= m_control.wanted_max_blocks
5359                                                 && m_control.range_all == false
5360                                                 && d > m_control.wanted_min_range * BS)
5361                                         continue;
5362
5363                                 blocks_drawn++;
5364                                 sector_blocks_drawn++;
5365
5366                                 u32 c = mesh->getMeshBufferCount();
5367
5368                                 for(u32 i=0; i<c; i++)
5369                                 {
5370                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
5371                                         const video::SMaterial& material = buf->getMaterial();
5372                                         video::IMaterialRenderer* rnd =
5373                                                         driver->getMaterialRenderer(material.MaterialType);
5374                                         bool transparent = (rnd && rnd->isTransparent());
5375                                         // Render transparent on transparent pass and likewise.
5376                                         if(transparent == is_transparent_pass)
5377                                         {
5378                                                 /*
5379                                                         This *shouldn't* hurt too much because Irrlicht
5380                                                         doesn't change opengl textures if the old
5381                                                         material is set again.
5382                                                 */
5383                                                 driver->setMaterial(buf->getMaterial());
5384                                                 driver->drawMeshBuffer(buf);
5385                                                 vertex_count += buf->getVertexCount();
5386                                         }
5387                                 }
5388                         }
5389                 } // foreach sectorblocks
5390
5391                 if(sector_blocks_drawn != 0)
5392                 {
5393                         m_last_drawn_sectors[sp] = true;
5394                 }
5395         }
5396         
5397         m_control.blocks_drawn = blocks_drawn;
5398         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
5399
5400         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
5401                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
5402 }
5403
5404 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
5405                 core::map<v3s16, MapBlock*> *affected_blocks)
5406 {
5407         bool changed = false;
5408         /*
5409                 Add it to all blocks touching it
5410         */
5411         v3s16 dirs[7] = {
5412                 v3s16(0,0,0), // this
5413                 v3s16(0,0,1), // back
5414                 v3s16(0,1,0), // top
5415                 v3s16(1,0,0), // right
5416                 v3s16(0,0,-1), // front
5417                 v3s16(0,-1,0), // bottom
5418                 v3s16(-1,0,0), // left
5419         };
5420         for(u16 i=0; i<7; i++)
5421         {
5422                 v3s16 p2 = p + dirs[i];
5423                 // Block position of neighbor (or requested) node
5424                 v3s16 blockpos = getNodeBlockPos(p2);
5425                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5426                 if(blockref == NULL)
5427                         continue;
5428                 // Relative position of requested node
5429                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5430                 if(blockref->setTempMod(relpos, mod))
5431                 {
5432                         changed = true;
5433                 }
5434         }
5435         if(changed && affected_blocks!=NULL)
5436         {
5437                 for(u16 i=0; i<7; i++)
5438                 {
5439                         v3s16 p2 = p + dirs[i];
5440                         // Block position of neighbor (or requested) node
5441                         v3s16 blockpos = getNodeBlockPos(p2);
5442                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5443                         if(blockref == NULL)
5444                                 continue;
5445                         affected_blocks->insert(blockpos, blockref);
5446                 }
5447         }
5448         return changed;
5449 }
5450
5451 bool ClientMap::clearTempMod(v3s16 p,
5452                 core::map<v3s16, MapBlock*> *affected_blocks)
5453 {
5454         bool changed = false;
5455         v3s16 dirs[7] = {
5456                 v3s16(0,0,0), // this
5457                 v3s16(0,0,1), // back
5458                 v3s16(0,1,0), // top
5459                 v3s16(1,0,0), // right
5460                 v3s16(0,0,-1), // front
5461                 v3s16(0,-1,0), // bottom
5462                 v3s16(-1,0,0), // left
5463         };
5464         for(u16 i=0; i<7; i++)
5465         {
5466                 v3s16 p2 = p + dirs[i];
5467                 // Block position of neighbor (or requested) node
5468                 v3s16 blockpos = getNodeBlockPos(p2);
5469                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5470                 if(blockref == NULL)
5471                         continue;
5472                 // Relative position of requested node
5473                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5474                 if(blockref->clearTempMod(relpos))
5475                 {
5476                         changed = true;
5477                 }
5478         }
5479         if(changed && affected_blocks!=NULL)
5480         {
5481                 for(u16 i=0; i<7; i++)
5482                 {
5483                         v3s16 p2 = p + dirs[i];
5484                         // Block position of neighbor (or requested) node
5485                         v3s16 blockpos = getNodeBlockPos(p2);
5486                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5487                         if(blockref == NULL)
5488                                 continue;
5489                         affected_blocks->insert(blockpos, blockref);
5490                 }
5491         }
5492         return changed;
5493 }
5494
5495 void ClientMap::expireMeshes(bool only_daynight_diffed)
5496 {
5497         TimeTaker timer("expireMeshes()");
5498
5499         core::map<v2s16, MapSector*>::Iterator si;
5500         si = m_sectors.getIterator();
5501         for(; si.atEnd() == false; si++)
5502         {
5503                 MapSector *sector = si.getNode()->getValue();
5504
5505                 core::list< MapBlock * > sectorblocks;
5506                 sector->getBlocks(sectorblocks);
5507                 
5508                 core::list< MapBlock * >::Iterator i;
5509                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5510                 {
5511                         MapBlock *block = *i;
5512
5513                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
5514                         {
5515                                 continue;
5516                         }
5517                         
5518                         {
5519                                 JMutexAutoLock lock(block->mesh_mutex);
5520                                 if(block->mesh != NULL)
5521                                 {
5522                                         /*block->mesh->drop();
5523                                         block->mesh = NULL;*/
5524                                         block->setMeshExpired(true);
5525                                 }
5526                         }
5527                 }
5528         }
5529 }
5530
5531 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
5532 {
5533         assert(mapType() == MAPTYPE_CLIENT);
5534
5535         try{
5536                 v3s16 p = blockpos + v3s16(0,0,0);
5537                 MapBlock *b = getBlockNoCreate(p);
5538                 b->updateMesh(daynight_ratio);
5539                 //b->setMeshExpired(true);
5540         }
5541         catch(InvalidPositionException &e){}
5542         // Leading edge
5543         try{
5544                 v3s16 p = blockpos + v3s16(-1,0,0);
5545                 MapBlock *b = getBlockNoCreate(p);
5546                 b->updateMesh(daynight_ratio);
5547                 //b->setMeshExpired(true);
5548         }
5549         catch(InvalidPositionException &e){}
5550         try{
5551                 v3s16 p = blockpos + v3s16(0,-1,0);
5552                 MapBlock *b = getBlockNoCreate(p);
5553                 b->updateMesh(daynight_ratio);
5554                 //b->setMeshExpired(true);
5555         }
5556         catch(InvalidPositionException &e){}
5557         try{
5558                 v3s16 p = blockpos + v3s16(0,0,-1);
5559                 MapBlock *b = getBlockNoCreate(p);
5560                 b->updateMesh(daynight_ratio);
5561                 //b->setMeshExpired(true);
5562         }
5563         catch(InvalidPositionException &e){}
5564 }
5565
5566 #if 0
5567 /*
5568         Update mesh of block in which the node is, and if the node is at the
5569         leading edge, update the appropriate leading blocks too.
5570 */
5571 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
5572 {
5573         v3s16 dirs[4] = {
5574                 v3s16(0,0,0),
5575                 v3s16(-1,0,0),
5576                 v3s16(0,-1,0),
5577                 v3s16(0,0,-1),
5578         };
5579         v3s16 blockposes[4];
5580         for(u32 i=0; i<4; i++)
5581         {
5582                 v3s16 np = nodepos + dirs[i];
5583                 blockposes[i] = getNodeBlockPos(np);
5584                 // Don't update mesh of block if it has been done already
5585                 bool already_updated = false;
5586                 for(u32 j=0; j<i; j++)
5587                 {
5588                         if(blockposes[j] == blockposes[i])
5589                         {
5590                                 already_updated = true;
5591                                 break;
5592                         }
5593                 }
5594                 if(already_updated)
5595                         continue;
5596                 // Update mesh
5597                 MapBlock *b = getBlockNoCreate(blockposes[i]);
5598                 b->updateMesh(daynight_ratio);
5599         }
5600 }
5601 #endif
5602
5603 void ClientMap::PrintInfo(std::ostream &out)
5604 {
5605         out<<"ClientMap: ";
5606 }
5607
5608 #endif // !SERVER
5609
5610 /*
5611         MapVoxelManipulator
5612 */
5613
5614 MapVoxelManipulator::MapVoxelManipulator(Map *map)
5615 {
5616         m_map = map;
5617 }
5618
5619 MapVoxelManipulator::~MapVoxelManipulator()
5620 {
5621         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
5622                         <<std::endl;*/
5623 }
5624
5625 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5626 {
5627         TimeTaker timer1("emerge", &emerge_time);
5628
5629         // Units of these are MapBlocks
5630         v3s16 p_min = getNodeBlockPos(a.MinEdge);
5631         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
5632
5633         VoxelArea block_area_nodes
5634                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5635
5636         addArea(block_area_nodes);
5637
5638         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5639         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5640         for(s32 x=p_min.X; x<=p_max.X; x++)
5641         {
5642                 v3s16 p(x,y,z);
5643                 core::map<v3s16, bool>::Node *n;
5644                 n = m_loaded_blocks.find(p);
5645                 if(n != NULL)
5646                         continue;
5647                 
5648                 bool block_data_inexistent = false;
5649                 try
5650                 {
5651                         TimeTaker timer1("emerge load", &emerge_load_time);
5652
5653                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
5654                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5655                                         <<" wanted area: ";
5656                         a.print(dstream);
5657                         dstream<<std::endl;*/
5658                         
5659                         MapBlock *block = m_map->getBlockNoCreate(p);
5660                         if(block->isDummy())
5661                                 block_data_inexistent = true;
5662                         else
5663                                 block->copyTo(*this);
5664                 }
5665                 catch(InvalidPositionException &e)
5666                 {
5667                         block_data_inexistent = true;
5668                 }
5669
5670                 if(block_data_inexistent)
5671                 {
5672                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5673                         // Fill with VOXELFLAG_INEXISTENT
5674                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
5675                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
5676                         {
5677                                 s32 i = m_area.index(a.MinEdge.X,y,z);
5678                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
5679                         }
5680                 }
5681
5682                 m_loaded_blocks.insert(p, !block_data_inexistent);
5683         }
5684
5685         //dstream<<"emerge done"<<std::endl;
5686 }
5687
5688 /*
5689         SUGG: Add an option to only update eg. water and air nodes.
5690               This will make it interfere less with important stuff if
5691                   run on background.
5692 */
5693 void MapVoxelManipulator::blitBack
5694                 (core::map<v3s16, MapBlock*> & modified_blocks)
5695 {
5696         if(m_area.getExtent() == v3s16(0,0,0))
5697                 return;
5698         
5699         //TimeTaker timer1("blitBack");
5700
5701         /*dstream<<"blitBack(): m_loaded_blocks.size()="
5702                         <<m_loaded_blocks.size()<<std::endl;*/
5703         
5704         /*
5705                 Initialize block cache
5706         */
5707         v3s16 blockpos_last;
5708         MapBlock *block = NULL;
5709         bool block_checked_in_modified = false;
5710
5711         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
5712         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
5713         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
5714         {
5715                 v3s16 p(x,y,z);
5716
5717                 u8 f = m_flags[m_area.index(p)];
5718                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
5719                         continue;
5720
5721                 MapNode &n = m_data[m_area.index(p)];
5722                         
5723                 v3s16 blockpos = getNodeBlockPos(p);
5724                 
5725                 try
5726                 {
5727                         // Get block
5728                         if(block == NULL || blockpos != blockpos_last){
5729                                 block = m_map->getBlockNoCreate(blockpos);
5730                                 blockpos_last = blockpos;
5731                                 block_checked_in_modified = false;
5732                         }
5733                         
5734                         // Calculate relative position in block
5735                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
5736
5737                         // Don't continue if nothing has changed here
5738                         if(block->getNode(relpos) == n)
5739                                 continue;
5740
5741                         //m_map->setNode(m_area.MinEdge + p, n);
5742                         block->setNode(relpos, n);
5743                         
5744                         /*
5745                                 Make sure block is in modified_blocks
5746                         */
5747                         if(block_checked_in_modified == false)
5748                         {
5749                                 modified_blocks[blockpos] = block;
5750                                 block_checked_in_modified = true;
5751                         }
5752                 }
5753                 catch(InvalidPositionException &e)
5754                 {
5755                 }
5756         }
5757 }
5758
5759 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
5760                 MapVoxelManipulator(map),
5761                 m_create_area(false)
5762 {
5763 }
5764
5765 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
5766 {
5767 }
5768
5769 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5770 {
5771         // Just create the area so that it can be pointed to
5772         VoxelManipulator::emerge(a, caller_id);
5773 }
5774
5775 void ManualMapVoxelManipulator::initialEmerge(
5776                 v3s16 blockpos_min, v3s16 blockpos_max)
5777 {
5778         TimeTaker timer1("initialEmerge", &emerge_time);
5779
5780         // Units of these are MapBlocks
5781         v3s16 p_min = blockpos_min;
5782         v3s16 p_max = blockpos_max;
5783
5784         VoxelArea block_area_nodes
5785                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5786         
5787         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
5788         if(size_MB >= 1)
5789         {
5790                 dstream<<"initialEmerge: area: ";
5791                 block_area_nodes.print(dstream);
5792                 dstream<<" ("<<size_MB<<"MB)";
5793                 dstream<<std::endl;
5794         }
5795
5796         addArea(block_area_nodes);
5797
5798         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5799         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5800         for(s32 x=p_min.X; x<=p_max.X; x++)
5801         {
5802                 v3s16 p(x,y,z);
5803                 core::map<v3s16, bool>::Node *n;
5804                 n = m_loaded_blocks.find(p);
5805                 if(n != NULL)
5806                         continue;
5807                 
5808                 bool block_data_inexistent = false;
5809                 try
5810                 {
5811                         TimeTaker timer1("emerge load", &emerge_load_time);
5812
5813                         MapBlock *block = m_map->getBlockNoCreate(p);
5814                         if(block->isDummy())
5815                                 block_data_inexistent = true;
5816                         else
5817                                 block->copyTo(*this);
5818                 }
5819                 catch(InvalidPositionException &e)
5820                 {
5821                         block_data_inexistent = true;
5822                 }
5823
5824                 if(block_data_inexistent)
5825                 {
5826                         /*
5827                                 Mark area inexistent
5828                         */
5829                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5830                         // Fill with VOXELFLAG_INEXISTENT
5831                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
5832                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
5833                         {
5834                                 s32 i = m_area.index(a.MinEdge.X,y,z);
5835                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
5836                         }
5837                 }
5838
5839                 m_loaded_blocks.insert(p, !block_data_inexistent);
5840         }
5841 }
5842
5843 void ManualMapVoxelManipulator::blitBackAll(
5844                 core::map<v3s16, MapBlock*> * modified_blocks)
5845 {
5846         if(m_area.getExtent() == v3s16(0,0,0))
5847                 return;
5848         
5849         /*
5850                 Copy data of all blocks
5851         */
5852         for(core::map<v3s16, bool>::Iterator
5853                         i = m_loaded_blocks.getIterator();
5854                         i.atEnd() == false; i++)
5855         {
5856                 bool existed = i.getNode()->getValue();
5857                 if(existed == false)
5858                         continue;
5859                 v3s16 p = i.getNode()->getKey();
5860                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
5861                 if(block == NULL)
5862                 {
5863                         dstream<<"WARNING: "<<__FUNCTION_NAME
5864                                         <<": got NULL block "
5865                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5866                                         <<std::endl;
5867                         continue;
5868                 }
5869
5870                 block->copyFrom(*this);
5871
5872                 if(modified_blocks)
5873                         modified_blocks->insert(p, block);
5874         }
5875 }
5876
5877 //END